mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-04-30 18:36:28 +00:00
Compare commits
63 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e1aaf927b | ||
|
|
f0bcb7f477 | ||
|
|
d96705d55a | ||
|
|
d7e8f7a8cb | ||
|
|
becc6c7200 | ||
|
|
5cddc4d617 | ||
|
|
392e89ee86 | ||
|
|
3e43029a32 | ||
|
|
3ee2ec4908 | ||
|
|
719844cd4f | ||
|
|
1dac3cd991 | ||
|
|
416a4ad6f8 | ||
|
|
0ce3841bda | ||
|
|
5362908efb | ||
|
|
d9d9148510 | ||
|
|
214f0be60d | ||
|
|
715e6706cc | ||
|
|
086b403336 | ||
|
|
717c2ca8dd | ||
|
|
18a8c6f350 | ||
|
|
1caee897b1 | ||
|
|
4a0da7fcbb | ||
|
|
4bd6b35d31 | ||
|
|
cf66c8a249 | ||
|
|
841ceffbcb | ||
|
|
d122d3f6fc | ||
|
|
c825648063 | ||
|
|
5c60788abf | ||
|
|
bf318b3838 | ||
|
|
03b12029aa | ||
|
|
6777d9471f | ||
|
|
61ea1aef35 | ||
|
|
ae4358d189 | ||
|
|
8fe7cdd864 | ||
|
|
586fdefa75 | ||
|
|
765fc79d28 | ||
|
|
e14ebe38f4 | ||
|
|
a3d9f72462 | ||
|
|
4f5a50642d | ||
|
|
a3c5cc6773 | ||
|
|
581ad7bbd8 | ||
|
|
6fd530dbff | ||
|
|
076fe3cfb0 | ||
|
|
decadf7cbc | ||
|
|
559b4494de | ||
|
|
ddbe3028e5 | ||
|
|
98fede2ba0 | ||
|
|
b6b6e0db94 | ||
|
|
f9ad7304ca | ||
|
|
d0fe612858 | ||
|
|
31b7c8aace | ||
|
|
d017b603ce | ||
|
|
55f8456229 | ||
|
|
c4b3c94092 | ||
|
|
ca32d9f925 | ||
|
|
ee6d8cea9d | ||
|
|
6920a247c2 | ||
|
|
bce61ee785 | ||
|
|
8465e87bdc | ||
|
|
f3ef0bc8e1 | ||
|
|
104d98ef02 | ||
|
|
5251c8b075 | ||
|
|
a151726272 |
@@ -59,14 +59,14 @@ pool: Standard
|
||||
|
||||
stages:
|
||||
### Sanity
|
||||
- stage: Sanity_devel
|
||||
displayName: Sanity devel
|
||||
- stage: Sanity_2_18
|
||||
displayName: Sanity 2.18
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
nameFormat: Test {0}
|
||||
testFormat: devel/sanity/{0}
|
||||
testFormat: 2.18/sanity/{0}
|
||||
targets:
|
||||
- test: 1
|
||||
- test: 2
|
||||
@@ -99,28 +99,15 @@ stages:
|
||||
- test: 2
|
||||
- test: 3
|
||||
- test: 4
|
||||
- stage: Sanity_2_15
|
||||
displayName: Sanity 2.15
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
nameFormat: Test {0}
|
||||
testFormat: 2.15/sanity/{0}
|
||||
targets:
|
||||
- test: 1
|
||||
- test: 2
|
||||
- test: 3
|
||||
- test: 4
|
||||
### Units
|
||||
- stage: Units_devel
|
||||
displayName: Units devel
|
||||
- stage: Units_2_18
|
||||
displayName: Units 2.18
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
nameFormat: Python {0}
|
||||
testFormat: devel/units/{0}/1
|
||||
testFormat: 2.18/units/{0}/1
|
||||
targets:
|
||||
- test: 3.8
|
||||
- test: 3.9
|
||||
@@ -151,26 +138,15 @@ stages:
|
||||
- test: 2.7
|
||||
- test: 3.6
|
||||
- test: "3.11"
|
||||
- stage: Units_2_15
|
||||
displayName: Units 2.15
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
nameFormat: Python {0}
|
||||
testFormat: 2.15/units/{0}/1
|
||||
targets:
|
||||
- test: 3.5
|
||||
- test: "3.10"
|
||||
|
||||
## Remote
|
||||
- stage: Remote_devel_extra_vms
|
||||
displayName: Remote devel extra VMs
|
||||
- stage: Remote_2_18_extra_vms
|
||||
displayName: Remote 2.18 extra VMs
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
testFormat: devel/{0}
|
||||
testFormat: 2.18/{0}
|
||||
targets:
|
||||
- name: Alpine 3.20
|
||||
test: alpine/3.20
|
||||
@@ -182,13 +158,13 @@ stages:
|
||||
test: ubuntu/24.04
|
||||
groups:
|
||||
- vm
|
||||
- stage: Remote_devel
|
||||
displayName: Remote devel
|
||||
- stage: Remote_2_18
|
||||
displayName: Remote 2.18
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
testFormat: devel/{0}
|
||||
testFormat: 2.18/{0}
|
||||
targets:
|
||||
- name: macOS 14.3
|
||||
test: macos/14.3
|
||||
@@ -232,43 +208,23 @@ stages:
|
||||
test: rhel/9.2
|
||||
- name: RHEL 8.8
|
||||
test: rhel/8.8
|
||||
- name: RHEL 7.9
|
||||
test: rhel/7.9
|
||||
# - name: FreeBSD 13.2
|
||||
# test: freebsd/13.2
|
||||
groups:
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
- stage: Remote_2_15
|
||||
displayName: Remote 2.15
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
testFormat: 2.15/{0}
|
||||
targets:
|
||||
- name: RHEL 9.1
|
||||
test: rhel/9.1
|
||||
- name: RHEL 8.7
|
||||
test: rhel/8.7
|
||||
- name: RHEL 7.9
|
||||
test: rhel/7.9
|
||||
# - name: FreeBSD 13.1
|
||||
# test: freebsd/13.1
|
||||
# - name: FreeBSD 12.4
|
||||
# test: freebsd/12.4
|
||||
groups:
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
|
||||
### Docker
|
||||
- stage: Docker_devel
|
||||
displayName: Docker devel
|
||||
- stage: Docker_2_18
|
||||
displayName: Docker 2.18
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
testFormat: devel/linux/{0}
|
||||
testFormat: 2.18/linux/{0}
|
||||
targets:
|
||||
- name: Fedora 40
|
||||
test: fedora40
|
||||
@@ -314,20 +270,6 @@ stages:
|
||||
test: opensuse15
|
||||
- name: Alpine 3
|
||||
test: alpine3
|
||||
groups:
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
- stage: Docker_2_15
|
||||
displayName: Docker 2.15
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
testFormat: 2.15/linux/{0}
|
||||
targets:
|
||||
- name: Fedora 37
|
||||
test: fedora37
|
||||
- name: CentOS 7
|
||||
test: centos7
|
||||
groups:
|
||||
@@ -336,13 +278,13 @@ stages:
|
||||
- 3
|
||||
|
||||
### Community Docker
|
||||
- stage: Docker_community_devel
|
||||
displayName: Docker (community images) devel
|
||||
- stage: Docker_community_2_18
|
||||
displayName: Docker (community images) 2.18
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
testFormat: devel/linux-community/{0}
|
||||
testFormat: 2.18/linux-community/{0}
|
||||
targets:
|
||||
- name: Debian Bullseye
|
||||
test: debian-bullseye/3.9
|
||||
@@ -356,77 +298,63 @@ stages:
|
||||
- 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: '3.8'
|
||||
- test: '3.11'
|
||||
- test: '3.13'
|
||||
- stage: Generic_2_17
|
||||
displayName: Generic 2.17
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
nameFormat: Python {0}
|
||||
testFormat: 2.17/generic/{0}/1
|
||||
targets:
|
||||
- test: '3.7'
|
||||
- test: '3.12'
|
||||
- stage: Generic_2_16
|
||||
displayName: Generic 2.16
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
nameFormat: Python {0}
|
||||
testFormat: 2.16/generic/{0}/1
|
||||
targets:
|
||||
- test: '2.7'
|
||||
- test: '3.6'
|
||||
- test: '3.11'
|
||||
- stage: Generic_2_15
|
||||
displayName: Generic 2.15
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
nameFormat: Python {0}
|
||||
testFormat: 2.15/generic/{0}/1
|
||||
targets:
|
||||
- test: '3.9'
|
||||
# Right now all generic tests are disabled. Uncomment when at least one of them is re-enabled.
|
||||
# - stage: Generic_2_18
|
||||
# displayName: Generic 2.18
|
||||
# dependsOn: []
|
||||
# jobs:
|
||||
# - template: templates/matrix.yml
|
||||
# parameters:
|
||||
# nameFormat: Python {0}
|
||||
# testFormat: 2.18/generic/{0}/1
|
||||
# targets:
|
||||
# - test: '3.8'
|
||||
# - test: '3.11'
|
||||
# - test: '3.13'
|
||||
# - stage: Generic_2_17
|
||||
# displayName: Generic 2.17
|
||||
# dependsOn: []
|
||||
# jobs:
|
||||
# - template: templates/matrix.yml
|
||||
# parameters:
|
||||
# nameFormat: Python {0}
|
||||
# testFormat: 2.17/generic/{0}/1
|
||||
# targets:
|
||||
# - test: '3.7'
|
||||
# - test: '3.12'
|
||||
# - stage: Generic_2_16
|
||||
# displayName: Generic 2.16
|
||||
# dependsOn: []
|
||||
# jobs:
|
||||
# - template: templates/matrix.yml
|
||||
# parameters:
|
||||
# nameFormat: Python {0}
|
||||
# testFormat: 2.16/generic/{0}/1
|
||||
# targets:
|
||||
# - test: '2.7'
|
||||
# - test: '3.6'
|
||||
# - test: '3.11'
|
||||
|
||||
- stage: Summary
|
||||
condition: succeededOrFailed()
|
||||
dependsOn:
|
||||
- Sanity_devel
|
||||
- Sanity_2_18
|
||||
- Sanity_2_17
|
||||
- Sanity_2_16
|
||||
- Sanity_2_15
|
||||
- Units_devel
|
||||
- Units_2_18
|
||||
- Units_2_17
|
||||
- Units_2_16
|
||||
- Units_2_15
|
||||
- Remote_devel_extra_vms
|
||||
- Remote_devel
|
||||
- Remote_2_18_extra_vms
|
||||
- Remote_2_18
|
||||
- Remote_2_17
|
||||
- Remote_2_16
|
||||
- Remote_2_15
|
||||
- Docker_devel
|
||||
- Docker_2_18
|
||||
- Docker_2_17
|
||||
- Docker_2_16
|
||||
- Docker_2_15
|
||||
- Docker_community_devel
|
||||
- Docker_community_2_18
|
||||
# Right now all generic tests are disabled. Uncomment when at least one of them is re-enabled.
|
||||
# - Generic_devel
|
||||
# - Generic_2_18
|
||||
# - Generic_2_17
|
||||
# - Generic_2_16
|
||||
# - Generic_2_15
|
||||
jobs:
|
||||
- template: templates/coverage.yml
|
||||
|
||||
23
.github/workflows/ansible-test.yml
vendored
23
.github/workflows/ansible-test.yml
vendored
@@ -31,6 +31,7 @@ jobs:
|
||||
ansible:
|
||||
- '2.13'
|
||||
- '2.14'
|
||||
- '2.15'
|
||||
# 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
|
||||
@@ -76,6 +77,10 @@ jobs:
|
||||
python: '3.8'
|
||||
- ansible: '2.14'
|
||||
python: '3.9'
|
||||
- ansible: '2.15'
|
||||
python: '3.5'
|
||||
- ansible: '2.15'
|
||||
python: '3.10'
|
||||
|
||||
steps:
|
||||
- name: >-
|
||||
@@ -166,16 +171,32 @@ jobs:
|
||||
docker: alpine3
|
||||
python: ''
|
||||
target: azp/posix/3/
|
||||
# 2.15
|
||||
- ansible: '2.15'
|
||||
docker: fedora37
|
||||
python: ''
|
||||
target: azp/posix/1/
|
||||
- ansible: '2.15'
|
||||
docker: fedora37
|
||||
python: ''
|
||||
target: azp/posix/2/
|
||||
- ansible: '2.15'
|
||||
docker: fedora37
|
||||
python: ''
|
||||
target: azp/posix/3/
|
||||
# Right now all generic tests are disabled. Uncomment when at least one of them is re-enabled.
|
||||
# - ansible: '2.13'
|
||||
# docker: default
|
||||
# python: '3.9'
|
||||
# target: azp/generic/1/
|
||||
# Right now all generic tests are disabled. Uncomment when at least one of them is re-enabled.
|
||||
# - ansible: '2.14'
|
||||
# docker: default
|
||||
# python: '3.10'
|
||||
# target: azp/generic/1/
|
||||
# - ansible: '2.15'
|
||||
# docker: default
|
||||
# python: '3.9'
|
||||
# target: azp/generic/1/
|
||||
|
||||
steps:
|
||||
- name: >-
|
||||
|
||||
10
.github/workflows/reuse.yml
vendored
10
.github/workflows/reuse.yml
vendored
@@ -7,10 +7,14 @@ name: Verify REUSE
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request_target:
|
||||
branches:
|
||||
- main
|
||||
- stable-*
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
branches: [main]
|
||||
branches:
|
||||
- main
|
||||
- stable-*
|
||||
# Run CI once per day (at 07:30 UTC)
|
||||
schedule:
|
||||
- cron: '30 7 * * *'
|
||||
|
||||
227
CHANGELOG.md
227
CHANGELOG.md
@@ -2,94 +2,197 @@
|
||||
|
||||
**Topics**
|
||||
|
||||
- <a href="#v8-6-3">v8\.6\.3</a>
|
||||
- <a href="#v8-6-7">v8\.6\.7</a>
|
||||
- <a href="#release-summary">Release Summary</a>
|
||||
- <a href="#minor-changes">Minor Changes</a>
|
||||
- <a href="#bugfixes">Bugfixes</a>
|
||||
- <a href="#v8-6-2">v8\.6\.2</a>
|
||||
- <a href="#v8-6-6">v8\.6\.6</a>
|
||||
- <a href="#release-summary-1">Release Summary</a>
|
||||
- <a href="#minor-changes">Minor Changes</a>
|
||||
- <a href="#bugfixes-1">Bugfixes</a>
|
||||
- <a href="#known-issues">Known Issues</a>
|
||||
- <a href="#v8-6-1">v8\.6\.1</a>
|
||||
- <a href="#v8-6-5">v8\.6\.5</a>
|
||||
- <a href="#release-summary-2">Release Summary</a>
|
||||
- <a href="#security-fixes">Security Fixes</a>
|
||||
- <a href="#bugfixes-2">Bugfixes</a>
|
||||
- <a href="#v8-6-0">v8\.6\.0</a>
|
||||
- <a href="#v8-6-4">v8\.6\.4</a>
|
||||
- <a href="#release-summary-3">Release Summary</a>
|
||||
- <a href="#minor-changes-1">Minor Changes</a>
|
||||
- <a href="#deprecated-features">Deprecated Features</a>
|
||||
- <a href="#bugfixes-3">Bugfixes</a>
|
||||
- <a href="#new-modules">New Modules</a>
|
||||
- <a href="#v8-5-0">v8\.5\.0</a>
|
||||
- <a href="#v8-6-3">v8\.6\.3</a>
|
||||
- <a href="#release-summary-4">Release Summary</a>
|
||||
- <a href="#minor-changes-2">Minor Changes</a>
|
||||
- <a href="#security-fixes-1">Security Fixes</a>
|
||||
- <a href="#bugfixes-4">Bugfixes</a>
|
||||
- <a href="#v8-6-2">v8\.6\.2</a>
|
||||
- <a href="#release-summary-5">Release Summary</a>
|
||||
- <a href="#bugfixes-5">Bugfixes</a>
|
||||
- <a href="#known-issues">Known Issues</a>
|
||||
- <a href="#v8-6-1">v8\.6\.1</a>
|
||||
- <a href="#release-summary-6">Release Summary</a>
|
||||
- <a href="#security-fixes">Security Fixes</a>
|
||||
- <a href="#bugfixes-6">Bugfixes</a>
|
||||
- <a href="#v8-6-0">v8\.6\.0</a>
|
||||
- <a href="#release-summary-7">Release Summary</a>
|
||||
- <a href="#minor-changes-3">Minor Changes</a>
|
||||
- <a href="#deprecated-features">Deprecated Features</a>
|
||||
- <a href="#bugfixes-7">Bugfixes</a>
|
||||
- <a href="#new-modules">New Modules</a>
|
||||
- <a href="#v8-5-0">v8\.5\.0</a>
|
||||
- <a href="#release-summary-8">Release Summary</a>
|
||||
- <a href="#minor-changes-4">Minor Changes</a>
|
||||
- <a href="#security-fixes-1">Security Fixes</a>
|
||||
- <a href="#bugfixes-8">Bugfixes</a>
|
||||
- <a href="#new-modules-1">New Modules</a>
|
||||
- <a href="#v8-4-0">v8\.4\.0</a>
|
||||
- <a href="#release-summary-5">Release Summary</a>
|
||||
- <a href="#minor-changes-3">Minor Changes</a>
|
||||
- <a href="#bugfixes-5">Bugfixes</a>
|
||||
- <a href="#release-summary-9">Release Summary</a>
|
||||
- <a href="#minor-changes-5">Minor Changes</a>
|
||||
- <a href="#bugfixes-9">Bugfixes</a>
|
||||
- <a href="#new-plugins">New Plugins</a>
|
||||
- <a href="#callback">Callback</a>
|
||||
- <a href="#filter">Filter</a>
|
||||
- <a href="#new-modules-2">New Modules</a>
|
||||
- <a href="#v8-3-0">v8\.3\.0</a>
|
||||
- <a href="#release-summary-6">Release Summary</a>
|
||||
- <a href="#minor-changes-4">Minor Changes</a>
|
||||
- <a href="#release-summary-10">Release Summary</a>
|
||||
- <a href="#minor-changes-6">Minor Changes</a>
|
||||
- <a href="#deprecated-features-1">Deprecated Features</a>
|
||||
- <a href="#bugfixes-6">Bugfixes</a>
|
||||
- <a href="#bugfixes-10">Bugfixes</a>
|
||||
- <a href="#new-modules-3">New Modules</a>
|
||||
- <a href="#v8-2-0">v8\.2\.0</a>
|
||||
- <a href="#release-summary-7">Release Summary</a>
|
||||
- <a href="#minor-changes-5">Minor Changes</a>
|
||||
- <a href="#bugfixes-7">Bugfixes</a>
|
||||
- <a href="#release-summary-11">Release Summary</a>
|
||||
- <a href="#minor-changes-7">Minor Changes</a>
|
||||
- <a href="#bugfixes-11">Bugfixes</a>
|
||||
- <a href="#new-plugins-1">New Plugins</a>
|
||||
- <a href="#connection">Connection</a>
|
||||
- <a href="#filter-1">Filter</a>
|
||||
- <a href="#lookup">Lookup</a>
|
||||
- <a href="#new-modules-4">New Modules</a>
|
||||
- <a href="#v8-1-0">v8\.1\.0</a>
|
||||
- <a href="#release-summary-8">Release Summary</a>
|
||||
- <a href="#minor-changes-6">Minor Changes</a>
|
||||
- <a href="#bugfixes-8">Bugfixes</a>
|
||||
- <a href="#release-summary-12">Release Summary</a>
|
||||
- <a href="#minor-changes-8">Minor Changes</a>
|
||||
- <a href="#bugfixes-12">Bugfixes</a>
|
||||
- <a href="#new-plugins-2">New Plugins</a>
|
||||
- <a href="#lookup-1">Lookup</a>
|
||||
- <a href="#test">Test</a>
|
||||
- <a href="#new-modules-5">New Modules</a>
|
||||
- <a href="#v8-0-2">v8\.0\.2</a>
|
||||
- <a href="#release-summary-9">Release Summary</a>
|
||||
- <a href="#bugfixes-9">Bugfixes</a>
|
||||
- <a href="#release-summary-13">Release Summary</a>
|
||||
- <a href="#bugfixes-13">Bugfixes</a>
|
||||
- <a href="#v8-0-1">v8\.0\.1</a>
|
||||
- <a href="#release-summary-10">Release Summary</a>
|
||||
- <a href="#bugfixes-10">Bugfixes</a>
|
||||
- <a href="#release-summary-14">Release Summary</a>
|
||||
- <a href="#bugfixes-14">Bugfixes</a>
|
||||
- <a href="#v8-0-0">v8\.0\.0</a>
|
||||
- <a href="#release-summary-11">Release Summary</a>
|
||||
- <a href="#minor-changes-7">Minor Changes</a>
|
||||
- <a href="#release-summary-15">Release Summary</a>
|
||||
- <a href="#minor-changes-9">Minor Changes</a>
|
||||
- <a href="#breaking-changes--porting-guide">Breaking Changes / Porting Guide</a>
|
||||
- <a href="#deprecated-features-2">Deprecated Features</a>
|
||||
- <a href="#removed-features-previously-deprecated">Removed Features \(previously deprecated\)</a>
|
||||
- <a href="#bugfixes-11">Bugfixes</a>
|
||||
- <a href="#bugfixes-15">Bugfixes</a>
|
||||
- <a href="#known-issues-1">Known Issues</a>
|
||||
- <a href="#new-plugins-3">New Plugins</a>
|
||||
- <a href="#lookup-2">Lookup</a>
|
||||
- <a href="#new-modules-6">New Modules</a>
|
||||
This changelog describes changes after version 7\.0\.0\.
|
||||
|
||||
<a id="v8-6-3"></a>
|
||||
## v8\.6\.3
|
||||
<a id="v8-6-7"></a>
|
||||
## v8\.6\.7
|
||||
|
||||
<a id="release-summary"></a>
|
||||
### Release Summary
|
||||
|
||||
Bugfix release\.
|
||||
|
||||
<a id="bugfixes"></a>
|
||||
### Bugfixes
|
||||
|
||||
* collection\_version lookup plugin \- use <code>importlib</code> directly instead of the deprecated and in ansible\-core 2\.19 removed <code>ansible\.module\_utils\.compat\.importlib</code> \([https\://github\.com/ansible\-collections/community\.general/pull/9084](https\://github\.com/ansible\-collections/community\.general/pull/9084)\)\.
|
||||
* modprobe \- fix check mode not being honored for <code>persistent</code> option \([https\://github\.com/ansible\-collections/community\.general/issues/9051](https\://github\.com/ansible\-collections/community\.general/issues/9051)\, [https\://github\.com/ansible\-collections/community\.general/pull/9052](https\://github\.com/ansible\-collections/community\.general/pull/9052)\)\.
|
||||
|
||||
<a id="v8-6-6"></a>
|
||||
## v8\.6\.6
|
||||
|
||||
<a id="release-summary-1"></a>
|
||||
### Release Summary
|
||||
|
||||
Regular bugfix release\.
|
||||
|
||||
Note that this is the last regular bugfix release of community\.general 8\.x\.y\.
|
||||
From now on\, there will only be maintenance releases with major bugfixes and
|
||||
security fixes\.
|
||||
|
||||
<a id="minor-changes"></a>
|
||||
### Minor Changes
|
||||
|
||||
* redfish\_confg \- remove <code>CapacityBytes</code> from required paramaters of the <code>CreateVolume</code> command \([https\://github\.com/ansible\-collections/community\.general/pull/8956](https\://github\.com/ansible\-collections/community\.general/pull/8956)\)\.
|
||||
|
||||
<a id="bugfixes-1"></a>
|
||||
### Bugfixes
|
||||
|
||||
* cloudflare\_dns \- fix changing Cloudflare SRV records \([https\://github\.com/ansible\-collections/community\.general/issues/8679](https\://github\.com/ansible\-collections/community\.general/issues/8679)\, [https\://github\.com/ansible\-collections/community\.general/pull/8948](https\://github\.com/ansible\-collections/community\.general/pull/8948)\)\.
|
||||
* dig lookup plugin \- fix using only the last nameserver specified \([https\://github\.com/ansible\-collections/community\.general/pull/8970](https\://github\.com/ansible\-collections/community\.general/pull/8970)\)\.
|
||||
* homectl \- the module now tries to use <code>legacycrypt</code> on Python 3\.13\+ \([https\://github\.com/ansible\-collections/community\.general/issues/4691](https\://github\.com/ansible\-collections/community\.general/issues/4691)\, [https\://github\.com/ansible\-collections/community\.general/pull/8987](https\://github\.com/ansible\-collections/community\.general/pull/8987)\)\.
|
||||
* ini\_file \- pass absolute paths to <code>module\.atomic\_move\(\)</code> \([https\://github\.com/ansible/ansible/issues/83950](https\://github\.com/ansible/ansible/issues/83950)\, [https\://github\.com/ansible\-collections/community\.general/pull/8925](https\://github\.com/ansible\-collections/community\.general/pull/8925)\)\.
|
||||
* ipa\_hostgroup \- fix <code>enabled \`\` and \`\`disabled</code> states \([https\://github\.com/ansible\-collections/community\.general/issues/8408](https\://github\.com/ansible\-collections/community\.general/issues/8408)\, [https\://github\.com/ansible\-collections/community\.general/pull/8900](https\://github\.com/ansible\-collections/community\.general/pull/8900)\)\.
|
||||
* java\_keystore \- pass absolute paths to <code>module\.atomic\_move\(\)</code> \([https\://github\.com/ansible/ansible/issues/83950](https\://github\.com/ansible/ansible/issues/83950)\, [https\://github\.com/ansible\-collections/community\.general/pull/8925](https\://github\.com/ansible\-collections/community\.general/pull/8925)\)\.
|
||||
* jenkins\_plugin \- pass absolute paths to <code>module\.atomic\_move\(\)</code> \([https\://github\.com/ansible/ansible/issues/83950](https\://github\.com/ansible/ansible/issues/83950)\, [https\://github\.com/ansible\-collections/community\.general/pull/8925](https\://github\.com/ansible\-collections/community\.general/pull/8925)\)\.
|
||||
* kdeconfig \- pass absolute paths to <code>module\.atomic\_move\(\)</code> \([https\://github\.com/ansible/ansible/issues/83950](https\://github\.com/ansible/ansible/issues/83950)\, [https\://github\.com/ansible\-collections/community\.general/pull/8925](https\://github\.com/ansible\-collections/community\.general/pull/8925)\)\.
|
||||
* keycloak\_realm \- fix change detection in check mode by sorting the lists in the realms beforehand \([https\://github\.com/ansible\-collections/community\.general/pull/8877](https\://github\.com/ansible\-collections/community\.general/pull/8877)\)\.
|
||||
* keycloak\_user\_federation \- minimize change detection by setting <code>krbPrincipalAttribute</code> to <code>\'\'</code> in Keycloak responses if missing \([https\://github\.com/ansible\-collections/community\.general/pull/8785](https\://github\.com/ansible\-collections/community\.general/pull/8785)\)\.
|
||||
* keycloak\_user\_federation \- remove <code>lastSync</code> parameter from Keycloak responses to minimize diff/changes \([https\://github\.com/ansible\-collections/community\.general/pull/8812](https\://github\.com/ansible\-collections/community\.general/pull/8812)\)\.
|
||||
* one\_service \- fix service creation after it was deleted with <code>unique</code> parameter \([https\://github\.com/ansible\-collections/community\.general/issues/3137](https\://github\.com/ansible\-collections/community\.general/issues/3137)\, [https\://github\.com/ansible\-collections/community\.general/pull/8887](https\://github\.com/ansible\-collections/community\.general/pull/8887)\)\.
|
||||
* pam\_limits \- pass absolute paths to <code>module\.atomic\_move\(\)</code> \([https\://github\.com/ansible/ansible/issues/83950](https\://github\.com/ansible/ansible/issues/83950)\, [https\://github\.com/ansible\-collections/community\.general/pull/8925](https\://github\.com/ansible\-collections/community\.general/pull/8925)\)\.
|
||||
* udm\_user \- the module now tries to use <code>legacycrypt</code> on Python 3\.13\+ \([https\://github\.com/ansible\-collections/community\.general/issues/4690](https\://github\.com/ansible\-collections/community\.general/issues/4690)\, [https\://github\.com/ansible\-collections/community\.general/pull/8987](https\://github\.com/ansible\-collections/community\.general/pull/8987)\)\.
|
||||
|
||||
<a id="v8-6-5"></a>
|
||||
## v8\.6\.5
|
||||
|
||||
<a id="release-summary-2"></a>
|
||||
### Release Summary
|
||||
|
||||
Regular bugfix release\.
|
||||
|
||||
<a id="bugfixes-2"></a>
|
||||
### Bugfixes
|
||||
|
||||
* gitlab\_group\_access\_token \- fix crash in check mode caused by attempted access to a newly created access token \([https\://github\.com/ansible\-collections/community\.general/pull/8796](https\://github\.com/ansible\-collections/community\.general/pull/8796)\)\.
|
||||
* gitlab\_project\_access\_token \- fix crash in check mode caused by attempted access to a newly created access token \([https\://github\.com/ansible\-collections/community\.general/pull/8796](https\://github\.com/ansible\-collections/community\.general/pull/8796)\)\.
|
||||
* keycloak\_realm\_key \- fix invalid usage of <code>parent\_id</code> \([https\://github\.com/ansible\-collections/community\.general/issues/7850](https\://github\.com/ansible\-collections/community\.general/issues/7850)\, [https\://github\.com/ansible\-collections/community\.general/pull/8823](https\://github\.com/ansible\-collections/community\.general/pull/8823)\)\.
|
||||
* keycloak\_user\_federation \- fix key error when removing mappers during an update and new mappers are specified in the module args \([https\://github\.com/ansible\-collections/community\.general/pull/8762](https\://github\.com/ansible\-collections/community\.general/pull/8762)\)\.
|
||||
* keycloak\_user\_federation \- fix the <code>UnboundLocalError</code> that occurs when an ID is provided for a user federation mapper \([https\://github\.com/ansible\-collections/community\.general/pull/8831](https\://github\.com/ansible\-collections/community\.general/pull/8831)\)\.
|
||||
* keycloak\_user\_federation \- sort desired and after mapper list by name \(analog to before mapper list\) to minimize diff and make change detection more accurate \([https\://github\.com/ansible\-collections/community\.general/pull/8761](https\://github\.com/ansible\-collections/community\.general/pull/8761)\)\.
|
||||
* proxmox inventory plugin \- fixed a possible error on concatenating responses from proxmox\. In case an API call unexpectedly returned an empty result\, the inventory failed with a fatal error\. Added check for empty response \([https\://github\.com/ansible\-collections/community\.general/issues/8798](https\://github\.com/ansible\-collections/community\.general/issues/8798)\, [https\://github\.com/ansible\-collections/community\.general/pull/8794](https\://github\.com/ansible\-collections/community\.general/pull/8794)\)\.
|
||||
|
||||
<a id="v8-6-4"></a>
|
||||
## v8\.6\.4
|
||||
|
||||
<a id="release-summary-3"></a>
|
||||
### Release Summary
|
||||
|
||||
Regular bugfix release\.
|
||||
|
||||
<a id="minor-changes-1"></a>
|
||||
### Minor Changes
|
||||
|
||||
* passwordstore lookup plugin \- add the current user to the lockfile file name to address issues on multi\-user systems \([https\://github\.com/ansible\-collections/community\.general/pull/8689](https\://github\.com/ansible\-collections/community\.general/pull/8689)\)\.
|
||||
|
||||
<a id="bugfixes-3"></a>
|
||||
### Bugfixes
|
||||
|
||||
* gitlab\_runner \- fix <code>paused</code> parameter being ignored \([https\://github\.com/ansible\-collections/community\.general/pull/8648](https\://github\.com/ansible\-collections/community\.general/pull/8648)\)\.
|
||||
* homebrew\_cask \- fix <code>upgrade\_all</code> returns <code>changed</code> when nothing upgraded \([https\://github\.com/ansible\-collections/community\.general/issues/8707](https\://github\.com/ansible\-collections/community\.general/issues/8707)\, [https\://github\.com/ansible\-collections/community\.general/pull/8708](https\://github\.com/ansible\-collections/community\.general/pull/8708)\)\.
|
||||
* keycloak\_user\_federation \- get cleartext IDP <code>clientSecret</code> from full realm info to detect changes to it \([https\://github\.com/ansible\-collections/community\.general/issues/8294](https\://github\.com/ansible\-collections/community\.general/issues/8294)\, [https\://github\.com/ansible\-collections/community\.general/pull/8735](https\://github\.com/ansible\-collections/community\.general/pull/8735)\)\.
|
||||
* keycloak\_user\_federation \- remove existing user federation mappers if they are not present in the federation configuration and will not be updated \([https\://github\.com/ansible\-collections/community\.general/issues/7169](https\://github\.com/ansible\-collections/community\.general/issues/7169)\, [https\://github\.com/ansible\-collections/community\.general/pull/8695](https\://github\.com/ansible\-collections/community\.general/pull/8695)\)\.
|
||||
|
||||
<a id="v8-6-3"></a>
|
||||
## v8\.6\.3
|
||||
|
||||
<a id="release-summary-4"></a>
|
||||
### Release Summary
|
||||
|
||||
Regular bugfix release\.
|
||||
|
||||
<a id="minor-changes-2"></a>
|
||||
### Minor Changes
|
||||
|
||||
* wdc\_redfish\_command \- minor change to handle upgrade file for Redfish WD platforms \([https\://github\.com/ansible\-collections/community\.general/pull/8444](https\://github\.com/ansible\-collections/community\.general/pull/8444)\)\.
|
||||
|
||||
<a id="bugfixes"></a>
|
||||
<a id="bugfixes-4"></a>
|
||||
### Bugfixes
|
||||
|
||||
* bitwarden lookup plugin \- fix <code>KeyError</code> in <code>search\_field</code> \([https\://github\.com/ansible\-collections/community\.general/issues/8549](https\://github\.com/ansible\-collections/community\.general/issues/8549)\, [https\://github\.com/ansible\-collections/community\.general/pull/8557](https\://github\.com/ansible\-collections/community\.general/pull/8557)\)\.
|
||||
@@ -100,12 +203,12 @@ Regular bugfix release\.
|
||||
<a id="v8-6-2"></a>
|
||||
## v8\.6\.2
|
||||
|
||||
<a id="release-summary-1"></a>
|
||||
<a id="release-summary-5"></a>
|
||||
### Release Summary
|
||||
|
||||
Regular bugfix release\.
|
||||
|
||||
<a id="bugfixes-1"></a>
|
||||
<a id="bugfixes-5"></a>
|
||||
### Bugfixes
|
||||
|
||||
* git\_config \- fix behavior of <code>state\=absent</code> if <code>value</code> is present \([https\://github\.com/ansible\-collections/community\.general/issues/8436](https\://github\.com/ansible\-collections/community\.general/issues/8436)\, [https\://github\.com/ansible\-collections/community\.general/pull/8452](https\://github\.com/ansible\-collections/community\.general/pull/8452)\)\.
|
||||
@@ -127,7 +230,7 @@ Regular bugfix release\.
|
||||
<a id="v8-6-1"></a>
|
||||
## v8\.6\.1
|
||||
|
||||
<a id="release-summary-2"></a>
|
||||
<a id="release-summary-6"></a>
|
||||
### Release Summary
|
||||
|
||||
Regular bugfix release\.
|
||||
@@ -137,7 +240,7 @@ Regular bugfix release\.
|
||||
|
||||
* 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-2"></a>
|
||||
<a id="bugfixes-6"></a>
|
||||
### Bugfixes
|
||||
|
||||
* keycloak\_user\_federation \- fix diff of empty <code>krbPrincipalAttribute</code> \([https\://github\.com/ansible\-collections/community\.general/pull/8320](https\://github\.com/ansible\-collections/community\.general/pull/8320)\)\.
|
||||
@@ -148,12 +251,12 @@ Regular bugfix release\.
|
||||
<a id="v8-6-0"></a>
|
||||
## v8\.6\.0
|
||||
|
||||
<a id="release-summary-3"></a>
|
||||
<a id="release-summary-7"></a>
|
||||
### Release Summary
|
||||
|
||||
Regular bugfix and features release\.
|
||||
|
||||
<a id="minor-changes-1"></a>
|
||||
<a id="minor-changes-3"></a>
|
||||
### Minor Changes
|
||||
|
||||
* Use offset\-aware <code>datetime\.datetime</code> objects \(with timezone UTC\) instead of offset\-naive UTC timestamps\, which are deprecated in Python 3\.12 \([https\://github\.com/ansible\-collections/community\.general/pull/8222](https\://github\.com/ansible\-collections/community\.general/pull/8222)\)\.
|
||||
@@ -176,7 +279,7 @@ Regular bugfix and features release\.
|
||||
|
||||
* hipchat callback plugin \- the hipchat service has been discontinued and the self\-hosted variant has been End of Life since 2020\. The callback plugin is therefore deprecated and will be removed from community\.general 10\.0\.0 if nobody provides compelling reasons to still keep it \([https\://github\.com/ansible\-collections/community\.general/issues/8184](https\://github\.com/ansible\-collections/community\.general/issues/8184)\, [https\://github\.com/ansible\-collections/community\.general/pull/8189](https\://github\.com/ansible\-collections/community\.general/pull/8189)\)\.
|
||||
|
||||
<a id="bugfixes-3"></a>
|
||||
<a id="bugfixes-7"></a>
|
||||
### Bugfixes
|
||||
|
||||
* aix\_filesystem \- fix <code>\_validate\_vg</code> not passing VG name to <code>lsvg\_cmd</code> \([https\://github\.com/ansible\-collections/community\.general/issues/8151](https\://github\.com/ansible\-collections/community\.general/issues/8151)\)\.
|
||||
@@ -202,12 +305,12 @@ Regular bugfix and features release\.
|
||||
<a id="v8-5-0"></a>
|
||||
## v8\.5\.0
|
||||
|
||||
<a id="release-summary-4"></a>
|
||||
<a id="release-summary-8"></a>
|
||||
### Release Summary
|
||||
|
||||
Regular feature and bugfix release with security fixes\.
|
||||
|
||||
<a id="minor-changes-2"></a>
|
||||
<a id="minor-changes-4"></a>
|
||||
### Minor Changes
|
||||
|
||||
* bitwarden lookup plugin \- allows to fetch all records of a given collection ID\, by allowing to pass an empty value for <code>search\_value</code> when <code>collection\_id</code> is provided \([https\://github\.com/ansible\-collections/community\.general/pull/8013](https\://github\.com/ansible\-collections/community\.general/pull/8013)\)\.
|
||||
@@ -225,7 +328,7 @@ Regular feature and bugfix release with 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-4"></a>
|
||||
<a id="bugfixes-8"></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)\)\.
|
||||
@@ -247,12 +350,12 @@ Regular feature and bugfix release with security fixes\.
|
||||
<a id="v8-4-0"></a>
|
||||
## v8\.4\.0
|
||||
|
||||
<a id="release-summary-5"></a>
|
||||
<a id="release-summary-9"></a>
|
||||
### Release Summary
|
||||
|
||||
Regular bugfix and feature release\.
|
||||
|
||||
<a id="minor-changes-3"></a>
|
||||
<a id="minor-changes-5"></a>
|
||||
### Minor Changes
|
||||
|
||||
* bitwarden lookup plugin \- add <code>bw\_session</code> option\, to pass session key instead of reading from env \([https\://github\.com/ansible\-collections/community\.general/pull/7994](https\://github\.com/ansible\-collections/community\.general/pull/7994)\)\.
|
||||
@@ -265,7 +368,7 @@ Regular bugfix and feature release\.
|
||||
* sudoers \- add support for the <code>NOEXEC</code> tag in sudoers rules \([https\://github\.com/ansible\-collections/community\.general/pull/7983](https\://github\.com/ansible\-collections/community\.general/pull/7983)\)\.
|
||||
* terraform \- fix <code>diff\_mode</code> in state <code>absent</code> and when terraform <code>resource\_changes</code> does not exist \([https\://github\.com/ansible\-collections/community\.general/pull/7963](https\://github\.com/ansible\-collections/community\.general/pull/7963)\)\.
|
||||
|
||||
<a id="bugfixes-5"></a>
|
||||
<a id="bugfixes-9"></a>
|
||||
### Bugfixes
|
||||
|
||||
* cargo \- fix idempotency issues when using a custom installation path for packages \(using the <code>\-\-path</code> parameter\)\. The initial installation runs fine\, but subsequent runs use the <code>get\_installed\(\)</code> function which did not check the given installation location\, before running <code>cargo install</code>\. This resulted in a false <code>changed</code> state\. Also the removal of packeges using <code>state\: absent</code> failed\, as the installation check did not use the given parameter \([https\://github\.com/ansible\-collections/community\.general/pull/7970](https\://github\.com/ansible\-collections/community\.general/pull/7970)\)\.
|
||||
@@ -303,12 +406,12 @@ Regular bugfix and feature release\.
|
||||
<a id="v8-3-0"></a>
|
||||
## v8\.3\.0
|
||||
|
||||
<a id="release-summary-6"></a>
|
||||
<a id="release-summary-10"></a>
|
||||
### Release Summary
|
||||
|
||||
Regular bugfix and feature release\.
|
||||
|
||||
<a id="minor-changes-4"></a>
|
||||
<a id="minor-changes-6"></a>
|
||||
### Minor Changes
|
||||
|
||||
* consul\_auth\_method\, consul\_binding\_rule\, consul\_policy\, consul\_role\, consul\_session\, consul\_token \- added action group <code>community\.general\.consul</code> \([https\://github\.com/ansible\-collections/community\.general/pull/7897](https\://github\.com/ansible\-collections/community\.general/pull/7897)\)\.
|
||||
@@ -326,7 +429,7 @@ Regular bugfix and feature release\.
|
||||
|
||||
* consul\_acl \- the module has been deprecated and will be removed in community\.general 10\.0\.0\. <code>consul\_token</code> and <code>consul\_policy</code> can be used instead \([https\://github\.com/ansible\-collections/community\.general/pull/7901](https\://github\.com/ansible\-collections/community\.general/pull/7901)\)\.
|
||||
|
||||
<a id="bugfixes-6"></a>
|
||||
<a id="bugfixes-10"></a>
|
||||
### Bugfixes
|
||||
|
||||
* homebrew \- detect already installed formulae and casks using JSON output from <code>brew info</code> \([https\://github\.com/ansible\-collections/community\.general/issues/864](https\://github\.com/ansible\-collections/community\.general/issues/864)\)\.
|
||||
@@ -350,12 +453,12 @@ Regular bugfix and feature release\.
|
||||
<a id="v8-2-0"></a>
|
||||
## v8\.2\.0
|
||||
|
||||
<a id="release-summary-7"></a>
|
||||
<a id="release-summary-11"></a>
|
||||
### Release Summary
|
||||
|
||||
Regular bugfix and feature release\.
|
||||
|
||||
<a id="minor-changes-5"></a>
|
||||
<a id="minor-changes-7"></a>
|
||||
### Minor Changes
|
||||
|
||||
* ipa\_dnsrecord \- adds ability to manage NS record types \([https\://github\.com/ansible\-collections/community\.general/pull/7737](https\://github\.com/ansible\-collections/community\.general/pull/7737)\)\.
|
||||
@@ -371,7 +474,7 @@ Regular bugfix and feature release\.
|
||||
* ssh\_config \- new feature to set <code>IdentitiesOnly</code> option to <code>yes</code> or <code>no</code> \([https\://github\.com/ansible\-collections/community\.general/pull/7704](https\://github\.com/ansible\-collections/community\.general/pull/7704)\)\.
|
||||
* xcc\_redfish\_command \- added support for raw POSTs \(<code>command\=PostResource</code> in <code>category\=Raw</code>\) without a specific action info \([https\://github\.com/ansible\-collections/community\.general/pull/7746](https\://github\.com/ansible\-collections/community\.general/pull/7746)\)\.
|
||||
|
||||
<a id="bugfixes-7"></a>
|
||||
<a id="bugfixes-11"></a>
|
||||
### Bugfixes
|
||||
|
||||
* keycloak\_identity\_provider \- <code>mappers</code> processing was not idempotent if the mappers configuration list had not been sorted by name \(in ascending order\)\. Fix resolves the issue by sorting mappers in the desired state using the same key which is used for obtaining existing state \([https\://github\.com/ansible\-collections/community\.general/pull/7418](https\://github\.com/ansible\-collections/community\.general/pull/7418)\)\.
|
||||
@@ -411,12 +514,12 @@ Regular bugfix and feature release\.
|
||||
<a id="v8-1-0"></a>
|
||||
## v8\.1\.0
|
||||
|
||||
<a id="release-summary-8"></a>
|
||||
<a id="release-summary-12"></a>
|
||||
### Release Summary
|
||||
|
||||
Regular bugfix and feature release\.
|
||||
|
||||
<a id="minor-changes-6"></a>
|
||||
<a id="minor-changes-8"></a>
|
||||
### Minor Changes
|
||||
|
||||
* bitwarden lookup plugin \- when looking for items using an item ID\, the item is now accessed directly with <code>bw get item</code> instead of searching through all items\. This doubles the lookup speed \([https\://github\.com/ansible\-collections/community\.general/pull/7468](https\://github\.com/ansible\-collections/community\.general/pull/7468)\)\.
|
||||
@@ -453,7 +556,7 @@ Regular bugfix and feature release\.
|
||||
* redfish\_info \- adding the <code>BootProgress</code> property when getting <code>Systems</code> info \([https\://github\.com/ansible\-collections/community\.general/pull/7626](https\://github\.com/ansible\-collections/community\.general/pull/7626)\)\.
|
||||
* ssh\_config \- adds <code>controlmaster</code>\, <code>controlpath</code> and <code>controlpersist</code> parameters \([https\://github\.com/ansible\-collections/community\.general/pull/7456](https\://github\.com/ansible\-collections/community\.general/pull/7456)\)\.
|
||||
|
||||
<a id="bugfixes-8"></a>
|
||||
<a id="bugfixes-12"></a>
|
||||
### Bugfixes
|
||||
|
||||
* apt\-rpm \- the module did not upgrade packages if a newer version exists\. Now the package will be reinstalled if the candidate is newer than the installed version \([https\://github\.com/ansible\-collections/community\.general/issues/7414](https\://github\.com/ansible\-collections/community\.general/issues/7414)\)\.
|
||||
@@ -494,12 +597,12 @@ Regular bugfix and feature release\.
|
||||
<a id="v8-0-2"></a>
|
||||
## v8\.0\.2
|
||||
|
||||
<a id="release-summary-9"></a>
|
||||
<a id="release-summary-13"></a>
|
||||
### Release Summary
|
||||
|
||||
Bugfix release for inclusion in Ansible 9\.0\.0rc1\.
|
||||
|
||||
<a id="bugfixes-9"></a>
|
||||
<a id="bugfixes-13"></a>
|
||||
### Bugfixes
|
||||
|
||||
* ocapi\_utils\, oci\_utils\, redfish\_utils module utils \- replace <code>type\(\)</code> calls with <code>isinstance\(\)</code> calls \([https\://github\.com/ansible\-collections/community\.general/pull/7501](https\://github\.com/ansible\-collections/community\.general/pull/7501)\)\.
|
||||
@@ -508,12 +611,12 @@ Bugfix release for inclusion in Ansible 9\.0\.0rc1\.
|
||||
<a id="v8-0-1"></a>
|
||||
## v8\.0\.1
|
||||
|
||||
<a id="release-summary-10"></a>
|
||||
<a id="release-summary-14"></a>
|
||||
### Release Summary
|
||||
|
||||
Bugfix release for inclusion in Ansible 9\.0\.0b1\.
|
||||
|
||||
<a id="bugfixes-10"></a>
|
||||
<a id="bugfixes-14"></a>
|
||||
### Bugfixes
|
||||
|
||||
* 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)\)\.
|
||||
@@ -526,12 +629,12 @@ Bugfix release for inclusion in Ansible 9\.0\.0b1\.
|
||||
<a id="v8-0-0"></a>
|
||||
## v8\.0\.0
|
||||
|
||||
<a id="release-summary-11"></a>
|
||||
<a id="release-summary-15"></a>
|
||||
### Release Summary
|
||||
|
||||
This is release 8\.0\.0 of <code>community\.general</code>\, released on 2023\-11\-01\.
|
||||
|
||||
<a id="minor-changes-7"></a>
|
||||
<a id="minor-changes-9"></a>
|
||||
### Minor Changes
|
||||
|
||||
* The collection will start using semantic markup \([https\://github\.com/ansible\-collections/community\.general/pull/6539](https\://github\.com/ansible\-collections/community\.general/pull/6539)\)\.
|
||||
@@ -730,7 +833,7 @@ This is release 8\.0\.0 of <code>community\.general</code>\, released on 2023\-1
|
||||
* proxmox module utils \- removed unused imports \([https\://github\.com/ansible\-collections/community\.general/pull/6873](https\://github\.com/ansible\-collections/community\.general/pull/6873)\)\.
|
||||
* xfconf \- the deprecated <code>disable\_facts</code> option was removed \([https\://github\.com/ansible\-collections/community\.general/pull/7358](https\://github\.com/ansible\-collections/community\.general/pull/7358)\)\.
|
||||
|
||||
<a id="bugfixes-11"></a>
|
||||
<a id="bugfixes-15"></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)\)\.
|
||||
|
||||
@@ -6,6 +6,95 @@ Community General Release Notes
|
||||
|
||||
This changelog describes changes after version 7.0.0.
|
||||
|
||||
v8.6.7
|
||||
======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
Bugfix release.
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- collection_version lookup plugin - use ``importlib`` directly instead of the deprecated and in ansible-core 2.19 removed ``ansible.module_utils.compat.importlib`` (https://github.com/ansible-collections/community.general/pull/9084).
|
||||
- modprobe - fix check mode not being honored for ``persistent`` option (https://github.com/ansible-collections/community.general/issues/9051, https://github.com/ansible-collections/community.general/pull/9052).
|
||||
|
||||
v8.6.6
|
||||
======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
Regular bugfix release.
|
||||
|
||||
Note that this is the last regular bugfix release of community.general 8.x.y.
|
||||
From now on, there will only be maintenance releases with major bugfixes and
|
||||
security fixes.
|
||||
|
||||
Minor Changes
|
||||
-------------
|
||||
|
||||
- redfish_confg - remove ``CapacityBytes`` from required paramaters of the ``CreateVolume`` command (https://github.com/ansible-collections/community.general/pull/8956).
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- cloudflare_dns - fix changing Cloudflare SRV records (https://github.com/ansible-collections/community.general/issues/8679, https://github.com/ansible-collections/community.general/pull/8948).
|
||||
- dig lookup plugin - fix using only the last nameserver specified (https://github.com/ansible-collections/community.general/pull/8970).
|
||||
- homectl - the module now tries to use ``legacycrypt`` on Python 3.13+ (https://github.com/ansible-collections/community.general/issues/4691, https://github.com/ansible-collections/community.general/pull/8987).
|
||||
- ini_file - pass absolute paths to ``module.atomic_move()`` (https://github.com/ansible/ansible/issues/83950, https://github.com/ansible-collections/community.general/pull/8925).
|
||||
- ipa_hostgroup - fix ``enabled `` and ``disabled`` states (https://github.com/ansible-collections/community.general/issues/8408, https://github.com/ansible-collections/community.general/pull/8900).
|
||||
- java_keystore - pass absolute paths to ``module.atomic_move()`` (https://github.com/ansible/ansible/issues/83950, https://github.com/ansible-collections/community.general/pull/8925).
|
||||
- jenkins_plugin - pass absolute paths to ``module.atomic_move()`` (https://github.com/ansible/ansible/issues/83950, https://github.com/ansible-collections/community.general/pull/8925).
|
||||
- kdeconfig - pass absolute paths to ``module.atomic_move()`` (https://github.com/ansible/ansible/issues/83950, https://github.com/ansible-collections/community.general/pull/8925).
|
||||
- keycloak_realm - fix change detection in check mode by sorting the lists in the realms beforehand (https://github.com/ansible-collections/community.general/pull/8877).
|
||||
- keycloak_user_federation - minimize change detection by setting ``krbPrincipalAttribute`` to ``''`` in Keycloak responses if missing (https://github.com/ansible-collections/community.general/pull/8785).
|
||||
- keycloak_user_federation - remove ``lastSync`` parameter from Keycloak responses to minimize diff/changes (https://github.com/ansible-collections/community.general/pull/8812).
|
||||
- one_service - fix service creation after it was deleted with ``unique`` parameter (https://github.com/ansible-collections/community.general/issues/3137, https://github.com/ansible-collections/community.general/pull/8887).
|
||||
- pam_limits - pass absolute paths to ``module.atomic_move()`` (https://github.com/ansible/ansible/issues/83950, https://github.com/ansible-collections/community.general/pull/8925).
|
||||
- udm_user - the module now tries to use ``legacycrypt`` on Python 3.13+ (https://github.com/ansible-collections/community.general/issues/4690, https://github.com/ansible-collections/community.general/pull/8987).
|
||||
|
||||
v8.6.5
|
||||
======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
Regular bugfix release.
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- gitlab_group_access_token - fix crash in check mode caused by attempted access to a newly created access token (https://github.com/ansible-collections/community.general/pull/8796).
|
||||
- gitlab_project_access_token - fix crash in check mode caused by attempted access to a newly created access token (https://github.com/ansible-collections/community.general/pull/8796).
|
||||
- keycloak_realm_key - fix invalid usage of ``parent_id`` (https://github.com/ansible-collections/community.general/issues/7850, https://github.com/ansible-collections/community.general/pull/8823).
|
||||
- keycloak_user_federation - fix key error when removing mappers during an update and new mappers are specified in the module args (https://github.com/ansible-collections/community.general/pull/8762).
|
||||
- keycloak_user_federation - fix the ``UnboundLocalError`` that occurs when an ID is provided for a user federation mapper (https://github.com/ansible-collections/community.general/pull/8831).
|
||||
- keycloak_user_federation - sort desired and after mapper list by name (analog to before mapper list) to minimize diff and make change detection more accurate (https://github.com/ansible-collections/community.general/pull/8761).
|
||||
- proxmox inventory plugin - fixed a possible error on concatenating responses from proxmox. In case an API call unexpectedly returned an empty result, the inventory failed with a fatal error. Added check for empty response (https://github.com/ansible-collections/community.general/issues/8798, https://github.com/ansible-collections/community.general/pull/8794).
|
||||
|
||||
v8.6.4
|
||||
======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
Regular bugfix release.
|
||||
|
||||
Minor Changes
|
||||
-------------
|
||||
|
||||
- passwordstore lookup plugin - add the current user to the lockfile file name to address issues on multi-user systems (https://github.com/ansible-collections/community.general/pull/8689).
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- gitlab_runner - fix ``paused`` parameter being ignored (https://github.com/ansible-collections/community.general/pull/8648).
|
||||
- homebrew_cask - fix ``upgrade_all`` returns ``changed`` when nothing upgraded (https://github.com/ansible-collections/community.general/issues/8707, https://github.com/ansible-collections/community.general/pull/8708).
|
||||
- keycloak_user_federation - get cleartext IDP ``clientSecret`` from full realm info to detect changes to it (https://github.com/ansible-collections/community.general/issues/8294, https://github.com/ansible-collections/community.general/pull/8735).
|
||||
- keycloak_user_federation - remove existing user federation mappers if they are not present in the federation configuration and will not be updated (https://github.com/ansible-collections/community.general/issues/7169, https://github.com/ansible-collections/community.general/pull/8695).
|
||||
|
||||
v8.6.3
|
||||
======
|
||||
|
||||
|
||||
@@ -56,6 +56,8 @@ cd ~/dev/ansible_collections/community/general
|
||||
|
||||
Then you can run `ansible-test` (which is a part of [ansible-core](https://pypi.org/project/ansible-core/)) inside the checkout. The following example commands expect that you have installed Docker or Podman. Note that Podman has only been supported by more recent ansible-core releases. If you are using Docker, the following will work with Ansible 2.9+.
|
||||
|
||||
### Sanity tests
|
||||
|
||||
The following commands show how to run sanity tests:
|
||||
|
||||
```.bash
|
||||
@@ -66,6 +68,8 @@ ansible-test sanity --docker -v
|
||||
ansible-test sanity --docker -v plugins/modules/system/pids.py tests/integration/targets/pids/
|
||||
```
|
||||
|
||||
### Unit tests
|
||||
|
||||
The following commands show how to run unit tests:
|
||||
|
||||
```.bash
|
||||
@@ -79,13 +83,32 @@ ansible-test units --docker -v --python 3.8
|
||||
ansible-test units --docker -v --python 3.8 tests/unit/plugins/modules/net_tools/test_nmcli.py
|
||||
```
|
||||
|
||||
### Integration tests
|
||||
|
||||
The following commands show how to run integration tests:
|
||||
|
||||
```.bash
|
||||
# Run integration tests for the interfaces_files module in a Docker container using the
|
||||
# fedora35 operating system image (the supported images depend on your ansible-core version):
|
||||
ansible-test integration --docker fedora35 -v interfaces_file
|
||||
#### In Docker
|
||||
|
||||
Integration tests on Docker have the following parameters:
|
||||
- `image_name` (required): The name of the Docker image. To get the list of supported Docker images, run
|
||||
`ansible-test integration --help` and look for _target docker images_.
|
||||
- `test_name` (optional): The name of the integration test.
|
||||
For modules, this equals the short name of the module; for example, `pacman` in case of `community.general.pacman`.
|
||||
For plugins, the plugin type is added before the plugin's short name, for example `callback_yaml` for the `community.general.yaml` callback.
|
||||
```.bash
|
||||
# Test all plugins/modules on fedora40
|
||||
ansible-test integration -v --docker fedora40
|
||||
|
||||
# Template
|
||||
ansible-test integration -v --docker image_name test_name
|
||||
|
||||
# Example community.general.ini_file module on fedora40 Docker image:
|
||||
ansible-test integration -v --docker fedora40 ini_file
|
||||
```
|
||||
|
||||
#### Without isolation
|
||||
|
||||
```.bash
|
||||
# Run integration tests for the flattened lookup **without any isolation**:
|
||||
ansible-test integration -v lookup_flattened
|
||||
```
|
||||
|
||||
26
README.md
26
README.md
@@ -23,9 +23,21 @@ We follow [Ansible Code of Conduct](https://docs.ansible.com/ansible/latest/comm
|
||||
|
||||
If you encounter abusive behavior violating the [Ansible Code of Conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html), please refer to the [policy violations](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html#policy-violations) section of the Code of Conduct for information on how to raise a complaint.
|
||||
|
||||
## Communication
|
||||
|
||||
* Join the Ansible forum:
|
||||
* [Get Help](https://forum.ansible.com/c/help/6): get help or help others. This is for questions about modules or plugins in the collection. Please add appropriate tags if you start new discussions.
|
||||
* [Tag `community-general`](https://forum.ansible.com/tag/community-general): discuss the *collection itself*, instead of specific modules or plugins.
|
||||
* [Social Spaces](https://forum.ansible.com/c/chat/4): gather and interact with fellow enthusiasts.
|
||||
* [News & Announcements](https://forum.ansible.com/c/news/5): track project-wide announcements including social events.
|
||||
|
||||
* The Ansible [Bullhorn newsletter](https://docs.ansible.com/ansible/devel/community/communication.html#the-bullhorn): used to announce releases and important changes.
|
||||
|
||||
For more information about communication, see the [Ansible communication guide](https://docs.ansible.com/ansible/devel/community/communication.html).
|
||||
|
||||
## Tested with Ansible
|
||||
|
||||
Tested with the current ansible-core 2.13, ansible-core 2.14, ansible-core 2.15, ansible-core 2.16, ansible-core 2.17 releases and the current development version of ansible-core. Ansible-core versions before 2.13.0 are not supported. This includes all ansible-base 2.10 and Ansible 2.9 releases.
|
||||
Tested with the current ansible-core 2.13, ansible-core 2.14, ansible-core 2.15, ansible-core 2.16, ansible-core 2.17, and ansible-core 2.18 releases of ansible-core. Ansible-core versions before 2.13.0 are not supported. This includes all ansible-base 2.10 and Ansible 2.9 releases.
|
||||
|
||||
## External requirements
|
||||
|
||||
@@ -98,18 +110,6 @@ It is necessary for maintainers of this collection to be subscribed to:
|
||||
|
||||
They also should be subscribed to Ansible's [The Bullhorn newsletter](https://docs.ansible.com/ansible/devel/community/communication.html#the-bullhorn).
|
||||
|
||||
## Communication
|
||||
|
||||
We announce important development changes and releases through Ansible's [The Bullhorn newsletter](https://eepurl.com/gZmiEP). If you are a collection developer, be sure you are subscribed.
|
||||
|
||||
Join us in the `#ansible` (general use questions and support), `#ansible-community` (community and collection development questions), and other [IRC channels](https://docs.ansible.com/ansible/devel/community/communication.html#irc-channels) on [Libera.chat](https://libera.chat).
|
||||
|
||||
We take part in the global quarterly [Ansible Contributor Summit](https://github.com/ansible/community/wiki/Contributor-Summit) virtually or in-person. Track [The Bullhorn newsletter](https://eepurl.com/gZmiEP) and join us.
|
||||
|
||||
For more information about communities, meetings and agendas see [Community Wiki](https://github.com/ansible/community/wiki/Community).
|
||||
|
||||
For more information about communication, refer to Ansible's the [Communication guide](https://docs.ansible.com/ansible/devel/community/communication.html).
|
||||
|
||||
## Publishing New Version
|
||||
|
||||
See the [Releasing guidelines](https://github.com/ansible/community-docs/blob/main/releasing_collections.rst) to learn how to release this collection.
|
||||
|
||||
@@ -1541,3 +1541,126 @@ releases:
|
||||
- 8613-redfish_utils-language.yaml
|
||||
- 8614-nsupdate-index-out-of-range.yml
|
||||
release_date: '2024-07-14'
|
||||
8.6.4:
|
||||
changes:
|
||||
bugfixes:
|
||||
- gitlab_runner - fix ``paused`` parameter being ignored (https://github.com/ansible-collections/community.general/pull/8648).
|
||||
- homebrew_cask - fix ``upgrade_all`` returns ``changed`` when nothing upgraded
|
||||
(https://github.com/ansible-collections/community.general/issues/8707, https://github.com/ansible-collections/community.general/pull/8708).
|
||||
- keycloak_user_federation - get cleartext IDP ``clientSecret`` from full
|
||||
realm info to detect changes to it (https://github.com/ansible-collections/community.general/issues/8294,
|
||||
https://github.com/ansible-collections/community.general/pull/8735).
|
||||
- keycloak_user_federation - remove existing user federation mappers if they
|
||||
are not present in the federation configuration and will not be updated
|
||||
(https://github.com/ansible-collections/community.general/issues/7169, https://github.com/ansible-collections/community.general/pull/8695).
|
||||
minor_changes:
|
||||
- passwordstore lookup plugin - add the current user to the lockfile file
|
||||
name to address issues on multi-user systems (https://github.com/ansible-collections/community.general/pull/8689).
|
||||
release_summary: Regular bugfix release.
|
||||
fragments:
|
||||
- 8.6.4.yml
|
||||
- 8648-fix-gitlab-runner-paused.yaml
|
||||
- 8689-passwordstore-lock-naming.yml
|
||||
- 8695-keycloak_user_federation-mapper-removal.yml
|
||||
- 8708-homebrew_cask-fix-upgrade-all.yml
|
||||
- 8735-keycloak_identity_provider-get-cleartext-secret-from-realm-info.yml
|
||||
release_date: '2024-08-12'
|
||||
8.6.5:
|
||||
changes:
|
||||
bugfixes:
|
||||
- gitlab_group_access_token - fix crash in check mode caused by attempted
|
||||
access to a newly created access token (https://github.com/ansible-collections/community.general/pull/8796).
|
||||
- gitlab_project_access_token - fix crash in check mode caused by attempted
|
||||
access to a newly created access token (https://github.com/ansible-collections/community.general/pull/8796).
|
||||
- keycloak_realm_key - fix invalid usage of ``parent_id`` (https://github.com/ansible-collections/community.general/issues/7850,
|
||||
https://github.com/ansible-collections/community.general/pull/8823).
|
||||
- keycloak_user_federation - fix key error when removing mappers during an
|
||||
update and new mappers are specified in the module args (https://github.com/ansible-collections/community.general/pull/8762).
|
||||
- keycloak_user_federation - fix the ``UnboundLocalError`` that occurs when
|
||||
an ID is provided for a user federation mapper (https://github.com/ansible-collections/community.general/pull/8831).
|
||||
- keycloak_user_federation - sort desired and after mapper list by name (analog
|
||||
to before mapper list) to minimize diff and make change detection more accurate
|
||||
(https://github.com/ansible-collections/community.general/pull/8761).
|
||||
- proxmox inventory plugin - fixed a possible error on concatenating responses
|
||||
from proxmox. In case an API call unexpectedly returned an empty result,
|
||||
the inventory failed with a fatal error. Added check for empty response
|
||||
(https://github.com/ansible-collections/community.general/issues/8798, https://github.com/ansible-collections/community.general/pull/8794).
|
||||
release_summary: Regular bugfix release.
|
||||
fragments:
|
||||
- 8.6.5.yml
|
||||
- 8761-keycloak_user_federation-sort-desired-and-after-mappers-by-name.yml
|
||||
- 8762-keycloac_user_federation-fix-key-error-when-updating.yml
|
||||
- 8794-Fixing-possible-concatination-error.yaml
|
||||
- 8796-gitlab-access-token-check-mode.yml
|
||||
- 8823-keycloak-realm-key.yml
|
||||
- 8831-fix-error-when-mapper-id-is-provided.yml
|
||||
release_date: '2024-09-09'
|
||||
8.6.6:
|
||||
changes:
|
||||
bugfixes:
|
||||
- cloudflare_dns - fix changing Cloudflare SRV records (https://github.com/ansible-collections/community.general/issues/8679,
|
||||
https://github.com/ansible-collections/community.general/pull/8948).
|
||||
- dig lookup plugin - fix using only the last nameserver specified (https://github.com/ansible-collections/community.general/pull/8970).
|
||||
- homectl - the module now tries to use ``legacycrypt`` on Python 3.13+ (https://github.com/ansible-collections/community.general/issues/4691,
|
||||
https://github.com/ansible-collections/community.general/pull/8987).
|
||||
- ini_file - pass absolute paths to ``module.atomic_move()`` (https://github.com/ansible/ansible/issues/83950,
|
||||
https://github.com/ansible-collections/community.general/pull/8925).
|
||||
- ipa_hostgroup - fix ``enabled `` and ``disabled`` states (https://github.com/ansible-collections/community.general/issues/8408,
|
||||
https://github.com/ansible-collections/community.general/pull/8900).
|
||||
- java_keystore - pass absolute paths to ``module.atomic_move()`` (https://github.com/ansible/ansible/issues/83950,
|
||||
https://github.com/ansible-collections/community.general/pull/8925).
|
||||
- jenkins_plugin - pass absolute paths to ``module.atomic_move()`` (https://github.com/ansible/ansible/issues/83950,
|
||||
https://github.com/ansible-collections/community.general/pull/8925).
|
||||
- kdeconfig - pass absolute paths to ``module.atomic_move()`` (https://github.com/ansible/ansible/issues/83950,
|
||||
https://github.com/ansible-collections/community.general/pull/8925).
|
||||
- keycloak_realm - fix change detection in check mode by sorting the lists
|
||||
in the realms beforehand (https://github.com/ansible-collections/community.general/pull/8877).
|
||||
- keycloak_user_federation - minimize change detection by setting ``krbPrincipalAttribute``
|
||||
to ``''`` in Keycloak responses if missing (https://github.com/ansible-collections/community.general/pull/8785).
|
||||
- keycloak_user_federation - remove ``lastSync`` parameter from Keycloak responses
|
||||
to minimize diff/changes (https://github.com/ansible-collections/community.general/pull/8812).
|
||||
- one_service - fix service creation after it was deleted with ``unique``
|
||||
parameter (https://github.com/ansible-collections/community.general/issues/3137,
|
||||
https://github.com/ansible-collections/community.general/pull/8887).
|
||||
- pam_limits - pass absolute paths to ``module.atomic_move()`` (https://github.com/ansible/ansible/issues/83950,
|
||||
https://github.com/ansible-collections/community.general/pull/8925).
|
||||
- udm_user - the module now tries to use ``legacycrypt`` on Python 3.13+ (https://github.com/ansible-collections/community.general/issues/4690,
|
||||
https://github.com/ansible-collections/community.general/pull/8987).
|
||||
minor_changes:
|
||||
- redfish_confg - remove ``CapacityBytes`` from required paramaters of the
|
||||
``CreateVolume`` command (https://github.com/ansible-collections/community.general/pull/8956).
|
||||
release_summary: 'Regular bugfix release.
|
||||
|
||||
|
||||
Note that this is the last regular bugfix release of community.general 8.x.y.
|
||||
|
||||
From now on, there will only be maintenance releases with major bugfixes and
|
||||
|
||||
security fixes.'
|
||||
fragments:
|
||||
- 8.6.6.yml
|
||||
- 8679-fix-cloudflare-srv.yml
|
||||
- 8785-keycloak_user_federation-set-krbPrincipalAttribute-to-empty-string-if-missing.yaml
|
||||
- 8812-keycloak-user-federation-remove-lastSync-param-from-kc-responses.yml
|
||||
- 8877-keycloak_realm-sort-lists-before-change-detection.yaml
|
||||
- 8887-fix-one_service-unique.yml
|
||||
- 8900-ipa-hostgroup-fix-states.yml
|
||||
- 8925-atomic.yml
|
||||
- 8956-remove-capacitybytes-from-the-required-parameters_list.yml
|
||||
- 8970-fix-dig-multi-nameservers.yml
|
||||
- 8987-legacycrypt.yml
|
||||
release_date: '2024-10-07'
|
||||
8.6.7:
|
||||
changes:
|
||||
bugfixes:
|
||||
- collection_version lookup plugin - use ``importlib`` directly instead of
|
||||
the deprecated and in ansible-core 2.19 removed ``ansible.module_utils.compat.importlib``
|
||||
(https://github.com/ansible-collections/community.general/pull/9084).
|
||||
- modprobe - fix check mode not being honored for ``persistent`` option (https://github.com/ansible-collections/community.general/issues/9051,
|
||||
https://github.com/ansible-collections/community.general/pull/9052).
|
||||
release_summary: Bugfix release.
|
||||
fragments:
|
||||
- 8.6.7.yml
|
||||
- 9052-modprobe-bugfix.yml
|
||||
- 9084-collection_version-importlib.yml
|
||||
release_date: '2024-11-03'
|
||||
|
||||
@@ -9,6 +9,8 @@ edit_on_github:
|
||||
path_prefix: ''
|
||||
|
||||
extra_links:
|
||||
- description: Ask for help
|
||||
url: https://forum.ansible.com/c/help/6/none
|
||||
- description: Submit a bug report
|
||||
url: https://github.com/ansible-collections/community.general/issues/new?assignees=&labels=&template=bug_report.yml
|
||||
- description: Request a feature
|
||||
@@ -22,10 +24,10 @@ communication:
|
||||
- topic: General usage and support questions
|
||||
network: Libera
|
||||
channel: '#ansible'
|
||||
mailing_lists:
|
||||
- topic: Ansible Project List
|
||||
url: https://groups.google.com/g/ansible-project
|
||||
forums:
|
||||
- topic: Ansible Forum
|
||||
- topic: "Ansible Forum: General usage and support questions"
|
||||
# The following URL directly points to the "Get Help" section
|
||||
url: https://forum.ansible.com/c/help/6/none
|
||||
- topic: "Ansible Forum: Discussions about the collection itself, not for specific modules or plugins"
|
||||
# The following URL directly points to the "community-general" tag
|
||||
url: https://forum.ansible.com/tag/community-general
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
namespace: community
|
||||
name: general
|
||||
version: 8.6.3
|
||||
version: 8.6.7
|
||||
readme: README.md
|
||||
authors:
|
||||
- Ansible (https://github.com/ansible)
|
||||
|
||||
@@ -88,6 +88,10 @@ class ActionModule(ActionBase):
|
||||
max_timeout = self._connection._play_context.timeout
|
||||
module_args = self._task.args
|
||||
|
||||
async_status_args = {}
|
||||
starter_cmd = None
|
||||
confirm_cmd = None
|
||||
|
||||
if module_args.get('state', None) == 'restored':
|
||||
if not wrap_async:
|
||||
if not check_mode:
|
||||
|
||||
@@ -304,6 +304,7 @@ class OpenTelemetrySource(object):
|
||||
status = Status(status_code=StatusCode.OK)
|
||||
if host_data.status != 'included':
|
||||
# Support loops
|
||||
enriched_error_message = None
|
||||
if 'results' in host_data.result._result:
|
||||
if host_data.status == 'failed':
|
||||
message = self.get_error_message_from_results(host_data.result._result['results'], task_data.action)
|
||||
|
||||
@@ -13,6 +13,8 @@ DOCUMENTATION = '''
|
||||
author: Felix Fontein (@felixfontein)
|
||||
description:
|
||||
- Transform a sequence of dictionaries to a dictionary where the dictionaries are indexed by an attribute.
|
||||
- This filter is similar to the Jinja2 C(groupby) filter. Use the Jinja2 C(groupby) filter if you have multiple entries with the same value,
|
||||
or when you need a dictionary with list values, or when you need to use deeply nested attributes.
|
||||
positional: attribute
|
||||
options:
|
||||
_input:
|
||||
|
||||
@@ -329,8 +329,9 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
data = json['data']
|
||||
break
|
||||
else:
|
||||
# /hosts 's 'results' is a list of all hosts, returned is paginated
|
||||
data = data + json['data']
|
||||
if json['data']:
|
||||
# /hosts 's 'results' is a list of all hosts, returned is paginated
|
||||
data = data + json['data']
|
||||
break
|
||||
|
||||
self._cache[self.cache_key][url] = data
|
||||
|
||||
@@ -63,11 +63,11 @@ RETURN = """
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
from importlib import import_module
|
||||
|
||||
import yaml
|
||||
|
||||
from ansible.errors import AnsibleLookupError
|
||||
from ansible.module_utils.compat.importlib import import_module
|
||||
from ansible.plugins.lookup import LookupBase
|
||||
|
||||
|
||||
|
||||
@@ -330,6 +330,7 @@ class LookupModule(LookupBase):
|
||||
myres.use_edns(0, ednsflags=dns.flags.DO, payload=edns_size)
|
||||
|
||||
domains = []
|
||||
nameservers = []
|
||||
qtype = self.get_option('qtype')
|
||||
flat = self.get_option('flat')
|
||||
fail_on_error = self.get_option('fail_on_error')
|
||||
@@ -345,7 +346,6 @@ class LookupModule(LookupBase):
|
||||
if t.startswith('@'): # e.g. "@10.0.1.2,192.0.2.1" is ok.
|
||||
nsset = t[1:].split(',')
|
||||
for ns in nsset:
|
||||
nameservers = []
|
||||
# Check if we have a valid IP address. If so, use that, otherwise
|
||||
# try to resolve name to address using system's resolver. If that
|
||||
# fails we bail out.
|
||||
@@ -358,7 +358,6 @@ class LookupModule(LookupBase):
|
||||
nameservers.append(nsaddr)
|
||||
except Exception as e:
|
||||
raise AnsibleError("dns lookup NS: %s" % to_native(e))
|
||||
myres.nameservers = nameservers
|
||||
continue
|
||||
if '=' in t:
|
||||
try:
|
||||
@@ -397,6 +396,9 @@ class LookupModule(LookupBase):
|
||||
|
||||
# print "--- domain = {0} qtype={1} rdclass={2}".format(domain, qtype, rdclass)
|
||||
|
||||
if len(nameservers) > 0:
|
||||
myres.nameservers = nameservers
|
||||
|
||||
if qtype.upper() == 'PTR':
|
||||
reversed_domains = []
|
||||
for domain in domains:
|
||||
|
||||
@@ -468,7 +468,8 @@ class LookupModule(LookupBase):
|
||||
def opt_lock(self, type):
|
||||
if self.get_option('lock') == type:
|
||||
tmpdir = os.environ.get('TMPDIR', '/tmp')
|
||||
lockfile = os.path.join(tmpdir, '.passwordstore.lock')
|
||||
user = os.environ.get('USER')
|
||||
lockfile = os.path.join(tmpdir, '.{0}.passwordstore.lock'.format(user))
|
||||
with FileLock().lock_file(lockfile, tmpdir, self.lock_timeout):
|
||||
self.locked = type
|
||||
yield
|
||||
|
||||
@@ -104,37 +104,37 @@ EXAMPLES = r"""
|
||||
- name: Generate random string
|
||||
ansible.builtin.debug:
|
||||
var: lookup('community.general.random_string')
|
||||
# Example result: ['DeadBeeF']
|
||||
# Example result: 'DeadBeeF'
|
||||
|
||||
- name: Generate random string with length 12
|
||||
ansible.builtin.debug:
|
||||
var: lookup('community.general.random_string', length=12)
|
||||
# Example result: ['Uan0hUiX5kVG']
|
||||
# Example result: 'Uan0hUiX5kVG'
|
||||
|
||||
- name: Generate base64 encoded random string
|
||||
ansible.builtin.debug:
|
||||
var: lookup('community.general.random_string', base64=True)
|
||||
# Example result: ['NHZ6eWN5Qk0=']
|
||||
# Example result: 'NHZ6eWN5Qk0='
|
||||
|
||||
- name: Generate a random string with 1 lower, 1 upper, 1 number and 1 special char (at least)
|
||||
ansible.builtin.debug:
|
||||
var: lookup('community.general.random_string', min_lower=1, min_upper=1, min_special=1, min_numeric=1)
|
||||
# Example result: ['&Qw2|E[-']
|
||||
# Example result: '&Qw2|E[-'
|
||||
|
||||
- name: Generate a random string with all lower case characters
|
||||
debug:
|
||||
ansible.builtin.debug:
|
||||
var: query('community.general.random_string', upper=false, numbers=false, special=false)
|
||||
# Example result: ['exolxzyz']
|
||||
|
||||
- name: Generate random hexadecimal string
|
||||
debug:
|
||||
ansible.builtin.debug:
|
||||
var: query('community.general.random_string', upper=false, lower=false, override_special=hex_chars, numbers=false)
|
||||
vars:
|
||||
hex_chars: '0123456789ABCDEF'
|
||||
# Example result: ['D2A40737']
|
||||
|
||||
- name: Generate random hexadecimal string with override_all
|
||||
debug:
|
||||
ansible.builtin.debug:
|
||||
var: query('community.general.random_string', override_all=hex_chars)
|
||||
vars:
|
||||
hex_chars: '0123456789ABCDEF'
|
||||
|
||||
@@ -29,6 +29,7 @@ class iLORedfishUtils(RedfishUtils):
|
||||
result['ret'] = True
|
||||
data = response['data']
|
||||
|
||||
current_session = None
|
||||
if 'Oem' in data:
|
||||
if data["Oem"]["Hpe"]["Links"]["MySession"]["@odata.id"]:
|
||||
current_session = data["Oem"]["Hpe"]["Links"]["MySession"]["@odata.id"]
|
||||
|
||||
@@ -3679,8 +3679,8 @@ class RedfishUtils(object):
|
||||
'msg': "Provided Storage Subsystem ID %s does not exist on the server" % storage_subsystem_id}
|
||||
|
||||
# Validate input parameters
|
||||
required_parameters = ['RAIDType', 'Drives', 'CapacityBytes']
|
||||
allowed_parameters = ['DisplayName', 'InitializeMethod', 'MediaSpanCount',
|
||||
required_parameters = ['RAIDType', 'Drives']
|
||||
allowed_parameters = ['CapacityBytes', 'DisplayName', 'InitializeMethod', 'MediaSpanCount',
|
||||
'Name', 'ReadCachePolicy', 'StripSizeBytes', 'VolumeUsage', 'WriteCachePolicy']
|
||||
|
||||
for parameter in required_parameters:
|
||||
|
||||
@@ -192,6 +192,7 @@ def main():
|
||||
rmitab = module.get_bin_path('rmitab')
|
||||
chitab = module.get_bin_path('chitab')
|
||||
rc = 0
|
||||
err = None
|
||||
|
||||
# check if the new entry exists
|
||||
current_entry = check_current_entry(module)
|
||||
|
||||
@@ -74,6 +74,7 @@ options:
|
||||
world:
|
||||
description:
|
||||
- Use a custom world file when checking for explicitly installed packages.
|
||||
The file is used only when a value is provided for O(name), and O(state) is set to V(present) or V(latest).
|
||||
type: str
|
||||
default: /etc/apk/world
|
||||
version_added: 5.4.0
|
||||
|
||||
@@ -102,40 +102,40 @@ EXAMPLES = r'''
|
||||
- name: Create a @home subvolume under the root subvolume
|
||||
community.general.btrfs_subvolume:
|
||||
name: /@home
|
||||
device: /dev/vda2
|
||||
filesystem_device: /dev/vda2
|
||||
|
||||
- name: Remove the @home subvolume if it exists
|
||||
community.general.btrfs_subvolume:
|
||||
name: /@home
|
||||
state: absent
|
||||
device: /dev/vda2
|
||||
filesystem_device: /dev/vda2
|
||||
|
||||
- name: Create a snapshot of the root subvolume named @
|
||||
community.general.btrfs_subvolume:
|
||||
name: /@
|
||||
snapshot_source: /
|
||||
device: /dev/vda2
|
||||
filesystem_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
|
||||
filesystem_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
|
||||
filesystem_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
|
||||
filesystem_device: /dev/vda2
|
||||
|
||||
'''
|
||||
|
||||
|
||||
@@ -716,12 +716,14 @@ class CloudflareAPI(object):
|
||||
"port": params['port'],
|
||||
"weight": params['weight'],
|
||||
"priority": params['priority'],
|
||||
"name": params['record'],
|
||||
"proto": params['proto'],
|
||||
"service": params['service']
|
||||
}
|
||||
|
||||
new_record = {"type": params['type'], "ttl": params['ttl'], 'data': srv_data}
|
||||
new_record = {
|
||||
"type": params['type'],
|
||||
"name": params['service'] + '.' + params['proto'] + '.' + params['record'],
|
||||
"ttl": params['ttl'],
|
||||
'data': srv_data,
|
||||
}
|
||||
search_value = str(params['weight']) + '\t' + str(params['port']) + '\t' + params['value']
|
||||
search_record = params['service'] + '.' + params['proto'] + '.' + params['record']
|
||||
|
||||
|
||||
@@ -183,6 +183,7 @@ class CronVar(object):
|
||||
fileh = open(backup_file, 'w')
|
||||
elif self.cron_file:
|
||||
fileh = open(self.cron_file, 'w')
|
||||
path = None
|
||||
else:
|
||||
filed, path = tempfile.mkstemp(prefix='crontab')
|
||||
fileh = os.fdopen(filed, 'w')
|
||||
|
||||
@@ -313,7 +313,10 @@ def main():
|
||||
module.exit_json(changed=True, msg="Successfully recreated access token", access_token=gitlab_access_token.access_token_object._attrs)
|
||||
else:
|
||||
gitlab_access_token.create_access_token(group, {'name': name, 'scopes': scopes, 'access_level': access_level, 'expires_at': expires_at})
|
||||
module.exit_json(changed=True, msg="Successfully created access token", access_token=gitlab_access_token.access_token_object._attrs)
|
||||
if module.check_mode:
|
||||
module.exit_json(changed=True, msg="Successfully created access token", access_token={})
|
||||
else:
|
||||
module.exit_json(changed=True, msg="Successfully created access token", access_token=gitlab_access_token.access_token_object._attrs)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -311,7 +311,10 @@ def main():
|
||||
module.exit_json(changed=True, msg="Successfully recreated access token", access_token=gitlab_access_token.access_token_object._attrs)
|
||||
else:
|
||||
gitlab_access_token.create_access_token(project, {'name': name, 'scopes': scopes, 'access_level': access_level, 'expires_at': expires_at})
|
||||
module.exit_json(changed=True, msg="Successfully created access token", access_token=gitlab_access_token.access_token_object._attrs)
|
||||
if module.check_mode:
|
||||
module.exit_json(changed=True, msg="Successfully created access token", access_token={})
|
||||
else:
|
||||
module.exit_json(changed=True, msg="Successfully created access token", access_token=gitlab_access_token.access_token_object._attrs)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -33,7 +33,10 @@ author:
|
||||
- Samy Coenen (@SamyCoenen)
|
||||
- Guillaume Martinez (@Lunik)
|
||||
requirements:
|
||||
- python-gitlab >= 1.5.0
|
||||
- python-gitlab >= 1.5.0 for legacy runner registration workflow
|
||||
(runner registration token - U(https://docs.gitlab.com/runner/register/#register-with-a-runner-registration-token-deprecated))
|
||||
- python-gitlab >= 4.0.0 for new runner registration workflow
|
||||
(runner authentication token - U(https://docs.gitlab.com/runner/register/#register-with-a-runner-authentication-token))
|
||||
extends_documentation_fragment:
|
||||
- community.general.auth_basic
|
||||
- community.general.gitlab
|
||||
@@ -466,6 +469,7 @@ def main():
|
||||
state = module.params['state']
|
||||
runner_description = module.params['description']
|
||||
runner_active = module.params['active']
|
||||
runner_paused = module.params['paused']
|
||||
tag_list = module.params['tag_list']
|
||||
run_untagged = module.params['run_untagged']
|
||||
runner_locked = module.params['locked']
|
||||
@@ -500,7 +504,7 @@ def main():
|
||||
module.exit_json(changed=False, msg="Runner deleted or does not exists")
|
||||
|
||||
if state == 'present':
|
||||
if gitlab_runner.create_or_update_runner(runner_description, {
|
||||
runner_values = {
|
||||
"active": runner_active,
|
||||
"tag_list": tag_list,
|
||||
"run_untagged": run_untagged,
|
||||
@@ -510,7 +514,11 @@ def main():
|
||||
"registration_token": registration_token,
|
||||
"group": group,
|
||||
"project": project,
|
||||
}):
|
||||
}
|
||||
if LooseVersion(gitlab_runner._gitlab.version()[0]) >= LooseVersion("14.8.0"):
|
||||
# the paused attribute for runners is available since 14.8
|
||||
runner_values["paused"] = runner_paused
|
||||
if gitlab_runner.create_or_update_runner(runner_description, runner_values):
|
||||
module.exit_json(changed=True, runner=gitlab_runner.runner_object._attrs,
|
||||
msg="Successfully created or updated the runner %s" % runner_description)
|
||||
else:
|
||||
|
||||
@@ -598,7 +598,12 @@ class HomebrewCask(object):
|
||||
rc, out, err = self.module.run_command(cmd)
|
||||
|
||||
if rc == 0:
|
||||
if re.search(r'==> No Casks to upgrade', out.strip(), re.IGNORECASE):
|
||||
# 'brew upgrade --cask' does not output anything if no casks are upgraded
|
||||
if not out.strip():
|
||||
self.message = 'Homebrew casks already upgraded.'
|
||||
|
||||
# handle legacy 'brew cask upgrade'
|
||||
elif re.search(r'==> No Casks to upgrade', out.strip(), re.IGNORECASE):
|
||||
self.message = 'Homebrew casks already upgraded.'
|
||||
|
||||
else:
|
||||
|
||||
@@ -18,11 +18,11 @@ version_added: 4.4.0
|
||||
description:
|
||||
- Manages a user's home directory managed by systemd-homed.
|
||||
notes:
|
||||
- This module does B(not) work with Python 3.13 or newer. It uses the deprecated L(crypt Python module,
|
||||
https://docs.python.org/3.12/library/crypt.html) from the Python standard library, which was removed
|
||||
from Python 3.13.
|
||||
- This module requires the deprecated L(crypt Python module,
|
||||
https://docs.python.org/3.12/library/crypt.html) library which was removed from Python 3.13.
|
||||
For Python 3.13 or newer, you need to install L(legacycrypt, https://pypi.org/project/legacycrypt/).
|
||||
requirements:
|
||||
- Python 3.12 or earlier
|
||||
- legacycrypt (on Python 3.13 or newer)
|
||||
extends_documentation_fragment:
|
||||
- community.general.attributes
|
||||
attributes:
|
||||
@@ -284,6 +284,17 @@ else:
|
||||
HAS_CRYPT = True
|
||||
CRYPT_IMPORT_ERROR = None
|
||||
|
||||
try:
|
||||
import legacycrypt
|
||||
if not HAS_CRYPT:
|
||||
crypt = legacycrypt
|
||||
except ImportError:
|
||||
HAS_LEGACYCRYPT = False
|
||||
LEGACYCRYPT_IMPORT_ERROR = traceback.format_exc()
|
||||
else:
|
||||
HAS_LEGACYCRYPT = True
|
||||
LEGACYCRYPT_IMPORT_ERROR = None
|
||||
|
||||
|
||||
class Homectl(object):
|
||||
'''#TODO DOC STRINGS'''
|
||||
@@ -606,9 +617,9 @@ def main():
|
||||
]
|
||||
)
|
||||
|
||||
if not HAS_CRYPT:
|
||||
if not HAS_CRYPT and not HAS_LEGACYCRYPT:
|
||||
module.fail_json(
|
||||
msg=missing_required_lib('crypt (part of Python 3.13 standard library)'),
|
||||
msg=missing_required_lib('crypt (part of standard library up to Python 3.12) or legacycrypt (PyPI)'),
|
||||
exception=CRYPT_IMPORT_ERROR,
|
||||
)
|
||||
|
||||
|
||||
@@ -569,7 +569,7 @@ def do_ini(module, filename, section=None, section_has_values=None, option=None,
|
||||
module.fail_json(msg="Unable to create temporary file %s", traceback=traceback.format_exc())
|
||||
|
||||
try:
|
||||
module.atomic_move(tmpfile, target_filename)
|
||||
module.atomic_move(tmpfile, os.path.abspath(target_filename))
|
||||
except IOError:
|
||||
module.ansible.fail_json(msg='Unable to move temporary \
|
||||
file %s to %s, IOError' % (tmpfile, target_filename), traceback=traceback.format_exc())
|
||||
|
||||
@@ -57,13 +57,14 @@ options:
|
||||
state:
|
||||
description:
|
||||
- State to ensure.
|
||||
- V("absent") and V("disabled") give the same results.
|
||||
- V("present") and V("enabled") give the same results.
|
||||
default: "present"
|
||||
choices: ["absent", "disabled", "enabled", "present"]
|
||||
type: str
|
||||
extends_documentation_fragment:
|
||||
- community.general.ipa.documentation
|
||||
- community.general.attributes
|
||||
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
@@ -160,7 +161,7 @@ def ensure(module, client):
|
||||
module_hostgroup = get_hostgroup_dict(description=module.params['description'])
|
||||
|
||||
changed = False
|
||||
if state == 'present':
|
||||
if state in ['present', 'enabled']:
|
||||
if not ipa_hostgroup:
|
||||
changed = True
|
||||
if not module.check_mode:
|
||||
|
||||
@@ -459,6 +459,7 @@ def main():
|
||||
if not os.access(b_path, os.R_OK):
|
||||
module.fail_json(msg="Source %s not readable" % path)
|
||||
state_to_restore = read_state(b_path)
|
||||
cmd = None
|
||||
else:
|
||||
cmd = ' '.join(SAVECOMMAND)
|
||||
|
||||
|
||||
@@ -150,13 +150,11 @@ EXAMPLES = '''
|
||||
name: example
|
||||
certificate: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
h19dUZ2co2fI/ibYiwxWk4aeNE6KWvCaTQOMQ8t6Uo2XKhpL/xnjoAgh1uCQN/69
|
||||
MG+34+RhUWzCfdZH7T8/qDxJw2kEPKluaYh7KnMsba+5jHjmtzix5QIDAQABo4IB
|
||||
h19dUZ2co2f...
|
||||
-----END CERTIFICATE-----
|
||||
private_key: |
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
DBVFTEVDVFJJQ0lURSBERSBGUkFOQ0UxFzAVBgNVBAsMDjAwMDIgNTUyMDgxMzE3
|
||||
GLlDNMw/uHyME7gHFsqJA7O11VY6O5WQ4IDP3m/s5ZV6s+Nn6Lerz17VZ99
|
||||
DBVFTEVDVFJ...
|
||||
-----END RSA PRIVATE KEY-----
|
||||
password: changeit
|
||||
dest: /etc/security/keystore.jks
|
||||
@@ -472,7 +470,7 @@ class JavaKeystore:
|
||||
|
||||
if self.keystore_type == 'pkcs12':
|
||||
# Preserve properties of the destination file, if any.
|
||||
self.module.atomic_move(keystore_p12_path, self.keystore_path)
|
||||
self.module.atomic_move(os.path.abspath(keystore_p12_path), os.path.abspath(self.keystore_path))
|
||||
self.update_permissions()
|
||||
self.result['changed'] = True
|
||||
return self.result
|
||||
|
||||
@@ -685,7 +685,7 @@ class JenkinsPlugin(object):
|
||||
|
||||
# Move the updates file to the right place if we could read it
|
||||
if tmp_updates_file != updates_file:
|
||||
self.module.atomic_move(tmp_updates_file, updates_file)
|
||||
self.module.atomic_move(os.path.abspath(tmp_updates_file), os.path.abspath(updates_file))
|
||||
|
||||
# Check if we have the plugin data available
|
||||
if not data.get('plugins', {}).get(self.params['name']):
|
||||
@@ -718,7 +718,7 @@ class JenkinsPlugin(object):
|
||||
details=to_native(e))
|
||||
|
||||
# Move the file onto the right place
|
||||
self.module.atomic_move(tmp_f, f)
|
||||
self.module.atomic_move(os.path.abspath(tmp_f), os.path.abspath(f))
|
||||
|
||||
def uninstall(self):
|
||||
changed = False
|
||||
|
||||
@@ -214,7 +214,7 @@ def run_module(module, tmpdir, kwriteconfig):
|
||||
if module.params['backup'] and os.path.exists(b_path):
|
||||
result['backup_file'] = module.backup_local(result['path'])
|
||||
try:
|
||||
module.atomic_move(b_tmpfile, b_path)
|
||||
module.atomic_move(b_tmpfile, os.path.abspath(b_path))
|
||||
except IOError:
|
||||
module.ansible.fail_json(msg='Unable to move temporary file %s to %s, IOError' % (tmpfile, result['path']), traceback=traceback.format_exc())
|
||||
|
||||
|
||||
@@ -445,6 +445,15 @@ def get_identity_provider_with_mappers(kc, alias, realm):
|
||||
idp = kc.get_identity_provider(alias, realm)
|
||||
if idp is not None:
|
||||
idp['mappers'] = sorted(kc.get_identity_provider_mappers(alias, realm), key=lambda x: x.get('name'))
|
||||
# clientSecret returned by API when using `get_identity_provider(alias, realm)` is always **********
|
||||
# to detect changes to the secret, we get the actual cleartext secret from the full realm info
|
||||
if 'config' in idp:
|
||||
if 'clientSecret' in idp['config']:
|
||||
for idp_from_realm in kc.get_realm_by_id(realm).get('identityProviders', []):
|
||||
if idp_from_realm['internalId'] == idp['internalId']:
|
||||
cleartext_secret = idp_from_realm.get('config', {}).get('clientSecret')
|
||||
if cleartext_secret:
|
||||
idp['config']['clientSecret'] = cleartext_secret
|
||||
if idp is None:
|
||||
idp = {}
|
||||
return idp
|
||||
|
||||
@@ -803,7 +803,7 @@ def main():
|
||||
if module._diff:
|
||||
result['diff'] = dict(before=sanitize_cr(before_norm),
|
||||
after=sanitize_cr(desired_norm))
|
||||
result['changed'] = (before_realm != desired_realm)
|
||||
result['changed'] = (before_norm != desired_norm)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ options:
|
||||
type: bool
|
||||
parent_id:
|
||||
description:
|
||||
- The parent_id of the realm key. In practice the ID (name) of the realm.
|
||||
- The parent_id of the realm key. In practice the name of the realm.
|
||||
type: str
|
||||
required: true
|
||||
provider_id:
|
||||
@@ -300,7 +300,7 @@ def main():
|
||||
|
||||
kc = KeycloakAPI(module, connection_header)
|
||||
|
||||
params_to_ignore = list(keycloak_argument_spec().keys()) + ["state", "force"]
|
||||
params_to_ignore = list(keycloak_argument_spec().keys()) + ["state", "force", "parent_id"]
|
||||
|
||||
# Filter and map the parameters names that apply to the role
|
||||
component_params = [x for x in module.params
|
||||
@@ -371,7 +371,7 @@ def main():
|
||||
parent_id = module.params.get('parent_id')
|
||||
|
||||
# Get a list of all Keycloak components that are of keyprovider type.
|
||||
realm_keys = kc.get_components(urlencode(dict(type=provider_type, parent=parent_id)), parent_id)
|
||||
realm_keys = kc.get_components(urlencode(dict(type=provider_type)), parent_id)
|
||||
|
||||
# If this component is present get its key ID. Confusingly the key ID is
|
||||
# also known as the Provider ID.
|
||||
|
||||
@@ -713,15 +713,23 @@ from ansible.module_utils.six.moves.urllib.parse import urlencode
|
||||
from copy import deepcopy
|
||||
|
||||
|
||||
def normalize_kc_comp(comp):
|
||||
if 'config' in comp:
|
||||
# kc completely removes the parameter `krbPrincipalAttribute` if it is set to `''`; the unset kc parameter is equivalent to `''`;
|
||||
# to make change detection and diff more accurate we set it again in the kc responses
|
||||
if 'krbPrincipalAttribute' not in comp['config']:
|
||||
comp['config']['krbPrincipalAttribute'] = ['']
|
||||
|
||||
# kc stores a timestamp of the last sync in `lastSync` to time the periodic sync, it is removed to minimize diff/changes
|
||||
comp['config'].pop('lastSync', None)
|
||||
|
||||
|
||||
def sanitize(comp):
|
||||
compcopy = deepcopy(comp)
|
||||
if 'config' in compcopy:
|
||||
compcopy['config'] = dict((k, v[0]) for k, v in compcopy['config'].items())
|
||||
if 'bindCredential' in compcopy['config']:
|
||||
compcopy['config']['bindCredential'] = '**********'
|
||||
# an empty string is valid for krbPrincipalAttribute but is filtered out in diff
|
||||
if 'krbPrincipalAttribute' not in compcopy['config']:
|
||||
compcopy['config']['krbPrincipalAttribute'] = ''
|
||||
if 'mappers' in compcopy:
|
||||
for mapper in compcopy['mappers']:
|
||||
if 'config' in mapper:
|
||||
@@ -868,7 +876,9 @@ def main():
|
||||
|
||||
# if user federation exists, get associated mappers
|
||||
if cid is not None and before_comp:
|
||||
before_comp['mappers'] = sorted(kc.get_components(urlencode(dict(parent=cid)), realm), key=lambda x: x.get('name'))
|
||||
before_comp['mappers'] = sorted(kc.get_components(urlencode(dict(parent=cid)), realm), key=lambda x: x.get('name') or '')
|
||||
|
||||
normalize_kc_comp(before_comp)
|
||||
|
||||
# Build a proposed changeset from parameters given to this module
|
||||
changeset = {}
|
||||
@@ -892,11 +902,11 @@ def main():
|
||||
if cid is None:
|
||||
old_mapper = {}
|
||||
elif change.get('id') is not None:
|
||||
old_mapper = kc.get_component(change['id'], realm)
|
||||
old_mapper = next((before_mapper for before_mapper in before_comp.get('mappers', []) if before_mapper["id"] == change['id']), None)
|
||||
if old_mapper is None:
|
||||
old_mapper = {}
|
||||
else:
|
||||
found = kc.get_components(urlencode(dict(parent=cid, name=change['name'])), realm)
|
||||
found = [before_mapper for before_mapper in before_comp.get('mappers', []) if before_mapper['name'] == change['name']]
|
||||
if len(found) > 1:
|
||||
module.fail_json(msg='Found multiple mappers with name `{name}`. Cannot continue.'.format(name=change['name']))
|
||||
if len(found) == 1:
|
||||
@@ -905,10 +915,11 @@ def main():
|
||||
old_mapper = {}
|
||||
new_mapper = old_mapper.copy()
|
||||
new_mapper.update(change)
|
||||
if new_mapper != old_mapper:
|
||||
if changeset.get('mappers') is None:
|
||||
changeset['mappers'] = list()
|
||||
changeset['mappers'].append(new_mapper)
|
||||
# changeset contains all desired mappers: those existing, to update or to create
|
||||
if changeset.get('mappers') is None:
|
||||
changeset['mappers'] = list()
|
||||
changeset['mappers'].append(new_mapper)
|
||||
changeset['mappers'] = sorted(changeset['mappers'], key=lambda x: x.get('name') or '')
|
||||
|
||||
# Prepare the desired values using the existing values (non-existence results in a dict that is save to use as a basis)
|
||||
desired_comp = before_comp.copy()
|
||||
@@ -931,42 +942,52 @@ def main():
|
||||
# Process a creation
|
||||
result['changed'] = True
|
||||
|
||||
if module._diff:
|
||||
result['diff'] = dict(before='', after=sanitize(desired_comp))
|
||||
|
||||
if module.check_mode:
|
||||
if module._diff:
|
||||
result['diff'] = dict(before='', after=sanitize(desired_comp))
|
||||
module.exit_json(**result)
|
||||
|
||||
# create it
|
||||
desired_comp = desired_comp.copy()
|
||||
updated_mappers = desired_comp.pop('mappers', [])
|
||||
desired_mappers = desired_comp.pop('mappers', [])
|
||||
after_comp = kc.create_component(desired_comp, realm)
|
||||
|
||||
cid = after_comp['id']
|
||||
updated_mappers = []
|
||||
# when creating a user federation, keycloak automatically creates default mappers
|
||||
default_mappers = kc.get_components(urlencode(dict(parent=cid)), realm)
|
||||
|
||||
for mapper in updated_mappers:
|
||||
found = kc.get_components(urlencode(dict(parent=cid, name=mapper['name'])), realm)
|
||||
# create new mappers or update existing default mappers
|
||||
for desired_mapper in desired_mappers:
|
||||
found = [default_mapper for default_mapper in default_mappers if default_mapper['name'] == desired_mapper['name']]
|
||||
if len(found) > 1:
|
||||
module.fail_json(msg='Found multiple mappers with name `{name}`. Cannot continue.'.format(name=mapper['name']))
|
||||
module.fail_json(msg='Found multiple mappers with name `{name}`. Cannot continue.'.format(name=desired_mapper['name']))
|
||||
if len(found) == 1:
|
||||
old_mapper = found[0]
|
||||
else:
|
||||
old_mapper = {}
|
||||
|
||||
new_mapper = old_mapper.copy()
|
||||
new_mapper.update(mapper)
|
||||
new_mapper.update(desired_mapper)
|
||||
|
||||
if new_mapper.get('id') is not None:
|
||||
kc.update_component(new_mapper, realm)
|
||||
updated_mappers.append(new_mapper)
|
||||
else:
|
||||
if new_mapper.get('parentId') is None:
|
||||
new_mapper['parentId'] = after_comp['id']
|
||||
mapper = kc.create_component(new_mapper, realm)
|
||||
new_mapper['parentId'] = cid
|
||||
updated_mappers.append(kc.create_component(new_mapper, realm))
|
||||
|
||||
after_comp['mappers'] = updated_mappers
|
||||
# we remove all unwanted default mappers
|
||||
# we use ids so we dont accidently remove one of the previously updated default mapper
|
||||
for default_mapper in default_mappers:
|
||||
if not default_mapper['id'] in [x['id'] for x in updated_mappers]:
|
||||
kc.delete_component(default_mapper['id'], realm)
|
||||
|
||||
after_comp['mappers'] = kc.get_components(urlencode(dict(parent=cid)), realm)
|
||||
normalize_kc_comp(after_comp)
|
||||
if module._diff:
|
||||
result['diff'] = dict(before='', after=sanitize(after_comp))
|
||||
result['end_state'] = sanitize(after_comp)
|
||||
|
||||
result['msg'] = "User federation {id} has been created".format(id=after_comp['id'])
|
||||
result['msg'] = "User federation {id} has been created".format(id=cid)
|
||||
module.exit_json(**result)
|
||||
|
||||
else:
|
||||
@@ -990,22 +1011,33 @@ def main():
|
||||
module.exit_json(**result)
|
||||
|
||||
# do the update
|
||||
desired_comp = desired_comp.copy()
|
||||
updated_mappers = desired_comp.pop('mappers', [])
|
||||
desired_mappers = desired_comp.pop('mappers', [])
|
||||
kc.update_component(desired_comp, realm)
|
||||
after_comp = kc.get_component(cid, realm)
|
||||
|
||||
for mapper in updated_mappers:
|
||||
for before_mapper in before_comp.get('mappers', []):
|
||||
# remove unwanted existing mappers that will not be updated
|
||||
if not before_mapper['id'] in [x['id'] for x in desired_mappers if 'id' in x]:
|
||||
kc.delete_component(before_mapper['id'], realm)
|
||||
|
||||
for mapper in desired_mappers:
|
||||
if mapper in before_comp.get('mappers', []):
|
||||
continue
|
||||
if mapper.get('id') is not None:
|
||||
kc.update_component(mapper, realm)
|
||||
else:
|
||||
if mapper.get('parentId') is None:
|
||||
mapper['parentId'] = desired_comp['id']
|
||||
mapper = kc.create_component(mapper, realm)
|
||||
|
||||
after_comp['mappers'] = updated_mappers
|
||||
result['end_state'] = sanitize(after_comp)
|
||||
kc.create_component(mapper, realm)
|
||||
|
||||
after_comp = kc.get_component(cid, realm)
|
||||
after_comp['mappers'] = sorted(kc.get_components(urlencode(dict(parent=cid)), realm), key=lambda x: x.get('name') or '')
|
||||
normalize_kc_comp(after_comp)
|
||||
after_comp_sanitized = sanitize(after_comp)
|
||||
before_comp_sanitized = sanitize(before_comp)
|
||||
result['end_state'] = after_comp_sanitized
|
||||
if module._diff:
|
||||
result['diff'] = dict(before=before_comp_sanitized, after=after_comp_sanitized)
|
||||
result['changed'] = before_comp_sanitized != after_comp_sanitized
|
||||
result['msg'] = "User federation {id} has been updated".format(id=cid)
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
@@ -304,22 +304,7 @@ EXAMPLES = '''
|
||||
security_protocol: 'ssl-with-validation-custom-ca'
|
||||
certificate_authority: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
FAKECERTsdKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAmMSQwIgYDVQQDDBtvcGVu
|
||||
c2hpZnQtc2lnbmVyQDE1MDMzMjAxMTkwHhcNMTcwODIxMTI1NTE5WhcNMjIwODIw
|
||||
MTI1NTIwWjAmMSQwIgYDVQQDDBtvcGVuc2hpZnQtc2lnbmVyQDE1MDMzMjAxMTkw
|
||||
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDUDnL2tQ2xf/zO7F7hmZ4S
|
||||
ZuwKENdI4IYuWSxye4i3hPhKg6eKPzGzmDNWkIMDOrDAj1EgVSNPtPwsOL8OWvJm
|
||||
AaTjr070D7ZGWWnrrDrWEClBx9Rx/6JAM38RT8Pu7c1hXBm0J81KufSLLYiZ/gOw
|
||||
Znks5v5RUSGcAXvLkBJeATbsbh6fKX0RgQ3fFTvqQaE/r8LxcTN1uehPX1g5AaRa
|
||||
z/SNDHaFtQlE3XcqAAukyMn4N5kdNcuwF3GlQ+tJnJv8SstPkfQcZbTMUQ7I2KpJ
|
||||
ajXnMxmBhV5fCN4rb0QUNCrk2/B+EUMBY4MnxIakqNxnN1kvgI7FBbFgrHUe6QvJ
|
||||
AgMBAAGjIzAhMA4GA1UdDwEB/wQEAwICpDAPBgNVHRMBAf8EBTADAQH/MA0GCSqG
|
||||
SIb3DQEBCwUAA4IBAQAYRV57LUsqznSLZHA77o9+0fQetIE115DYP7wea42PODJI
|
||||
QJ+JETEfoCr0+YOMAbVmznP9GH5cMTKEWHExcIpbMBU7nMZp6A3htcJgF2fgPzOA
|
||||
aTUtzkuVCSrV//mbbYVxoFOc6sR3Br0wBs5+5iz3dBSt7xmgpMzZvqsQl655i051
|
||||
gGSTIY3z5EJmBZBjwuTjal9mMoPGA4eoTPqlITJDHQ2bdCV2oDbc7zqupGrUfZFA
|
||||
qzgieEyGzdCSRwjr1/PibA3bpwHyhD9CGD0PRVVTLhw6h6L5kuN1jA20OfzWxf/o
|
||||
XUsdmRaWiF+l4s6Dcd56SuRp5SGNa2+vP9Of/FX5
|
||||
FAKECERTsdKgAwI...
|
||||
-----END CERTIFICATE-----
|
||||
metrics:
|
||||
auth_key: 'topSecret'
|
||||
@@ -330,22 +315,7 @@ EXAMPLES = '''
|
||||
security_protocol: 'ssl-with-validation-custom-ca'
|
||||
certificate_authority: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
FAKECERTsdKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAmMSQwIgYDVQQDDBtvcGVu
|
||||
c2hpZnQtc2lnbmVyQDE1MDMzMjAxMTkwHhcNMTcwODIxMTI1NTE5WhcNMjIwODIw
|
||||
MTI1NTIwWjAmMSQwIgYDVQQDDBtvcGVuc2hpZnQtc2lnbmVyQDE1MDMzMjAxMTkw
|
||||
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDUDnL2tQ2xf/zO7F7hmZ4S
|
||||
ZuwKENdI4IYuWSxye4i3hPhKg6eKPzGzmDNWkIMDOrDAj1EgVSNPtPwsOL8OWvJm
|
||||
AaTjr070D7ZGWWnrrDrWEClBx9Rx/6JAM38RT8Pu7c1hXBm0J81KufSLLYiZ/gOw
|
||||
Znks5v5RUSGcAXvLkBJeATbsbh6fKX0RgQ3fFTvqQaE/r8LxcTN1uehPX1g5AaRa
|
||||
z/SNDHaFtQlE3XcqAAukyMn4N5kdNcuwF3GlQ+tJnJv8SstPkfQcZbTMUQ7I2KpJ
|
||||
ajXnMxmBhV5fCN4rb0QUNCrk2/B+EUMBY4MnxIakqNxnN1kvgI7FBbFgrHUe6QvJ
|
||||
AgMBAAGjIzAhMA4GA1UdDwEB/wQEAwICpDAPBgNVHRMBAf8EBTADAQH/MA0GCSqG
|
||||
SIb3DQEBCwUAA4IBAQAYRV57LUsqznSLZHA77o9+0fQetIE115DYP7wea42PODJI
|
||||
QJ+JETEfoCr0+YOMAbVmznP9GH5cMTKEWHExcIpbMBU7nMZp6A3htcJgF2fgPzOA
|
||||
aTUtzkuVCSrV//mbbYVxoFOc6sR3Br0wBs5+5iz3dBSt7xmgpMzZvqsQl655i051
|
||||
gGSTIY3z5EJmBZBjwuTjal9mMoPGA4eoTPqlITJDHQ2bdCV2oDbc7zqupGrUfZFA
|
||||
qzgieEyGzdCSRwjr1/PibA3bpwHyhD9CGD0PRVVTLhw6h6L5kuN1jA20OfzWxf/o
|
||||
XUsdmRaWiF+l4s6Dcd56SuRp5SGNa2+vP9Of/FX5
|
||||
FAKECERTsdKgAwI...
|
||||
-----END CERTIFICATE-----
|
||||
manageiq_connection:
|
||||
url: 'https://127.0.0.1:80'
|
||||
@@ -367,22 +337,7 @@ EXAMPLES = '''
|
||||
security_protocol: 'ssl-with-validation-custom-ca'
|
||||
certificate_authority: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
FAKECERTsdKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAmMSQwIgYDVQQDDBtvcGVu
|
||||
c2hpZnQtc2lnbmVyQDE1MDMzMjAxMTkwHhcNMTcwODIxMTI1NTE5WhcNMjIwODIw
|
||||
MTI1NTIwWjAmMSQwIgYDVQQDDBtvcGVuc2hpZnQtc2lnbmVyQDE1MDMzMjAxMTkw
|
||||
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDUDnL2tQ2xf/zO7F7hmZ4S
|
||||
ZuwKENdI4IYuWSxye4i3hPhKg6eKPzGzmDNWkIMDOrDAj1EgVSNPtPwsOL8OWvJm
|
||||
AaTjr070D7ZGWWnrrDrWEClBx9Rx/6JAM38RT8Pu7c1hXBm0J81KufSLLYiZ/gOw
|
||||
Znks5v5RUSGcAXvLkBJeATbsbh6fKX0RgQ3fFTvqQaE/r8LxcTN1uehPX1g5AaRa
|
||||
z/SNDHaFtQlE3XcqAAukyMn4N5kdNcuwF3GlQ+tJnJv8SstPkfQcZbTMUQ7I2KpJ
|
||||
ajXnMxmBhV5fCN4rb0QUNCrk2/B+EUMBY4MnxIakqNxnN1kvgI7FBbFgrHUe6QvJ
|
||||
AgMBAAGjIzAhMA4GA1UdDwEB/wQEAwICpDAPBgNVHRMBAf8EBTADAQH/MA0GCSqG
|
||||
SIb3DQEBCwUAA4IBAQAYRV57LUsqznSLZHA77o9+0fQetIE115DYP7wea42PODJI
|
||||
QJ+JETEfoCr0+YOMAbVmznP9GH5cMTKEWHExcIpbMBU7nMZp6A3htcJgF2fgPzOA
|
||||
aTUtzkuVCSrV//mbbYVxoFOc6sR3Br0wBs5+5iz3dBSt7xmgpMzZvqsQl655i051
|
||||
gGSTIY3z5EJmBZBjwuTjal9mMoPGA4eoTPqlITJDHQ2bdCV2oDbc7zqupGrUfZFA
|
||||
qzgieEyGzdCSRwjr1/PibA3bpwHyhD9CGD0PRVVTLhw6h6L5kuN1jA20OfzWxf/o
|
||||
XUsdmRaWiF+l4s6Dcd56SuRp5SGNa2+vP9Of/FX5
|
||||
FAKECERTsdKgAwI...
|
||||
-----END CERTIFICATE-----
|
||||
metrics:
|
||||
auth_key: 'topSecret'
|
||||
@@ -392,22 +347,7 @@ EXAMPLES = '''
|
||||
security_protocol: 'ssl-with-validation-custom-ca'
|
||||
certificate_authority: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
FAKECERTsdKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAmMSQwIgYDVQQDDBtvcGVu
|
||||
c2hpZnQtc2lnbmVyQDE1MDMzMjAxMTkwHhcNMTcwODIxMTI1NTE5WhcNMjIwODIw
|
||||
MTI1NTIwWjAmMSQwIgYDVQQDDBtvcGVuc2hpZnQtc2lnbmVyQDE1MDMzMjAxMTkw
|
||||
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDUDnL2tQ2xf/zO7F7hmZ4S
|
||||
ZuwKENdI4IYuWSxye4i3hPhKg6eKPzGzmDNWkIMDOrDAj1EgVSNPtPwsOL8OWvJm
|
||||
AaTjr070D7ZGWWnrrDrWEClBx9Rx/6JAM38RT8Pu7c1hXBm0J81KufSLLYiZ/gOw
|
||||
Znks5v5RUSGcAXvLkBJeATbsbh6fKX0RgQ3fFTvqQaE/r8LxcTN1uehPX1g5AaRa
|
||||
z/SNDHaFtQlE3XcqAAukyMn4N5kdNcuwF3GlQ+tJnJv8SstPkfQcZbTMUQ7I2KpJ
|
||||
ajXnMxmBhV5fCN4rb0QUNCrk2/B+EUMBY4MnxIakqNxnN1kvgI7FBbFgrHUe6QvJ
|
||||
AgMBAAGjIzAhMA4GA1UdDwEB/wQEAwICpDAPBgNVHRMBAf8EBTADAQH/MA0GCSqG
|
||||
SIb3DQEBCwUAA4IBAQAYRV57LUsqznSLZHA77o9+0fQetIE115DYP7wea42PODJI
|
||||
QJ+JETEfoCr0+YOMAbVmznP9GH5cMTKEWHExcIpbMBU7nMZp6A3htcJgF2fgPzOA
|
||||
aTUtzkuVCSrV//mbbYVxoFOc6sR3Br0wBs5+5iz3dBSt7xmgpMzZvqsQl655i051
|
||||
gGSTIY3z5EJmBZBjwuTjal9mMoPGA4eoTPqlITJDHQ2bdCV2oDbc7zqupGrUfZFA
|
||||
qzgieEyGzdCSRwjr1/PibA3bpwHyhD9CGD0PRVVTLhw6h6L5kuN1jA20OfzWxf/o
|
||||
XUsdmRaWiF+l4s6Dcd56SuRp5SGNa2+vP9Of/FX5
|
||||
FAKECERTsdKgAwI...
|
||||
-----END CERTIFICATE-----
|
||||
manageiq_connection:
|
||||
url: 'https://127.0.0.1'
|
||||
@@ -455,22 +395,7 @@ EXAMPLES = '''
|
||||
validate_certs: true
|
||||
certificate_authority: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
FAKECERTsdKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAmMSQwIgYDVQQDDBtvcGVu
|
||||
c2hpZnQtc2lnbmVyQDE1MDMzMjAxMTkwHhcNMTcwODIxMTI1NTE5WhcNMjIwODIw
|
||||
MTI1NTIwWjAmMSQwIgYDVQQDDBtvcGVuc2hpZnQtc2lnbmVyQDE1MDMzMjAxMTkw
|
||||
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDUDnL2tQ2xf/zO7F7hmZ4S
|
||||
ZuwKENdI4IYuWSxye4i3hPhKg6eKPzGzmDNWkIMDOrDAj1EgVSNPtPwsOL8OWvJm
|
||||
AaTjr070D7ZGWWnrrDrWEClBx9Rx/6JAM38RT8Pu7c1hXBm0J81KufSLLYiZ/gOw
|
||||
Znks5v5RUSGcAXvLkBJeATbsbh6fKX0RgQ3fFTvqQaE/r8LxcTN1uehPX1g5AaRa
|
||||
z/SNDHaFtQlE3XcqAAukyMn4N5kdNcuwF3GlQ+tJnJv8SstPkfQcZbTMUQ7I2KpJ
|
||||
ajXnMxmBhV5fCN4rb0QUNCrk2/B+EUMBY4MnxIakqNxnN1kvgI7FBbFgrHUe6QvJ
|
||||
AgMBAAGjIzAhMA4GA1UdDwEB/wQEAwICpDAPBgNVHRMBAf8EBTADAQH/MA0GCSqG
|
||||
SIb3DQEBCwUAA4IBAQAYRV57LUsqznSLZHA77o9+0fQetIE115DYP7wea42PODJI
|
||||
QJ+JETEfoCr0+YOMAbVmznP9GH5cMTKEWHExcIpbMBU7nMZp6A3htcJgF2fgPzOA
|
||||
aTUtzkuVCSrV//mbbYVxoFOc6sR3Br0wBs5+5iz3dBSt7xmgpMzZvqsQl655i051
|
||||
gGSTIY3z5EJmBZBjwuTjal9mMoPGA4eoTPqlITJDHQ2bdCV2oDbc7zqupGrUfZFA
|
||||
qzgieEyGzdCSRwjr1/PibA3bpwHyhD9CGD0PRVVTLhw6h6L5kuN1jA20OfzWxf/o
|
||||
XUsdmRaWiF+l4s6Dcd56SuRp5SGNa2+vP9Of/FX5
|
||||
FAKECERTsdKgAwI...
|
||||
-----END CERTIFICATE-----
|
||||
metrics:
|
||||
hostname: 'metrics.example.com'
|
||||
@@ -480,22 +405,7 @@ EXAMPLES = '''
|
||||
validate_certs: true
|
||||
certificate_authority: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
FAKECERTsdKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAmMSQwIgYDVQQDDBtvcGVu
|
||||
c2hpZnQtc2lnbmVyQDE1MDMzMjAxMTkwHhcNMTcwODIxMTI1NTE5WhcNMjIwODIw
|
||||
MTI1NTIwWjAmMSQwIgYDVQQDDBtvcGVuc2hpZnQtc2lnbmVyQDE1MDMzMjAxMTkw
|
||||
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDUDnL2tQ2xf/zO7F7hmZ4S
|
||||
ZuwKENdI4IYuWSxye4i3hPhKg6eKPzGzmDNWkIMDOrDAj1EgVSNPtPwsOL8OWvJm
|
||||
AaTjr070D7ZGWWnrrDrWEClBx9Rx/6JAM38RT8Pu7c1hXBm0J81KufSLLYiZ/gOw
|
||||
Znks5v5RUSGcAXvLkBJeATbsbh6fKX0RgQ3fFTvqQaE/r8LxcTN1uehPX1g5AaRa
|
||||
z/SNDHaFtQlE3XcqAAukyMn4N5kdNcuwF3GlQ+tJnJv8SstPkfQcZbTMUQ7I2KpJ
|
||||
ajXnMxmBhV5fCN4rb0QUNCrk2/B+EUMBY4MnxIakqNxnN1kvgI7FBbFgrHUe6QvJ
|
||||
AgMBAAGjIzAhMA4GA1UdDwEB/wQEAwICpDAPBgNVHRMBAf8EBTADAQH/MA0GCSqG
|
||||
SIb3DQEBCwUAA4IBAQAYRV57LUsqznSLZHA77o9+0fQetIE115DYP7wea42PODJI
|
||||
QJ+JETEfoCr0+YOMAbVmznP9GH5cMTKEWHExcIpbMBU7nMZp6A3htcJgF2fgPzOA
|
||||
aTUtzkuVCSrV//mbbYVxoFOc6sR3Br0wBs5+5iz3dBSt7xmgpMzZvqsQl655i051
|
||||
gGSTIY3z5EJmBZBjwuTjal9mMoPGA4eoTPqlITJDHQ2bdCV2oDbc7zqupGrUfZFA
|
||||
qzgieEyGzdCSRwjr1/PibA3bpwHyhD9CGD0PRVVTLhw6h6L5kuN1jA20OfzWxf/o
|
||||
XUsdmRaWiF+l4s6Dcd56SuRp5SGNa2+vP9Of/FX5
|
||||
FAKECERTsdKgAwI...
|
||||
-----END CERTIFICATE-----
|
||||
manageiq_connection:
|
||||
url: 'https://127.0.0.1'
|
||||
@@ -551,22 +461,7 @@ EXAMPLES = '''
|
||||
validate_certs: 'true'
|
||||
certificate_authority: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
FAKECERTsdKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAmMSQwIgYDVQQDDBtvcGVu
|
||||
c2hpZnQtc2lnbmVyQDE1MDMzMjAxMTkwHhcNMTcwODIxMTI1NTE5WhcNMjIwODIw
|
||||
MTI1NTIwWjAmMSQwIgYDVQQDDBtvcGVuc2hpZnQtc2lnbmVyQDE1MDMzMjAxMTkw
|
||||
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDUDnL2tQ2xf/zO7F7hmZ4S
|
||||
ZuwKENdI4IYuWSxye4i3hPhKg6eKPzGzmDNWkIMDOrDAj1EgVSNPtPwsOL8OWvJm
|
||||
AaTjr070D7ZGWWnrrDrWEClBx9Rx/6JAM38RT8Pu7c1hXBm0J81KufSLLYiZ/gOw
|
||||
Znks5v5RUSGcAXvLkBJeATbsbh6fKX0RgQ3fFTvqQaE/r8LxcTN1uehPX1g5AaRa
|
||||
z/SNDHaFtQlE3XcqAAukyMn4N5kdNcuwF3GlQ+tJnJv8SstPkfQcZbTMUQ7I2KpJ
|
||||
ajXnMxmBhV5fCN4rb0QUNCrk2/B+EUMBY4MnxIakqNxnN1kvgI7FBbFgrHUe6QvJ
|
||||
AgMBAAGjIzAhMA4GA1UdDwEB/wQEAwICpDAPBgNVHRMBAf8EBTADAQH/MA0GCSqG
|
||||
SIb3DQEBCwUAA4IBAQAYRV57LUsqznSLZHA77o9+0fQetIE115DYP7wea42PODJI
|
||||
QJ+JETEfoCr0+YOMAbVmznP9GH5cMTKEWHExcIpbMBU7nMZp6A3htcJgF2fgPzOA
|
||||
aTUtzkuVCSrV//mbbYVxoFOc6sR3Br0wBs5+5iz3dBSt7xmgpMzZvqsQl655i051
|
||||
gGSTIY3z5EJmBZBjwuTjal9mMoPGA4eoTPqlITJDHQ2bdCV2oDbc7zqupGrUfZFA
|
||||
qzgieEyGzdCSRwjr1/PibA3bpwHyhD9CGD0PRVVTLhw6h6L5kuN1jA20OfzWxf/o
|
||||
XUsdmRaWiF+l4s6Dcd56SuRp5SGNa2+vP9Of/FX5
|
||||
FAKECERTsdKgAwI...
|
||||
-----END CERTIFICATE-----
|
||||
ssh_keypair:
|
||||
hostname: director.example.com
|
||||
@@ -590,22 +485,7 @@ EXAMPLES = '''
|
||||
validate_certs: 'true'
|
||||
certificate_authority: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
FAKECERTsdKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAmMSQwIgYDVQQDDBtvcGVu
|
||||
c2hpZnQtc2lnbmVyQDE1MDMzMjAxMTkwHhcNMTcwODIxMTI1NTE5WhcNMjIwODIw
|
||||
MTI1NTIwWjAmMSQwIgYDVQQDDBtvcGVuc2hpZnQtc2lnbmVyQDE1MDMzMjAxMTkw
|
||||
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDUDnL2tQ2xf/zO7F7hmZ4S
|
||||
ZuwKENdI4IYuWSxye4i3hPhKg6eKPzGzmDNWkIMDOrDAj1EgVSNPtPwsOL8OWvJm
|
||||
AaTjr070D7ZGWWnrrDrWEClBx9Rx/6JAM38RT8Pu7c1hXBm0J81KufSLLYiZ/gOw
|
||||
Znks5v5RUSGcAXvLkBJeATbsbh6fKX0RgQ3fFTvqQaE/r8LxcTN1uehPX1g5AaRa
|
||||
z/SNDHaFtQlE3XcqAAukyMn4N5kdNcuwF3GlQ+tJnJv8SstPkfQcZbTMUQ7I2KpJ
|
||||
ajXnMxmBhV5fCN4rb0QUNCrk2/B+EUMBY4MnxIakqNxnN1kvgI7FBbFgrHUe6QvJ
|
||||
AgMBAAGjIzAhMA4GA1UdDwEB/wQEAwICpDAPBgNVHRMBAf8EBTADAQH/MA0GCSqG
|
||||
SIb3DQEBCwUAA4IBAQAYRV57LUsqznSLZHA77o9+0fQetIE115DYP7wea42PODJI
|
||||
QJ+JETEfoCr0+YOMAbVmznP9GH5cMTKEWHExcIpbMBU7nMZp6A3htcJgF2fgPzOA
|
||||
aTUtzkuVCSrV//mbbYVxoFOc6sR3Br0wBs5+5iz3dBSt7xmgpMzZvqsQl655i051
|
||||
gGSTIY3z5EJmBZBjwuTjal9mMoPGA4eoTPqlITJDHQ2bdCV2oDbc7zqupGrUfZFA
|
||||
qzgieEyGzdCSRwjr1/PibA3bpwHyhD9CGD0PRVVTLhw6h6L5kuN1jA20OfzWxf/o
|
||||
XUsdmRaWiF+l4s6Dcd56SuRp5SGNa2+vP9Of/FX5
|
||||
FAKECERTsdKgAwI...
|
||||
-----END CERTIFICATE-----
|
||||
metrics:
|
||||
role: amqp
|
||||
|
||||
@@ -181,6 +181,7 @@ def api_validation(args=None):
|
||||
https://www.memset.com/apidocs/methods_dns.html#dns.zone_record_create)
|
||||
'''
|
||||
failed_validation = False
|
||||
error = None
|
||||
|
||||
# priority can only be integer 0 > 999
|
||||
if not 0 <= args['priority'] <= 999:
|
||||
|
||||
@@ -163,8 +163,9 @@ class Modprobe(object):
|
||||
def create_module_file(self):
|
||||
file_path = os.path.join(MODULES_LOAD_LOCATION,
|
||||
self.name + '.conf')
|
||||
with open(file_path, 'w') as file:
|
||||
file.write(self.name + '\n')
|
||||
if not self.check_mode:
|
||||
with open(file_path, 'w') as file:
|
||||
file.write(self.name + '\n')
|
||||
|
||||
@property
|
||||
def module_options_file_content(self):
|
||||
@@ -175,8 +176,9 @@ class Modprobe(object):
|
||||
def create_module_options_file(self):
|
||||
new_file_path = os.path.join(PARAMETERS_FILES_LOCATION,
|
||||
self.name + '.conf')
|
||||
with open(new_file_path, 'w') as file:
|
||||
file.write(self.module_options_file_content)
|
||||
if not self.check_mode:
|
||||
with open(new_file_path, 'w') as file:
|
||||
file.write(self.module_options_file_content)
|
||||
|
||||
def disable_old_params(self):
|
||||
|
||||
@@ -190,7 +192,7 @@ class Modprobe(object):
|
||||
file_content[index] = '#' + line
|
||||
content_changed = True
|
||||
|
||||
if content_changed:
|
||||
if not self.check_mode and content_changed:
|
||||
with open(modprobe_file, 'w') as file:
|
||||
file.write('\n'.join(file_content))
|
||||
|
||||
@@ -206,7 +208,7 @@ class Modprobe(object):
|
||||
file_content[index] = '#' + line
|
||||
content_changed = True
|
||||
|
||||
if content_changed:
|
||||
if not self.check_mode and content_changed:
|
||||
with open(module_file, 'w') as file:
|
||||
file.write('\n'.join(file_content))
|
||||
|
||||
|
||||
@@ -522,7 +522,7 @@ def create_service_and_operation(module, auth, template_id, service_name, owner_
|
||||
if unique:
|
||||
service = get_service_by_name(module, auth, service_name)
|
||||
|
||||
if not service:
|
||||
if not service or service["TEMPLATE"]["BODY"]["state"] == "DONE":
|
||||
if not module.check_mode:
|
||||
service = create_service(module, auth, template_id, service_name, custom_attrs, unique, wait, wait_timeout)
|
||||
changed = True
|
||||
@@ -637,7 +637,6 @@ def get_service_id_by_name(module, auth, service_name):
|
||||
|
||||
|
||||
def get_connection_info(module):
|
||||
|
||||
url = module.params.get('api_url')
|
||||
username = module.params.get('api_username')
|
||||
password = module.params.get('api_password')
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2021, Georg Gadinger <nilsding@nilsding.org>
|
||||
# Copyright (c) 2021, Jyrki Gadinger <nilsding@nilsding.org>
|
||||
# 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
|
||||
|
||||
@@ -60,7 +60,7 @@ extends_documentation_fragment:
|
||||
- community.general.attributes
|
||||
|
||||
author:
|
||||
- "Georg Gadinger (@nilsding)"
|
||||
- "Jyrki Gadinger (@nilsding)"
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
|
||||
@@ -339,7 +339,7 @@ def main():
|
||||
pass
|
||||
|
||||
# Move tempfile to newfile
|
||||
module.atomic_move(nf.name, limits_conf)
|
||||
module.atomic_move(os.path.abspath(nf.name), os.path.abspath(limits_conf))
|
||||
|
||||
try:
|
||||
nf.close()
|
||||
|
||||
@@ -27,6 +27,7 @@ options:
|
||||
type: list
|
||||
elements: path
|
||||
requirements:
|
||||
- pip >= 20.3b1 (necessary for the C(--format) option)
|
||||
- The requested pip executables must be installed on the target.
|
||||
author:
|
||||
- Matthew Jones (@matburt)
|
||||
|
||||
@@ -157,6 +157,17 @@ EXAMPLES = '''
|
||||
community.general.pipx:
|
||||
name: pycowsay
|
||||
state: absent
|
||||
|
||||
- name: Install multiple packages from list
|
||||
vars:
|
||||
pipx_packages:
|
||||
- pycowsay
|
||||
- black
|
||||
- tox
|
||||
community.general.pipx:
|
||||
name: "{{ item }}"
|
||||
state: latest
|
||||
with_items: "{{ pipx_packages }}"
|
||||
'''
|
||||
|
||||
|
||||
|
||||
@@ -326,7 +326,8 @@ EXAMPLES = r'''
|
||||
password: 123456
|
||||
hostname: example.org
|
||||
ostemplate: 'local:vztmpl/ubuntu-14.04-x86_64.tar.gz'
|
||||
netif: '{"net0":"name=eth0,ip=dhcp,ip6=dhcp,bridge=vmbr0"}'
|
||||
netif:
|
||||
net0: "name=eth0,ip=dhcp,ip6=dhcp,bridge=vmbr0"
|
||||
|
||||
- name: Create new container with minimal options defining network interface with static ip
|
||||
community.general.proxmox:
|
||||
@@ -338,7 +339,21 @@ EXAMPLES = r'''
|
||||
password: 123456
|
||||
hostname: example.org
|
||||
ostemplate: 'local:vztmpl/ubuntu-14.04-x86_64.tar.gz'
|
||||
netif: '{"net0":"name=eth0,gw=192.168.0.1,ip=192.168.0.2/24,bridge=vmbr0"}'
|
||||
netif:
|
||||
net0: "name=eth0,gw=192.168.0.1,ip=192.168.0.2/24,bridge=vmbr0"
|
||||
|
||||
- name: Create new container with more options defining network interface with static ip4 and ip6 with vlan-tag and mtu
|
||||
community.general.proxmox:
|
||||
vmid: 100
|
||||
node: uk-mc02
|
||||
api_user: root@pam
|
||||
api_password: 1q2w3e
|
||||
api_host: node1
|
||||
password: 123456
|
||||
hostname: example.org
|
||||
ostemplate: 'local:vztmpl/ubuntu-14.04-x86_64.tar.gz'
|
||||
netif:
|
||||
net0: "name=eth0,gw=192.168.0.1,ip=192.168.0.2/24,ip6=fe80::1227/64,gw6=fe80::1,bridge=vmbr0,firewall=1,tag=934,mtu=1500"
|
||||
|
||||
- name: Create new container with minimal options defining a mount with 8GB
|
||||
community.general.proxmox:
|
||||
@@ -350,7 +365,8 @@ EXAMPLES = r'''
|
||||
password: 123456
|
||||
hostname: example.org
|
||||
ostemplate: 'local:vztmpl/ubuntu-14.04-x86_64.tar.gz'
|
||||
mounts: '{"mp0":"local:8,mp=/mnt/test/"}'
|
||||
mounts:
|
||||
mp0: "local:8,mp=/mnt/test/"
|
||||
|
||||
- name: Create new container with minimal options defining a cpu core limit
|
||||
community.general.proxmox:
|
||||
@@ -420,7 +436,8 @@ EXAMPLES = r'''
|
||||
api_user: root@pam
|
||||
api_password: 1q2w3e
|
||||
api_host: node1
|
||||
netif: '{"net0":"name=eth0,gw=192.168.0.1,ip=192.168.0.3/24,bridge=vmbr0"}'
|
||||
netif:
|
||||
net0: "name=eth0,gw=192.168.0.1,ip=192.168.0.3/24,bridge=vmbr0"
|
||||
update: true
|
||||
|
||||
- name: Start container
|
||||
|
||||
@@ -541,6 +541,7 @@ class ProxmoxDiskAnsible(ProxmoxAnsible):
|
||||
# NOOP
|
||||
return False, "Disk %s not found in VM %s and creation was disabled in parameters." % (disk, vmid)
|
||||
|
||||
timeout_str = "Reached timeout. Last line in task before timeout: %s"
|
||||
if (create == 'regular' and disk not in vm_config) or (create == 'forced'):
|
||||
# CREATE
|
||||
playbook_config = self.get_create_attributes()
|
||||
|
||||
@@ -163,6 +163,9 @@ options:
|
||||
required: false
|
||||
description:
|
||||
- Setting dict of volume to be created.
|
||||
- If C(CapacityBytes) key is not specified in this dictionary, the size of
|
||||
the volume will be determined by the Redfish service. It is possible the
|
||||
size will not be the maximum available size.
|
||||
type: dict
|
||||
default: {}
|
||||
version_added: '7.5.0'
|
||||
|
||||
@@ -307,6 +307,8 @@ def main():
|
||||
if m_args['community'] is None:
|
||||
module.fail_json(msg='Community not set when using snmp version 2')
|
||||
|
||||
integrity_proto = None
|
||||
privacy_proto = None
|
||||
if m_args['version'] == "v3":
|
||||
if m_args['username'] is None:
|
||||
module.fail_json(msg='Username not set when using snmp version 3')
|
||||
|
||||
@@ -49,7 +49,8 @@ options:
|
||||
aliases: [ rtc ]
|
||||
choices: [ local, UTC ]
|
||||
notes:
|
||||
- On SmartOS the C(sm-set-timezone) utility (part of the smtools package) is required to set the zone timezone
|
||||
- On Ubuntu 24.04 the C(util-linux-extra) package is required to provide the C(hwclock) command.
|
||||
- On SmartOS the C(sm-set-timezone) utility (part of the smtools package) is required to set the zone timezone.
|
||||
- On AIX only Olson/tz database timezones are usable (POSIX is not supported).
|
||||
An OS reboot is also required on AIX for the new timezone setting to take effect.
|
||||
Note that AIX 6.1+ is needed (OS level 61 or newer).
|
||||
@@ -75,6 +76,7 @@ diff:
|
||||
|
||||
EXAMPLES = r'''
|
||||
- name: Set timezone to Asia/Tokyo
|
||||
become: true
|
||||
community.general.timezone:
|
||||
name: Asia/Tokyo
|
||||
'''
|
||||
|
||||
@@ -21,11 +21,11 @@ description:
|
||||
server (UCS).
|
||||
It uses the python API of the UCS to create a new object or edit it."
|
||||
notes:
|
||||
- This module does B(not) work with Python 3.13 or newer. It uses the deprecated L(crypt Python module,
|
||||
https://docs.python.org/3.12/library/crypt.html) from the Python standard library, which was removed
|
||||
from Python 3.13.
|
||||
- This module requires the deprecated L(crypt Python module,
|
||||
https://docs.python.org/3.12/library/crypt.html) library which was removed from Python 3.13.
|
||||
For Python 3.13 or newer, you need to install L(legacycrypt, https://pypi.org/project/legacycrypt/).
|
||||
requirements:
|
||||
- Python 3.12 or earlier
|
||||
- legacycrypt (on Python 3.13 or newer)
|
||||
extends_documentation_fragment:
|
||||
- community.general.attributes
|
||||
attributes:
|
||||
@@ -350,6 +350,17 @@ else:
|
||||
HAS_CRYPT = True
|
||||
CRYPT_IMPORT_ERROR = None
|
||||
|
||||
try:
|
||||
import legacycrypt
|
||||
if not HAS_CRYPT:
|
||||
crypt = legacycrypt
|
||||
except ImportError:
|
||||
HAS_LEGACYCRYPT = False
|
||||
LEGACYCRYPT_IMPORT_ERROR = traceback.format_exc()
|
||||
else:
|
||||
HAS_LEGACYCRYPT = True
|
||||
LEGACYCRYPT_IMPORT_ERROR = None
|
||||
|
||||
|
||||
def main():
|
||||
expiry = date.strftime(date.today() + timedelta(days=365), "%Y-%m-%d")
|
||||
@@ -467,10 +478,10 @@ def main():
|
||||
])
|
||||
)
|
||||
|
||||
if not HAS_CRYPT:
|
||||
if not HAS_CRYPT and not HAS_LEGACYCRYPT:
|
||||
module.fail_json(
|
||||
msg=missing_required_lib('crypt (part of Python 3.13 standard library)'),
|
||||
exception=CRYPT_IMPORT_ERROR,
|
||||
msg=missing_required_lib('crypt (part of standard library up to Python 3.12) or legacycrypt (PyPI)'),
|
||||
exception=LEGACYCRYPT_IMPORT_ERROR,
|
||||
)
|
||||
|
||||
username = module.params['username']
|
||||
|
||||
@@ -5,3 +5,4 @@
|
||||
|
||||
dependencies:
|
||||
- setup_pkg_mgr
|
||||
- setup_os_pkg_name
|
||||
|
||||
@@ -9,17 +9,10 @@
|
||||
suffix: .django_manage
|
||||
register: tmp_django_root
|
||||
|
||||
- name: Install virtualenv on CentOS 8
|
||||
- name: Install virtualenv
|
||||
package:
|
||||
name: virtualenv
|
||||
name: "{{ os_package_name.virtualenv }}"
|
||||
state: present
|
||||
when: ansible_distribution == 'CentOS' and ansible_distribution_major_version == '8'
|
||||
|
||||
- name: Install virtualenv on Arch Linux
|
||||
pip:
|
||||
name: virtualenv
|
||||
state: present
|
||||
when: ansible_os_family == 'Archlinux'
|
||||
|
||||
- name: Install required library
|
||||
pip:
|
||||
|
||||
@@ -2,5 +2,4 @@
|
||||
# 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
|
||||
|
||||
cloud/gandi
|
||||
unsupported
|
||||
|
||||
@@ -15,6 +15,11 @@
|
||||
ignore_errors: true
|
||||
|
||||
- block:
|
||||
- name: Install legacycrypt on Python 3.13+
|
||||
pip:
|
||||
name: legacycrypt
|
||||
when: ansible_python_version is version("3.13", ">=")
|
||||
|
||||
- name: Check and start systemd-homed service
|
||||
service:
|
||||
name: systemd-homed.service
|
||||
|
||||
@@ -6,4 +6,3 @@ azp/posix/2
|
||||
destructive
|
||||
skip/python2
|
||||
skip/python3.5
|
||||
disabled # TODO
|
||||
|
||||
@@ -217,76 +217,76 @@
|
||||
- "'tox' not in uninstall_tox_again.application"
|
||||
|
||||
##############################################################################
|
||||
- name: ensure application ansible-lint is uninstalled
|
||||
- name: ensure application pylint is uninstalled
|
||||
community.general.pipx:
|
||||
name: ansible-lint
|
||||
name: pylint
|
||||
state: absent
|
||||
|
||||
- name: install application ansible-lint
|
||||
- name: install application pylint
|
||||
community.general.pipx:
|
||||
name: ansible-lint
|
||||
register: install_ansible_lint
|
||||
name: pylint
|
||||
register: install_pylint
|
||||
|
||||
- name: inject packages
|
||||
community.general.pipx:
|
||||
state: inject
|
||||
name: ansible-lint
|
||||
name: pylint
|
||||
inject_packages:
|
||||
- licenses
|
||||
register: inject_pkgs_ansible_lint
|
||||
register: inject_pkgs_pylint
|
||||
|
||||
- name: inject packages with apps
|
||||
community.general.pipx:
|
||||
state: inject
|
||||
name: ansible-lint
|
||||
name: pylint
|
||||
inject_packages:
|
||||
- black
|
||||
install_apps: true
|
||||
register: inject_pkgs_apps_ansible_lint
|
||||
register: inject_pkgs_apps_pylint
|
||||
|
||||
- name: cleanup ansible-lint
|
||||
- name: cleanup pylint
|
||||
community.general.pipx:
|
||||
state: absent
|
||||
name: ansible-lint
|
||||
register: uninstall_ansible_lint
|
||||
name: pylint
|
||||
register: uninstall_pylint
|
||||
|
||||
- name: check assertions inject_packages
|
||||
assert:
|
||||
that:
|
||||
- install_ansible_lint is changed
|
||||
- inject_pkgs_ansible_lint is changed
|
||||
- '"ansible-lint" in inject_pkgs_ansible_lint.application'
|
||||
- '"licenses" in inject_pkgs_ansible_lint.application["ansible-lint"]["injected"]'
|
||||
- inject_pkgs_apps_ansible_lint is changed
|
||||
- '"ansible-lint" in inject_pkgs_apps_ansible_lint.application'
|
||||
- '"black" in inject_pkgs_apps_ansible_lint.application["ansible-lint"]["injected"]'
|
||||
- uninstall_ansible_lint is changed
|
||||
- install_pylint is changed
|
||||
- inject_pkgs_pylint is changed
|
||||
- '"pylint" in inject_pkgs_pylint.application'
|
||||
- '"licenses" in inject_pkgs_pylint.application["pylint"]["injected"]'
|
||||
- inject_pkgs_apps_pylint is changed
|
||||
- '"pylint" in inject_pkgs_apps_pylint.application'
|
||||
- '"black" in inject_pkgs_apps_pylint.application["pylint"]["injected"]'
|
||||
- uninstall_pylint is changed
|
||||
|
||||
##############################################################################
|
||||
- name: install jupyter - not working smoothly in freebsd
|
||||
when: ansible_system != 'FreeBSD'
|
||||
# when: ansible_system != 'FreeBSD'
|
||||
block:
|
||||
- name: ensure application jupyter is uninstalled
|
||||
- name: ensure application mkdocs is uninstalled
|
||||
community.general.pipx:
|
||||
name: jupyter
|
||||
name: mkdocs
|
||||
state: absent
|
||||
|
||||
- name: install application jupyter
|
||||
- name: install application mkdocs
|
||||
community.general.pipx:
|
||||
name: jupyter
|
||||
name: mkdocs
|
||||
install_deps: true
|
||||
register: install_jupyter
|
||||
register: install_mkdocs
|
||||
|
||||
- name: cleanup jupyter
|
||||
- name: cleanup mkdocs
|
||||
community.general.pipx:
|
||||
state: absent
|
||||
name: jupyter
|
||||
name: mkdocs
|
||||
|
||||
- name: check assertions
|
||||
assert:
|
||||
that:
|
||||
- install_jupyter is changed
|
||||
- '"ipython" in install_jupyter.stdout'
|
||||
- install_mkdocs is changed
|
||||
- '"markdown_py" in install_mkdocs.stdout'
|
||||
|
||||
##############################################################################
|
||||
- name: ensure /opt/pipx
|
||||
|
||||
@@ -6,4 +6,3 @@ azp/posix/3
|
||||
destructive
|
||||
skip/python2
|
||||
skip/python3.5
|
||||
disabled # TODO
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
apps:
|
||||
- name: tox
|
||||
source: tox==3.24.0
|
||||
- name: ansible-lint
|
||||
- name: pylint
|
||||
inject_packages:
|
||||
- licenses
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
- name: install applications
|
||||
community.general.pipx:
|
||||
name: "{{ item.name }}"
|
||||
source: "{{ item.source|default(omit) }}"
|
||||
source: "{{ item.source | default(omit) }}"
|
||||
loop: "{{ apps }}"
|
||||
|
||||
- name: inject packages
|
||||
@@ -102,9 +102,9 @@
|
||||
include_injected: true
|
||||
register: info2_all_deps
|
||||
|
||||
- name: retrieve application ansible-lint
|
||||
- name: retrieve application pylint
|
||||
community.general.pipx_info:
|
||||
name: ansible-lint
|
||||
name: pylint
|
||||
include_deps: true
|
||||
include_injected: true
|
||||
register: info2_lint
|
||||
@@ -131,10 +131,10 @@
|
||||
- "'injected' in all_apps_deps[0]"
|
||||
- "'licenses' in all_apps_deps[0].injected"
|
||||
|
||||
- lint|length == 1
|
||||
- lint | length == 1
|
||||
- all_apps_deps|length == 2
|
||||
- lint[0] == all_apps_deps[0]
|
||||
vars:
|
||||
all_apps: "{{ info2_all.application|sort(attribute='name') }}"
|
||||
all_apps_deps: "{{ info2_all_deps.application|sort(attribute='name') }}"
|
||||
lint: "{{ info2_lint.application|sort(attribute='name') }}"
|
||||
all_apps_deps: "{{ info2_all_deps.application | sort(attribute='name') }}"
|
||||
lint: "{{ info2_lint.application | sort(attribute='name') }}"
|
||||
|
||||
11
tests/integration/targets/setup_os_pkg_name/tasks/alpine.yml
Normal file
11
tests/integration/targets/setup_os_pkg_name/tasks/alpine.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
# 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: Update OS Package name fact (alpine)
|
||||
ansible.builtin.set_fact:
|
||||
os_package_name: "{{ os_package_name | combine(specific_package_names) }}"
|
||||
vars:
|
||||
specific_package_names:
|
||||
virtualenv: py3-virtualenv
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
# 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: Update OS Package name fact (archlinux)
|
||||
ansible.builtin.set_fact:
|
||||
os_package_name: "{{ os_package_name | combine(specific_package_names) }}"
|
||||
vars:
|
||||
specific_package_names:
|
||||
virtualenv: python-virtualenv
|
||||
10
tests/integration/targets/setup_os_pkg_name/tasks/debian.yml
Normal file
10
tests/integration/targets/setup_os_pkg_name/tasks/debian.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
# 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: Update OS Package name fact (debian)
|
||||
ansible.builtin.set_fact:
|
||||
os_package_name: "{{ os_package_name | combine(specific_package_names) }}"
|
||||
vars:
|
||||
specific_package_names: {}
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
# 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: Update OS Package name fact (default)
|
||||
ansible.builtin.set_fact:
|
||||
os_package_name: "{{ os_package_name | combine(specific_package_names) }}"
|
||||
vars:
|
||||
specific_package_names:
|
||||
virtualenv: virtualenv
|
||||
26
tests/integration/targets/setup_os_pkg_name/tasks/main.yml
Normal file
26
tests/integration/targets/setup_os_pkg_name/tasks/main.yml
Normal file
@@ -0,0 +1,26 @@
|
||||
---
|
||||
####################################################################
|
||||
# WARNING: These are designed specifically for Ansible tests #
|
||||
# and should not be used as examples of how to write Ansible roles #
|
||||
####################################################################
|
||||
|
||||
# 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: Make sure we have the ansible_os_family and ansible_distribution_version facts
|
||||
ansible.builtin.setup:
|
||||
gather_subset: distribution
|
||||
when: ansible_facts == {}
|
||||
|
||||
- name: Create OS Package name fact
|
||||
ansible.builtin.set_fact:
|
||||
os_package_name: {}
|
||||
|
||||
- name: Include the files setting the package names
|
||||
ansible.builtin.include_tasks: "{{ file }}"
|
||||
loop_control:
|
||||
loop_var: file
|
||||
loop:
|
||||
- "default.yml"
|
||||
- "{{ ansible_os_family | lower }}.yml"
|
||||
10
tests/integration/targets/setup_os_pkg_name/tasks/redhat.yml
Normal file
10
tests/integration/targets/setup_os_pkg_name/tasks/redhat.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
# 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: Update OS Package name fact (redhat)
|
||||
ansible.builtin.set_fact:
|
||||
os_package_name: "{{ os_package_name | combine(specific_package_names) }}"
|
||||
vars:
|
||||
specific_package_names: {}
|
||||
11
tests/integration/targets/setup_os_pkg_name/tasks/suse.yml
Normal file
11
tests/integration/targets/setup_os_pkg_name/tasks/suse.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
# 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: Update OS Package name fact (suse)
|
||||
ansible.builtin.set_fact:
|
||||
os_package_name: "{{ os_package_name | combine(specific_package_names) }}"
|
||||
vars:
|
||||
specific_package_names:
|
||||
virtualenv: python3-virtualenv
|
||||
@@ -15,9 +15,8 @@
|
||||
ansible.builtin.include_tasks: test.yml
|
||||
- name: Include test_channel
|
||||
ansible.builtin.include_tasks: test_channel.yml
|
||||
# TODO: Find better package to download and install from sources - cider 1.6.0 takes over 35 seconds to install
|
||||
# - name: Include test_dangerous
|
||||
# ansible.builtin.include_tasks: test_dangerous.yml
|
||||
- name: Include test_dangerous
|
||||
ansible.builtin.include_tasks: test_dangerous.yml
|
||||
- name: Include test_3dash
|
||||
ansible.builtin.include_tasks: test_3dash.yml
|
||||
- name: Include test_empty_list
|
||||
|
||||
@@ -5,43 +5,48 @@
|
||||
|
||||
# NOTE This is currently disabled for performance reasons!
|
||||
|
||||
- name: Make sure package is not installed (cider)
|
||||
- name: Make sure package is not installed (bpytop)
|
||||
community.general.snap:
|
||||
name: cider
|
||||
name: bpytop
|
||||
state: absent
|
||||
|
||||
- name: Download cider snap
|
||||
ansible.builtin.get_url:
|
||||
url: https://github.com/ciderapp/cider-releases/releases/download/v1.6.0/cider_1.6.0_amd64.snap
|
||||
dest: "{{ remote_tmp_dir }}/cider_1.6.0_amd64.snap"
|
||||
mode: "0644"
|
||||
- name: Download bpytop snap
|
||||
ansible.builtin.command:
|
||||
cmd: snap download bpytop
|
||||
chdir: "{{ remote_tmp_dir }}"
|
||||
register: bpytop_download
|
||||
|
||||
# Test for https://github.com/ansible-collections/community.general/issues/5715
|
||||
- name: Install package from file (check)
|
||||
community.general.snap:
|
||||
name: "{{ remote_tmp_dir }}/cider_1.6.0_amd64.snap"
|
||||
dangerous: true
|
||||
state: present
|
||||
check_mode: true
|
||||
register: install_dangerous_check
|
||||
- name: Test block
|
||||
vars:
|
||||
snap_file: "{{ (bpytop_download.stdout_lines[-1] | split(' '))[-1] }}"
|
||||
snap_path: "{{ remote_tmp_dir }}/{{ snap_file }}"
|
||||
block:
|
||||
# Test for https://github.com/ansible-collections/community.general/issues/5715
|
||||
- name: Install package from file (check)
|
||||
community.general.snap:
|
||||
name: "{{ snap_path }}"
|
||||
dangerous: true
|
||||
state: present
|
||||
check_mode: true
|
||||
register: install_dangerous_check
|
||||
|
||||
- name: Install package from file
|
||||
community.general.snap:
|
||||
name: "{{ remote_tmp_dir }}/cider_1.6.0_amd64.snap"
|
||||
dangerous: true
|
||||
state: present
|
||||
register: install_dangerous
|
||||
- name: Install package from file
|
||||
community.general.snap:
|
||||
name: "{{ snap_path }}"
|
||||
dangerous: true
|
||||
state: present
|
||||
register: install_dangerous
|
||||
|
||||
- name: Install package from file
|
||||
community.general.snap:
|
||||
name: "{{ remote_tmp_dir }}/cider_1.6.0_amd64.snap"
|
||||
dangerous: true
|
||||
state: present
|
||||
register: install_dangerous_idempot
|
||||
- name: Install package from file (again)
|
||||
community.general.snap:
|
||||
name: "{{ snap_path }}"
|
||||
dangerous: true
|
||||
state: present
|
||||
register: install_dangerous_idempot
|
||||
|
||||
- name: Remove package
|
||||
community.general.snap:
|
||||
name: cider
|
||||
name: bpytop
|
||||
state: absent
|
||||
register: remove_dangerous
|
||||
|
||||
|
||||
@@ -7,3 +7,4 @@ destructive
|
||||
skip/aix
|
||||
skip/osx
|
||||
skip/macos
|
||||
skip/rhel7.9 # TODO: '/bin/timedatectl set-local-rtc no' fails with 'Failed to set local RTC: Failed to set RTC to local/UTC: Input/output error'
|
||||
|
||||
@@ -60,6 +60,14 @@
|
||||
state: present
|
||||
when: ansible_distribution == 'Alpine'
|
||||
|
||||
- name: make sure hwclock is installed in Ubuntu 24.04
|
||||
package:
|
||||
name: util-linux-extra
|
||||
state: present
|
||||
when:
|
||||
- ansible_distribution == 'Ubuntu'
|
||||
- ansible_facts.distribution_major_version is version('24', '>=')
|
||||
|
||||
- name: make sure the dbus service is started under systemd
|
||||
systemd:
|
||||
name: dbus
|
||||
|
||||
@@ -146,7 +146,7 @@ def serialize_groups(groups):
|
||||
return list(map(str, groups))
|
||||
|
||||
|
||||
@ pytest.fixture(scope="module")
|
||||
@pytest.fixture(scope="module")
|
||||
def inventory():
|
||||
r = InventoryModule()
|
||||
r.inventory = InventoryData()
|
||||
|
||||
@@ -7,7 +7,7 @@ from __future__ import (absolute_import, division, print_function)
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
from ansible_collections.community.general.plugins.modules.monitoring.datadog import datadog_downtime
|
||||
from ansible_collections.community.general.plugins.modules import datadog_downtime
|
||||
from ansible_collections.community.general.tests.unit.compat.mock import MagicMock, patch
|
||||
from ansible_collections.community.general.tests.unit.plugins.modules.utils import (
|
||||
AnsibleExitJson, AnsibleFailJson, ModuleTestCase, set_module_args
|
||||
@@ -36,7 +36,7 @@ class TestDatadogDowntime(ModuleTestCase):
|
||||
set_module_args({})
|
||||
self.module.main()
|
||||
|
||||
@patch("ansible_collections.community.general.plugins.modules.monitoring.datadog.datadog_downtime.DowntimesApi")
|
||||
@patch("ansible_collections.community.general.plugins.modules.datadog_downtime.DowntimesApi")
|
||||
def test_create_downtime_when_no_id(self, downtimes_api_mock):
|
||||
set_module_args({
|
||||
"monitor_tags": ["foo:bar"],
|
||||
@@ -60,10 +60,11 @@ class TestDatadogDowntime(ModuleTestCase):
|
||||
downtime.end = 2222
|
||||
downtime.timezone = "UTC"
|
||||
downtime.recurrence = DowntimeRecurrence(
|
||||
rrule="rrule"
|
||||
rrule="rrule",
|
||||
type="rrule"
|
||||
)
|
||||
|
||||
create_downtime_mock = MagicMock(return_value=Downtime(id=12345))
|
||||
create_downtime_mock = MagicMock(return_value=self.__downtime_with_id(12345))
|
||||
downtimes_api_mock.return_value = MagicMock(create_downtime=create_downtime_mock)
|
||||
with self.assertRaises(AnsibleExitJson) as result:
|
||||
self.module.main()
|
||||
@@ -71,7 +72,7 @@ class TestDatadogDowntime(ModuleTestCase):
|
||||
self.assertEqual(result.exception.args[0]['downtime']['id'], 12345)
|
||||
create_downtime_mock.assert_called_once_with(downtime)
|
||||
|
||||
@patch("ansible_collections.community.general.plugins.modules.monitoring.datadog.datadog_downtime.DowntimesApi")
|
||||
@patch("ansible_collections.community.general.plugins.modules.datadog_downtime.DowntimesApi")
|
||||
def test_create_downtime_when_id_and_disabled(self, downtimes_api_mock):
|
||||
set_module_args({
|
||||
"id": 1212,
|
||||
@@ -96,11 +97,16 @@ class TestDatadogDowntime(ModuleTestCase):
|
||||
downtime.end = 2222
|
||||
downtime.timezone = "UTC"
|
||||
downtime.recurrence = DowntimeRecurrence(
|
||||
rrule="rrule"
|
||||
rrule="rrule",
|
||||
type="rrule"
|
||||
)
|
||||
|
||||
create_downtime_mock = MagicMock(return_value=Downtime(id=12345))
|
||||
get_downtime_mock = MagicMock(return_value=Downtime(id=1212, disabled=True))
|
||||
disabled_downtime = Downtime()
|
||||
disabled_downtime.disabled = True
|
||||
disabled_downtime.id = 1212
|
||||
|
||||
create_downtime_mock = MagicMock(return_value=self.__downtime_with_id(12345))
|
||||
get_downtime_mock = MagicMock(return_value=disabled_downtime)
|
||||
downtimes_api_mock.return_value = MagicMock(
|
||||
create_downtime=create_downtime_mock, get_downtime=get_downtime_mock
|
||||
)
|
||||
@@ -111,7 +117,7 @@ class TestDatadogDowntime(ModuleTestCase):
|
||||
create_downtime_mock.assert_called_once_with(downtime)
|
||||
get_downtime_mock.assert_called_once_with(1212)
|
||||
|
||||
@patch("ansible_collections.community.general.plugins.modules.monitoring.datadog.datadog_downtime.DowntimesApi")
|
||||
@patch("ansible_collections.community.general.plugins.modules.datadog_downtime.DowntimesApi")
|
||||
def test_update_downtime_when_not_disabled(self, downtimes_api_mock):
|
||||
set_module_args({
|
||||
"id": 1212,
|
||||
@@ -136,11 +142,16 @@ class TestDatadogDowntime(ModuleTestCase):
|
||||
downtime.end = 2222
|
||||
downtime.timezone = "UTC"
|
||||
downtime.recurrence = DowntimeRecurrence(
|
||||
rrule="rrule"
|
||||
rrule="rrule",
|
||||
type="rrule"
|
||||
)
|
||||
|
||||
update_downtime_mock = MagicMock(return_value=Downtime(id=1212))
|
||||
get_downtime_mock = MagicMock(return_value=Downtime(id=1212, disabled=False))
|
||||
enabled_downtime = Downtime()
|
||||
enabled_downtime.disabled = False
|
||||
enabled_downtime.id = 1212
|
||||
|
||||
update_downtime_mock = MagicMock(return_value=self.__downtime_with_id(1212))
|
||||
get_downtime_mock = MagicMock(return_value=enabled_downtime)
|
||||
downtimes_api_mock.return_value = MagicMock(
|
||||
update_downtime=update_downtime_mock, get_downtime=get_downtime_mock
|
||||
)
|
||||
@@ -151,7 +162,7 @@ class TestDatadogDowntime(ModuleTestCase):
|
||||
update_downtime_mock.assert_called_once_with(1212, downtime)
|
||||
get_downtime_mock.assert_called_once_with(1212)
|
||||
|
||||
@patch("ansible_collections.community.general.plugins.modules.monitoring.datadog.datadog_downtime.DowntimesApi")
|
||||
@patch("ansible_collections.community.general.plugins.modules.datadog_downtime.DowntimesApi")
|
||||
def test_update_downtime_no_change(self, downtimes_api_mock):
|
||||
set_module_args({
|
||||
"id": 1212,
|
||||
@@ -176,7 +187,8 @@ class TestDatadogDowntime(ModuleTestCase):
|
||||
downtime.end = 2222
|
||||
downtime.timezone = "UTC"
|
||||
downtime.recurrence = DowntimeRecurrence(
|
||||
rrule="rrule"
|
||||
rrule="rrule",
|
||||
type="rrule"
|
||||
)
|
||||
|
||||
downtime_get = Downtime()
|
||||
@@ -205,7 +217,7 @@ class TestDatadogDowntime(ModuleTestCase):
|
||||
update_downtime_mock.assert_called_once_with(1212, downtime)
|
||||
get_downtime_mock.assert_called_once_with(1212)
|
||||
|
||||
@patch("ansible_collections.community.general.plugins.modules.monitoring.datadog.datadog_downtime.DowntimesApi")
|
||||
@patch("ansible_collections.community.general.plugins.modules.datadog_downtime.DowntimesApi")
|
||||
def test_delete_downtime(self, downtimes_api_mock):
|
||||
set_module_args({
|
||||
"id": 1212,
|
||||
@@ -215,12 +227,16 @@ class TestDatadogDowntime(ModuleTestCase):
|
||||
})
|
||||
|
||||
cancel_downtime_mock = MagicMock()
|
||||
get_downtime_mock = MagicMock(return_value=Downtime(id=1212))
|
||||
downtimes_api_mock.return_value = MagicMock(
|
||||
get_downtime=get_downtime_mock,
|
||||
get_downtime=self.__downtime_with_id,
|
||||
cancel_downtime=cancel_downtime_mock
|
||||
)
|
||||
with self.assertRaises(AnsibleExitJson) as result:
|
||||
self.module.main()
|
||||
self.assertTrue(result.exception.args[0]['changed'])
|
||||
cancel_downtime_mock.assert_called_once_with(1212)
|
||||
|
||||
def __downtime_with_id(self, id):
|
||||
downtime = Downtime()
|
||||
downtime.id = id
|
||||
return downtime
|
||||
@@ -23,7 +23,7 @@ from ansible.module_utils.six import StringIO
|
||||
@contextmanager
|
||||
def patch_keycloak_api(get_identity_provider, create_identity_provider=None, update_identity_provider=None, delete_identity_provider=None,
|
||||
get_identity_provider_mappers=None, create_identity_provider_mapper=None, update_identity_provider_mapper=None,
|
||||
delete_identity_provider_mapper=None):
|
||||
delete_identity_provider_mapper=None, get_realm_by_id=None):
|
||||
"""Mock context manager for patching the methods in PwPolicyIPAClient that contact the IPA server
|
||||
|
||||
Patches the `login` and `_post_json` methods
|
||||
@@ -55,9 +55,11 @@ def patch_keycloak_api(get_identity_provider, create_identity_provider=None, upd
|
||||
as mock_update_identity_provider_mapper:
|
||||
with patch.object(obj, 'delete_identity_provider_mapper', side_effect=delete_identity_provider_mapper) \
|
||||
as mock_delete_identity_provider_mapper:
|
||||
yield mock_get_identity_provider, mock_create_identity_provider, mock_update_identity_provider, \
|
||||
mock_delete_identity_provider, mock_get_identity_provider_mappers, mock_create_identity_provider_mapper, \
|
||||
mock_update_identity_provider_mapper, mock_delete_identity_provider_mapper
|
||||
with patch.object(obj, 'get_realm_by_id', side_effect=get_realm_by_id) \
|
||||
as mock_get_realm_by_id:
|
||||
yield mock_get_identity_provider, mock_create_identity_provider, mock_update_identity_provider, \
|
||||
mock_delete_identity_provider, mock_get_identity_provider_mappers, mock_create_identity_provider_mapper, \
|
||||
mock_update_identity_provider_mapper, mock_delete_identity_provider_mapper, mock_get_realm_by_id
|
||||
|
||||
|
||||
def get_response(object_with_future_response, method, get_id_call_count):
|
||||
@@ -200,6 +202,38 @@ class TestKeycloakIdentityProvider(ModuleTestCase):
|
||||
"name": "last_name"
|
||||
}]
|
||||
]
|
||||
return_value_realm_get = [
|
||||
{
|
||||
'id': 'realm-name',
|
||||
'realm': 'realm-name',
|
||||
'enabled': True,
|
||||
'identityProviders': [
|
||||
{
|
||||
"addReadTokenRoleOnCreate": False,
|
||||
"alias": "oidc-idp",
|
||||
"authenticateByDefault": False,
|
||||
"config": {
|
||||
"authorizationUrl": "https://idp.example.com/auth",
|
||||
"clientAuthMethod": "client_secret_post",
|
||||
"clientId": "my-client",
|
||||
"clientSecret": "secret",
|
||||
"issuer": "https://idp.example.com",
|
||||
"syncMode": "FORCE",
|
||||
"tokenUrl": "https://idp.example.com/token",
|
||||
"userInfoUrl": "https://idp.example.com/userinfo"
|
||||
},
|
||||
"displayName": "OpenID Connect IdP",
|
||||
"enabled": True,
|
||||
"firstBrokerLoginFlowAlias": "first broker login",
|
||||
"internalId": "7ab437d5-f2bb-4ecc-91a8-315349454da6",
|
||||
"linkOnly": False,
|
||||
"providerId": "oidc",
|
||||
"storeToken": False,
|
||||
"trustEmail": False,
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
return_value_idp_created = [None]
|
||||
return_value_mapper_created = [None, None]
|
||||
changed = True
|
||||
@@ -210,15 +244,17 @@ class TestKeycloakIdentityProvider(ModuleTestCase):
|
||||
|
||||
with mock_good_connection():
|
||||
with patch_keycloak_api(get_identity_provider=return_value_idp_get, get_identity_provider_mappers=return_value_mappers_get,
|
||||
create_identity_provider=return_value_idp_created, create_identity_provider_mapper=return_value_mapper_created) \
|
||||
create_identity_provider=return_value_idp_created, create_identity_provider_mapper=return_value_mapper_created,
|
||||
get_realm_by_id=return_value_realm_get) \
|
||||
as (mock_get_identity_provider, mock_create_identity_provider, mock_update_identity_provider, mock_delete_identity_provider,
|
||||
mock_get_identity_provider_mappers, mock_create_identity_provider_mapper, mock_update_identity_provider_mapper,
|
||||
mock_delete_identity_provider_mapper):
|
||||
mock_delete_identity_provider_mapper, mock_get_realm_by_id):
|
||||
with self.assertRaises(AnsibleExitJson) as exec_info:
|
||||
self.module.main()
|
||||
|
||||
self.assertEqual(len(mock_get_identity_provider.mock_calls), 2)
|
||||
self.assertEqual(len(mock_get_identity_provider_mappers.mock_calls), 1)
|
||||
self.assertEqual(len(mock_get_realm_by_id.mock_calls), 1)
|
||||
self.assertEqual(len(mock_create_identity_provider.mock_calls), 1)
|
||||
self.assertEqual(len(mock_create_identity_provider_mapper.mock_calls), 2)
|
||||
|
||||
@@ -444,6 +480,68 @@ class TestKeycloakIdentityProvider(ModuleTestCase):
|
||||
"name": "last_name"
|
||||
}]
|
||||
]
|
||||
return_value_realm_get = [
|
||||
{
|
||||
'id': 'realm-name',
|
||||
'realm': 'realm-name',
|
||||
'enabled': True,
|
||||
'identityProviders': [
|
||||
{
|
||||
"addReadTokenRoleOnCreate": False,
|
||||
"alias": "oidc-idp",
|
||||
"authenticateByDefault": False,
|
||||
"config": {
|
||||
"authorizationUrl": "https://idp.example.com/auth",
|
||||
"clientAuthMethod": "client_secret_post",
|
||||
"clientId": "my-client",
|
||||
"clientSecret": "secret",
|
||||
"issuer": "https://idp.example.com",
|
||||
"syncMode": "FORCE",
|
||||
"tokenUrl": "https://idp.example.com/token",
|
||||
"userInfoUrl": "https://idp.example.com/userinfo"
|
||||
},
|
||||
"displayName": "OpenID Connect IdP",
|
||||
"enabled": True,
|
||||
"firstBrokerLoginFlowAlias": "first broker login",
|
||||
"internalId": "7ab437d5-f2bb-4ecc-91a8-315349454da6",
|
||||
"linkOnly": False,
|
||||
"providerId": "oidc",
|
||||
"storeToken": False,
|
||||
"trustEmail": False,
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
'id': 'realm-name',
|
||||
'realm': 'realm-name',
|
||||
'enabled': True,
|
||||
'identityProviders': [
|
||||
{
|
||||
"addReadTokenRoleOnCreate": False,
|
||||
"alias": "oidc-idp",
|
||||
"authenticateByDefault": False,
|
||||
"config": {
|
||||
"authorizationUrl": "https://idp.example.com/auth",
|
||||
"clientAuthMethod": "client_secret_post",
|
||||
"clientId": "my-client",
|
||||
"clientSecret": "secret",
|
||||
"issuer": "https://idp.example.com",
|
||||
"syncMode": "FORCE",
|
||||
"tokenUrl": "https://idp.example.com/token",
|
||||
"userInfoUrl": "https://idp.example.com/userinfo"
|
||||
},
|
||||
"displayName": "OpenID Connect IdP",
|
||||
"enabled": True,
|
||||
"firstBrokerLoginFlowAlias": "first broker login",
|
||||
"internalId": "7ab437d5-f2bb-4ecc-91a8-315349454da6",
|
||||
"linkOnly": False,
|
||||
"providerId": "oidc",
|
||||
"storeToken": False,
|
||||
"trustEmail": False,
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
return_value_idp_updated = [None]
|
||||
return_value_mapper_updated = [None]
|
||||
return_value_mapper_created = [None]
|
||||
@@ -456,15 +554,16 @@ class TestKeycloakIdentityProvider(ModuleTestCase):
|
||||
with mock_good_connection():
|
||||
with patch_keycloak_api(get_identity_provider=return_value_idp_get, get_identity_provider_mappers=return_value_mappers_get,
|
||||
update_identity_provider=return_value_idp_updated, update_identity_provider_mapper=return_value_mapper_updated,
|
||||
create_identity_provider_mapper=return_value_mapper_created) \
|
||||
create_identity_provider_mapper=return_value_mapper_created, get_realm_by_id=return_value_realm_get) \
|
||||
as (mock_get_identity_provider, mock_create_identity_provider, mock_update_identity_provider, mock_delete_identity_provider,
|
||||
mock_get_identity_provider_mappers, mock_create_identity_provider_mapper, mock_update_identity_provider_mapper,
|
||||
mock_delete_identity_provider_mapper):
|
||||
mock_delete_identity_provider_mapper, mock_get_realm_by_id):
|
||||
with self.assertRaises(AnsibleExitJson) as exec_info:
|
||||
self.module.main()
|
||||
|
||||
self.assertEqual(len(mock_get_identity_provider.mock_calls), 2)
|
||||
self.assertEqual(len(mock_get_identity_provider_mappers.mock_calls), 5)
|
||||
self.assertEqual(len(mock_get_realm_by_id.mock_calls), 2)
|
||||
self.assertEqual(len(mock_update_identity_provider.mock_calls), 1)
|
||||
self.assertEqual(len(mock_update_identity_provider_mapper.mock_calls), 1)
|
||||
self.assertEqual(len(mock_create_identity_provider_mapper.mock_calls), 1)
|
||||
@@ -472,6 +571,156 @@ class TestKeycloakIdentityProvider(ModuleTestCase):
|
||||
# Verify that the module's changed status matches what is expected
|
||||
self.assertIs(exec_info.exception.args[0]['changed'], changed)
|
||||
|
||||
def test_no_change_when_present(self):
|
||||
"""Update existing identity provider"""
|
||||
|
||||
module_args = {
|
||||
'auth_keycloak_url': 'http://keycloak.url/auth',
|
||||
'auth_password': 'admin',
|
||||
'auth_realm': 'master',
|
||||
'auth_username': 'admin',
|
||||
'auth_client_id': 'admin-cli',
|
||||
"addReadTokenRoleOnCreate": False,
|
||||
"alias": "oidc-idp",
|
||||
"authenticateByDefault": False,
|
||||
"config": {
|
||||
"authorizationUrl": "https://idp.example.com/auth",
|
||||
"clientAuthMethod": "client_secret_post",
|
||||
"clientId": "my-client",
|
||||
"clientSecret": "secret",
|
||||
"issuer": "https://idp.example.com",
|
||||
"syncMode": "FORCE",
|
||||
"tokenUrl": "https://idp.example.com/token",
|
||||
"userInfoUrl": "https://idp.example.com/userinfo"
|
||||
},
|
||||
"displayName": "OpenID Connect IdP changeme",
|
||||
"enabled": True,
|
||||
"firstBrokerLoginFlowAlias": "first broker login",
|
||||
"linkOnly": False,
|
||||
"providerId": "oidc",
|
||||
"storeToken": False,
|
||||
"trustEmail": False,
|
||||
'mappers': [{
|
||||
'name': "username",
|
||||
'identityProviderAlias': "oidc-idp",
|
||||
'identityProviderMapper': "oidc-user-attribute-idp-mapper",
|
||||
'config': {
|
||||
'claim': "username",
|
||||
'user.attribute': "username",
|
||||
'syncMode': "INHERIT",
|
||||
}
|
||||
}]
|
||||
}
|
||||
return_value_idp_get = [
|
||||
{
|
||||
"addReadTokenRoleOnCreate": False,
|
||||
"alias": "oidc-idp",
|
||||
"authenticateByDefault": False,
|
||||
"config": {
|
||||
"authorizationUrl": "https://idp.example.com/auth",
|
||||
"clientAuthMethod": "client_secret_post",
|
||||
"clientId": "my-client",
|
||||
"clientSecret": "**********",
|
||||
"issuer": "https://idp.example.com",
|
||||
"syncMode": "FORCE",
|
||||
"tokenUrl": "https://idp.example.com/token",
|
||||
"userInfoUrl": "https://idp.example.com/userinfo"
|
||||
},
|
||||
"displayName": "OpenID Connect IdP changeme",
|
||||
"enabled": True,
|
||||
"firstBrokerLoginFlowAlias": "first broker login",
|
||||
"internalId": "7ab437d5-f2bb-4ecc-91a8-315349454da6",
|
||||
"linkOnly": False,
|
||||
"providerId": "oidc",
|
||||
"storeToken": False,
|
||||
"trustEmail": False,
|
||||
},
|
||||
]
|
||||
return_value_mappers_get = [
|
||||
[{
|
||||
'config': {
|
||||
'claim': "username",
|
||||
'syncMode': "INHERIT",
|
||||
'user.attribute': "username"
|
||||
},
|
||||
"id": "616f11ba-b9ae-42ae-bd1b-bc618741c10b",
|
||||
'identityProviderAlias': "oidc-idp",
|
||||
'identityProviderMapper': "oidc-user-attribute-idp-mapper",
|
||||
'name': "username"
|
||||
}],
|
||||
[{
|
||||
'config': {
|
||||
'claim': "username",
|
||||
'syncMode': "INHERIT",
|
||||
'user.attribute': "username"
|
||||
},
|
||||
"id": "616f11ba-b9ae-42ae-bd1b-bc618741c10b",
|
||||
'identityProviderAlias': "oidc-idp",
|
||||
'identityProviderMapper': "oidc-user-attribute-idp-mapper",
|
||||
'name': "username"
|
||||
}]
|
||||
]
|
||||
return_value_realm_get = [
|
||||
{
|
||||
'id': 'realm-name',
|
||||
'realm': 'realm-name',
|
||||
'enabled': True,
|
||||
'identityProviders': [
|
||||
{
|
||||
"addReadTokenRoleOnCreate": False,
|
||||
"alias": "oidc-idp",
|
||||
"authenticateByDefault": False,
|
||||
"config": {
|
||||
"authorizationUrl": "https://idp.example.com/auth",
|
||||
"clientAuthMethod": "client_secret_post",
|
||||
"clientId": "my-client",
|
||||
"clientSecret": "secret",
|
||||
"issuer": "https://idp.example.com",
|
||||
"syncMode": "FORCE",
|
||||
"tokenUrl": "https://idp.example.com/token",
|
||||
"userInfoUrl": "https://idp.example.com/userinfo"
|
||||
},
|
||||
"displayName": "OpenID Connect IdP",
|
||||
"enabled": True,
|
||||
"firstBrokerLoginFlowAlias": "first broker login",
|
||||
"internalId": "7ab437d5-f2bb-4ecc-91a8-315349454da6",
|
||||
"linkOnly": False,
|
||||
"providerId": "oidc",
|
||||
"storeToken": False,
|
||||
"trustEmail": False,
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
return_value_idp_updated = [None]
|
||||
return_value_mapper_updated = [None]
|
||||
return_value_mapper_created = [None]
|
||||
changed = False
|
||||
|
||||
set_module_args(module_args)
|
||||
|
||||
# Run the module
|
||||
|
||||
with mock_good_connection():
|
||||
with patch_keycloak_api(get_identity_provider=return_value_idp_get, get_identity_provider_mappers=return_value_mappers_get,
|
||||
update_identity_provider=return_value_idp_updated, update_identity_provider_mapper=return_value_mapper_updated,
|
||||
create_identity_provider_mapper=return_value_mapper_created, get_realm_by_id=return_value_realm_get) \
|
||||
as (mock_get_identity_provider, mock_create_identity_provider, mock_update_identity_provider, mock_delete_identity_provider,
|
||||
mock_get_identity_provider_mappers, mock_create_identity_provider_mapper, mock_update_identity_provider_mapper,
|
||||
mock_delete_identity_provider_mapper, mock_get_realm_by_id):
|
||||
with self.assertRaises(AnsibleExitJson) as exec_info:
|
||||
self.module.main()
|
||||
|
||||
self.assertEqual(len(mock_get_identity_provider.mock_calls), 1)
|
||||
self.assertEqual(len(mock_get_identity_provider_mappers.mock_calls), 2)
|
||||
self.assertEqual(len(mock_get_realm_by_id.mock_calls), 1)
|
||||
self.assertEqual(len(mock_update_identity_provider.mock_calls), 0)
|
||||
self.assertEqual(len(mock_update_identity_provider_mapper.mock_calls), 0)
|
||||
self.assertEqual(len(mock_create_identity_provider_mapper.mock_calls), 0)
|
||||
|
||||
# Verify that the module's changed status matches what is expected
|
||||
self.assertIs(exec_info.exception.args[0]['changed'], changed)
|
||||
|
||||
def test_delete_when_absent(self):
|
||||
"""Remove an absent identity provider"""
|
||||
|
||||
@@ -497,7 +746,7 @@ class TestKeycloakIdentityProvider(ModuleTestCase):
|
||||
with patch_keycloak_api(get_identity_provider=return_value_idp_get) \
|
||||
as (mock_get_identity_provider, mock_create_identity_provider, mock_update_identity_provider, mock_delete_identity_provider,
|
||||
mock_get_identity_provider_mappers, mock_create_identity_provider_mapper, mock_update_identity_provider_mapper,
|
||||
mock_delete_identity_provider_mapper):
|
||||
mock_delete_identity_provider_mapper, mock_get_realm_by_id):
|
||||
with self.assertRaises(AnsibleExitJson) as exec_info:
|
||||
self.module.main()
|
||||
|
||||
@@ -560,6 +809,38 @@ class TestKeycloakIdentityProvider(ModuleTestCase):
|
||||
"name": "email"
|
||||
}]
|
||||
]
|
||||
return_value_realm_get = [
|
||||
{
|
||||
'id': 'realm-name',
|
||||
'realm': 'realm-name',
|
||||
'enabled': True,
|
||||
'identityProviders': [
|
||||
{
|
||||
"alias": "oidc",
|
||||
"displayName": "",
|
||||
"internalId": "2bca4192-e816-4beb-bcba-190164eb55b8",
|
||||
"providerId": "oidc",
|
||||
"enabled": True,
|
||||
"updateProfileFirstLoginMode": "on",
|
||||
"trustEmail": False,
|
||||
"storeToken": False,
|
||||
"addReadTokenRoleOnCreate": False,
|
||||
"authenticateByDefault": False,
|
||||
"linkOnly": False,
|
||||
"config": {
|
||||
"validateSignature": "false",
|
||||
"pkceEnabled": "false",
|
||||
"tokenUrl": "https://localhost:8000",
|
||||
"clientId": "asdf",
|
||||
"authorizationUrl": "https://localhost:8000",
|
||||
"clientAuthMethod": "client_secret_post",
|
||||
"clientSecret": "real_secret",
|
||||
"guiOrder": "0"
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
return_value_idp_deleted = [None]
|
||||
changed = True
|
||||
|
||||
@@ -569,15 +850,16 @@ class TestKeycloakIdentityProvider(ModuleTestCase):
|
||||
|
||||
with mock_good_connection():
|
||||
with patch_keycloak_api(get_identity_provider=return_value_idp_get, get_identity_provider_mappers=return_value_mappers_get,
|
||||
delete_identity_provider=return_value_idp_deleted) \
|
||||
delete_identity_provider=return_value_idp_deleted, get_realm_by_id=return_value_realm_get) \
|
||||
as (mock_get_identity_provider, mock_create_identity_provider, mock_update_identity_provider, mock_delete_identity_provider,
|
||||
mock_get_identity_provider_mappers, mock_create_identity_provider_mapper, mock_update_identity_provider_mapper,
|
||||
mock_delete_identity_provider_mapper):
|
||||
mock_delete_identity_provider_mapper, mock_get_realm_by_id):
|
||||
with self.assertRaises(AnsibleExitJson) as exec_info:
|
||||
self.module.main()
|
||||
|
||||
self.assertEqual(len(mock_get_identity_provider.mock_calls), 1)
|
||||
self.assertEqual(len(mock_get_identity_provider_mappers.mock_calls), 1)
|
||||
self.assertEqual(len(mock_get_realm_by_id.mock_calls), 1)
|
||||
self.assertEqual(len(mock_delete_identity_provider.mock_calls), 1)
|
||||
|
||||
# Verify that the module's changed status matches what is expected
|
||||
|
||||
380
tests/unit/plugins/modules/test_keycloak_realm_keys.py
Normal file
380
tests/unit/plugins/modules/test_keycloak_realm_keys.py
Normal file
@@ -0,0 +1,380 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# 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
|
||||
|
||||
from contextlib import contextmanager
|
||||
|
||||
from ansible_collections.community.general.tests.unit.compat import unittest
|
||||
from ansible_collections.community.general.tests.unit.compat.mock import patch
|
||||
from ansible_collections.community.general.tests.unit.plugins.modules.utils import AnsibleExitJson, ModuleTestCase, set_module_args
|
||||
|
||||
from ansible_collections.community.general.plugins.modules import keycloak_realm_key
|
||||
|
||||
from itertools import count
|
||||
|
||||
from ansible.module_utils.six import StringIO
|
||||
|
||||
|
||||
@contextmanager
|
||||
def patch_keycloak_api(get_components=None, get_component=None, create_component=None, update_component=None, delete_component=None):
|
||||
"""Mock context manager for patching the methods in KeycloakAPI
|
||||
"""
|
||||
|
||||
obj = keycloak_realm_key.KeycloakAPI
|
||||
with patch.object(obj, 'get_components', side_effect=get_components) \
|
||||
as mock_get_components:
|
||||
with patch.object(obj, 'get_component', side_effect=get_component) \
|
||||
as mock_get_component:
|
||||
with patch.object(obj, 'create_component', side_effect=create_component) \
|
||||
as mock_create_component:
|
||||
with patch.object(obj, 'update_component', side_effect=update_component) \
|
||||
as mock_update_component:
|
||||
with patch.object(obj, 'delete_component', side_effect=delete_component) \
|
||||
as mock_delete_component:
|
||||
yield mock_get_components, mock_get_component, mock_create_component, mock_update_component, mock_delete_component
|
||||
|
||||
|
||||
def get_response(object_with_future_response, method, get_id_call_count):
|
||||
if callable(object_with_future_response):
|
||||
return object_with_future_response()
|
||||
if isinstance(object_with_future_response, dict):
|
||||
return get_response(
|
||||
object_with_future_response[method], method, get_id_call_count)
|
||||
if isinstance(object_with_future_response, list):
|
||||
call_number = next(get_id_call_count)
|
||||
return get_response(
|
||||
object_with_future_response[call_number], method, get_id_call_count)
|
||||
return object_with_future_response
|
||||
|
||||
|
||||
def build_mocked_request(get_id_user_count, response_dict):
|
||||
def _mocked_requests(*args, **kwargs):
|
||||
url = args[0]
|
||||
method = kwargs['method']
|
||||
future_response = response_dict.get(url, None)
|
||||
return get_response(future_response, method, get_id_user_count)
|
||||
return _mocked_requests
|
||||
|
||||
|
||||
def create_wrapper(text_as_string):
|
||||
"""Allow to mock many times a call to one address.
|
||||
Without this function, the StringIO is empty for the second call.
|
||||
"""
|
||||
def _create_wrapper():
|
||||
return StringIO(text_as_string)
|
||||
return _create_wrapper
|
||||
|
||||
|
||||
def mock_good_connection():
|
||||
token_response = {
|
||||
'http://keycloak.url/auth/realms/master/protocol/openid-connect/token': create_wrapper('{"access_token": "alongtoken"}'), }
|
||||
return patch(
|
||||
'ansible_collections.community.general.plugins.module_utils.identity.keycloak.keycloak.open_url',
|
||||
side_effect=build_mocked_request(count(), token_response),
|
||||
autospec=True
|
||||
)
|
||||
|
||||
|
||||
class TestKeycloakRealmKeys(ModuleTestCase):
|
||||
def setUp(self):
|
||||
super(TestKeycloakRealmKeys, self).setUp()
|
||||
self.module = keycloak_realm_key
|
||||
|
||||
def test_create_when_absent(self):
|
||||
"""Add a new realm key"""
|
||||
|
||||
module_args = {
|
||||
'auth_keycloak_url': 'http://keycloak.url/auth',
|
||||
'auth_realm': 'master',
|
||||
'auth_username': 'admin',
|
||||
'auth_password': 'admin',
|
||||
'parent_id': 'realm-name',
|
||||
'name': 'testkey',
|
||||
'state': 'present',
|
||||
'provider_id': 'rsa',
|
||||
'config': {
|
||||
'priority': 0,
|
||||
'enabled': True,
|
||||
'private_key': 'privatekey',
|
||||
'algorithm': 'RS256',
|
||||
'certificate': 'foo',
|
||||
},
|
||||
}
|
||||
return_value_component_create = [
|
||||
{
|
||||
"id": "ebb7d999-60cc-4dfe-ab79-48f7bbd9d4d9",
|
||||
"name": "testkey",
|
||||
"providerId": "rsa",
|
||||
"parentId": "90c8fef9-15f8-4d5b-8b22-44e2e1cdcd09",
|
||||
"config": {
|
||||
"privateKey": [
|
||||
"**********"
|
||||
],
|
||||
"certificate": [
|
||||
"foo"
|
||||
],
|
||||
"active": [
|
||||
"true"
|
||||
],
|
||||
"priority": [
|
||||
"122"
|
||||
],
|
||||
"enabled": [
|
||||
"true"
|
||||
],
|
||||
"algorithm": [
|
||||
"RS256"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
# get before_comp, get default_mapper, get after_mapper
|
||||
return_value_components_get = [
|
||||
[], [], []
|
||||
]
|
||||
changed = True
|
||||
|
||||
set_module_args(module_args)
|
||||
|
||||
# Run the module
|
||||
|
||||
with mock_good_connection():
|
||||
with patch_keycloak_api(get_components=return_value_components_get, create_component=return_value_component_create) \
|
||||
as (mock_get_components, mock_get_component, mock_create_component, mock_update_component, mock_delete_component):
|
||||
with self.assertRaises(AnsibleExitJson) as exec_info:
|
||||
self.module.main()
|
||||
|
||||
self.assertEqual(len(mock_get_components.mock_calls), 1)
|
||||
self.assertEqual(len(mock_get_component.mock_calls), 0)
|
||||
self.assertEqual(len(mock_create_component.mock_calls), 1)
|
||||
self.assertEqual(len(mock_update_component.mock_calls), 0)
|
||||
self.assertEqual(len(mock_delete_component.mock_calls), 0)
|
||||
|
||||
# must not contain parent_id
|
||||
mock_create_component.assert_called_once_with({
|
||||
'name': 'testkey',
|
||||
'providerId': 'rsa',
|
||||
'providerType': 'org.keycloak.keys.KeyProvider',
|
||||
'config': {
|
||||
'priority': ['0'],
|
||||
'enabled': ['true'],
|
||||
'privateKey': ['privatekey'],
|
||||
'algorithm': ['RS256'],
|
||||
'certificate': ['foo'],
|
||||
'active': ['true'],
|
||||
},
|
||||
}, 'realm-name')
|
||||
|
||||
# Verify that the module's changed status matches what is expected
|
||||
self.assertIs(exec_info.exception.args[0]['changed'], changed)
|
||||
|
||||
def test_create_when_present(self):
|
||||
"""Update existing realm key"""
|
||||
|
||||
module_args = {
|
||||
'auth_keycloak_url': 'http://keycloak.url/auth',
|
||||
'auth_realm': 'master',
|
||||
'auth_username': 'admin',
|
||||
'auth_password': 'admin',
|
||||
'parent_id': 'realm-name',
|
||||
'name': 'testkey',
|
||||
'state': 'present',
|
||||
'provider_id': 'rsa',
|
||||
'config': {
|
||||
'priority': 0,
|
||||
'enabled': True,
|
||||
'private_key': 'privatekey',
|
||||
'algorithm': 'RS256',
|
||||
'certificate': 'foo',
|
||||
},
|
||||
}
|
||||
return_value_components_get = [
|
||||
[
|
||||
|
||||
{
|
||||
"id": "c1a957aa-3df0-4f70-9418-44202bf4ae1f",
|
||||
"name": "testkey",
|
||||
"providerId": "rsa",
|
||||
"providerType": "org.keycloak.keys.KeyProvider",
|
||||
"parentId": "90c8fef9-15f8-4d5b-8b22-44e2e1cdcd09",
|
||||
"config": {
|
||||
"privateKey": [
|
||||
"**********"
|
||||
],
|
||||
"certificate": [
|
||||
"foo"
|
||||
],
|
||||
"active": [
|
||||
"true"
|
||||
],
|
||||
"priority": [
|
||||
"122"
|
||||
],
|
||||
"enabled": [
|
||||
"true"
|
||||
],
|
||||
"algorithm": [
|
||||
"RS256"
|
||||
]
|
||||
}
|
||||
},
|
||||
],
|
||||
[],
|
||||
[]
|
||||
]
|
||||
return_value_component_update = [
|
||||
None
|
||||
]
|
||||
changed = True
|
||||
|
||||
set_module_args(module_args)
|
||||
|
||||
# Run the module
|
||||
|
||||
with mock_good_connection():
|
||||
with patch_keycloak_api(get_components=return_value_components_get,
|
||||
update_component=return_value_component_update) \
|
||||
as (mock_get_components, mock_get_component, mock_create_component, mock_update_component, mock_delete_component):
|
||||
with self.assertRaises(AnsibleExitJson) as exec_info:
|
||||
self.module.main()
|
||||
|
||||
self.assertEqual(len(mock_get_components.mock_calls), 1)
|
||||
self.assertEqual(len(mock_get_component.mock_calls), 0)
|
||||
self.assertEqual(len(mock_create_component.mock_calls), 0)
|
||||
self.assertEqual(len(mock_update_component.mock_calls), 1)
|
||||
self.assertEqual(len(mock_delete_component.mock_calls), 0)
|
||||
|
||||
# Verify that the module's changed status matches what is expected
|
||||
self.assertIs(exec_info.exception.args[0]['changed'], changed)
|
||||
|
||||
def test_delete_when_absent(self):
|
||||
"""Remove an absent realm key"""
|
||||
|
||||
module_args = {
|
||||
'auth_keycloak_url': 'http://keycloak.url/auth',
|
||||
'auth_realm': 'master',
|
||||
'auth_username': 'admin',
|
||||
'auth_password': 'admin',
|
||||
'parent_id': 'realm-name',
|
||||
'name': 'testkey',
|
||||
'state': 'absent',
|
||||
'provider_id': 'rsa',
|
||||
'config': {
|
||||
'priority': 0,
|
||||
'enabled': True,
|
||||
'private_key': 'privatekey',
|
||||
'algorithm': 'RS256',
|
||||
'certificate': 'foo',
|
||||
},
|
||||
}
|
||||
return_value_components_get = [
|
||||
[]
|
||||
]
|
||||
changed = False
|
||||
|
||||
set_module_args(module_args)
|
||||
|
||||
# Run the module
|
||||
|
||||
with mock_good_connection():
|
||||
with patch_keycloak_api(get_components=return_value_components_get) \
|
||||
as (mock_get_components, mock_get_component, mock_create_component, mock_update_component, mock_delete_component):
|
||||
with self.assertRaises(AnsibleExitJson) as exec_info:
|
||||
self.module.main()
|
||||
|
||||
self.assertEqual(len(mock_get_components.mock_calls), 1)
|
||||
self.assertEqual(len(mock_get_component.mock_calls), 0)
|
||||
self.assertEqual(len(mock_create_component.mock_calls), 0)
|
||||
self.assertEqual(len(mock_update_component.mock_calls), 0)
|
||||
self.assertEqual(len(mock_delete_component.mock_calls), 0)
|
||||
|
||||
# Verify that the module's changed status matches what is expected
|
||||
self.assertIs(exec_info.exception.args[0]['changed'], changed)
|
||||
|
||||
def test_delete_when_present(self):
|
||||
"""Remove an existing realm key"""
|
||||
|
||||
module_args = {
|
||||
'auth_keycloak_url': 'http://keycloak.url/auth',
|
||||
'auth_realm': 'master',
|
||||
'auth_username': 'admin',
|
||||
'auth_password': 'admin',
|
||||
'parent_id': 'realm-name',
|
||||
'name': 'testkey',
|
||||
'state': 'absent',
|
||||
'provider_id': 'rsa',
|
||||
'config': {
|
||||
'priority': 0,
|
||||
'enabled': True,
|
||||
'private_key': 'privatekey',
|
||||
'algorithm': 'RS256',
|
||||
'certificate': 'foo',
|
||||
},
|
||||
}
|
||||
|
||||
return_value_components_get = [
|
||||
[
|
||||
|
||||
{
|
||||
"id": "c1a957aa-3df0-4f70-9418-44202bf4ae1f",
|
||||
"name": "testkey",
|
||||
"providerId": "rsa",
|
||||
"providerType": "org.keycloak.keys.KeyProvider",
|
||||
"parentId": "90c8fef9-15f8-4d5b-8b22-44e2e1cdcd09",
|
||||
"config": {
|
||||
"privateKey": [
|
||||
"**********"
|
||||
],
|
||||
"certificate": [
|
||||
"foo"
|
||||
],
|
||||
"active": [
|
||||
"true"
|
||||
],
|
||||
"priority": [
|
||||
"122"
|
||||
],
|
||||
"enabled": [
|
||||
"true"
|
||||
],
|
||||
"algorithm": [
|
||||
"RS256"
|
||||
]
|
||||
}
|
||||
},
|
||||
],
|
||||
[],
|
||||
[]
|
||||
]
|
||||
return_value_component_delete = [
|
||||
None
|
||||
]
|
||||
changed = True
|
||||
|
||||
set_module_args(module_args)
|
||||
|
||||
# Run the module
|
||||
|
||||
with mock_good_connection():
|
||||
with patch_keycloak_api(get_components=return_value_components_get, delete_component=return_value_component_delete) \
|
||||
as (mock_get_components, mock_get_component, mock_create_component, mock_update_component, mock_delete_component):
|
||||
with self.assertRaises(AnsibleExitJson) as exec_info:
|
||||
self.module.main()
|
||||
|
||||
self.assertEqual(len(mock_get_components.mock_calls), 1)
|
||||
self.assertEqual(len(mock_get_component.mock_calls), 0)
|
||||
self.assertEqual(len(mock_create_component.mock_calls), 0)
|
||||
self.assertEqual(len(mock_update_component.mock_calls), 0)
|
||||
self.assertEqual(len(mock_delete_component.mock_calls), 1)
|
||||
|
||||
# Verify that the module's changed status matches what is expected
|
||||
self.assertIs(exec_info.exception.args[0]['changed'], changed)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -144,8 +144,9 @@ class TestKeycloakUserFederation(ModuleTestCase):
|
||||
}
|
||||
}
|
||||
]
|
||||
# get before_comp, get default_mapper, get after_mapper
|
||||
return_value_components_get = [
|
||||
[], []
|
||||
[], [], []
|
||||
]
|
||||
changed = True
|
||||
|
||||
@@ -159,7 +160,7 @@ class TestKeycloakUserFederation(ModuleTestCase):
|
||||
with self.assertRaises(AnsibleExitJson) as exec_info:
|
||||
self.module.main()
|
||||
|
||||
self.assertEqual(len(mock_get_components.mock_calls), 1)
|
||||
self.assertEqual(len(mock_get_components.mock_calls), 3)
|
||||
self.assertEqual(len(mock_get_component.mock_calls), 0)
|
||||
self.assertEqual(len(mock_create_component.mock_calls), 1)
|
||||
self.assertEqual(len(mock_update_component.mock_calls), 0)
|
||||
@@ -228,6 +229,7 @@ class TestKeycloakUserFederation(ModuleTestCase):
|
||||
}
|
||||
}
|
||||
],
|
||||
[],
|
||||
[]
|
||||
]
|
||||
return_value_component_get = [
|
||||
@@ -281,7 +283,7 @@ class TestKeycloakUserFederation(ModuleTestCase):
|
||||
with self.assertRaises(AnsibleExitJson) as exec_info:
|
||||
self.module.main()
|
||||
|
||||
self.assertEqual(len(mock_get_components.mock_calls), 2)
|
||||
self.assertEqual(len(mock_get_components.mock_calls), 3)
|
||||
self.assertEqual(len(mock_get_component.mock_calls), 1)
|
||||
self.assertEqual(len(mock_create_component.mock_calls), 0)
|
||||
self.assertEqual(len(mock_update_component.mock_calls), 1)
|
||||
@@ -344,7 +346,47 @@ class TestKeycloakUserFederation(ModuleTestCase):
|
||||
]
|
||||
}
|
||||
return_value_components_get = [
|
||||
[], []
|
||||
[],
|
||||
# exemplary default mapper created by keylocak
|
||||
[
|
||||
{
|
||||
"config": {
|
||||
"always.read.value.from.ldap": "false",
|
||||
"is.mandatory.in.ldap": "false",
|
||||
"ldap.attribute": "mail",
|
||||
"read.only": "true",
|
||||
"user.model.attribute": "email"
|
||||
},
|
||||
"id": "77e1763f-c51a-4286-bade-75577d64803c",
|
||||
"name": "email",
|
||||
"parentId": "e5f48aa3-b56b-4983-a8ad-2c7b8b5e77cb",
|
||||
"providerId": "user-attribute-ldap-mapper",
|
||||
"providerType": "org.keycloak.storage.ldap.mappers.LDAPStorageMapper"
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
"id": "2dfadafd-8b34-495f-a98b-153e71a22311",
|
||||
"name": "full name",
|
||||
"providerId": "full-name-ldap-mapper",
|
||||
"providerType": "org.keycloak.storage.ldap.mappers.LDAPStorageMapper",
|
||||
"parentId": "eb691537-b73c-4cd8-b481-6031c26499d8",
|
||||
"config": {
|
||||
"ldap.full.name.attribute": [
|
||||
"cn"
|
||||
],
|
||||
"read.only": [
|
||||
"true"
|
||||
],
|
||||
"write.only": [
|
||||
"false"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
return_value_component_delete = [
|
||||
None
|
||||
]
|
||||
return_value_component_create = [
|
||||
{
|
||||
@@ -462,11 +504,11 @@ class TestKeycloakUserFederation(ModuleTestCase):
|
||||
with self.assertRaises(AnsibleExitJson) as exec_info:
|
||||
self.module.main()
|
||||
|
||||
self.assertEqual(len(mock_get_components.mock_calls), 2)
|
||||
self.assertEqual(len(mock_get_components.mock_calls), 3)
|
||||
self.assertEqual(len(mock_get_component.mock_calls), 0)
|
||||
self.assertEqual(len(mock_create_component.mock_calls), 2)
|
||||
self.assertEqual(len(mock_update_component.mock_calls), 0)
|
||||
self.assertEqual(len(mock_delete_component.mock_calls), 0)
|
||||
self.assertEqual(len(mock_delete_component.mock_calls), 1)
|
||||
|
||||
# Verify that the module's changed status matches what is expected
|
||||
self.assertIs(exec_info.exception.args[0]['changed'], changed)
|
||||
|
||||
Reference in New Issue
Block a user