mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-04-30 10:26:52 +00:00
Compare commits
88 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d481a6b0d4 | ||
|
|
7a9253e68b | ||
|
|
7945d5afbe | ||
|
|
c28021b662 | ||
|
|
3dd39fedd2 | ||
|
|
6d8549f00a | ||
|
|
805362f337 | ||
|
|
c0b5119034 | ||
|
|
fd8a452f22 | ||
|
|
6d46e650b7 | ||
|
|
b4468bd4c7 | ||
|
|
e2af16b03f | ||
|
|
3abf169a2f | ||
|
|
5039265621 | ||
|
|
b52b754a3d | ||
|
|
9aef7ad67e | ||
|
|
0e15608149 | ||
|
|
844e3a581c | ||
|
|
3c86bb9cda | ||
|
|
8222f1f064 | ||
|
|
78e552469a | ||
|
|
acdf0cdc2f | ||
|
|
1246c3357b | ||
|
|
c5f939fbc5 | ||
|
|
666c07acee | ||
|
|
bcbd04a8fd | ||
|
|
36cb2c22a1 | ||
|
|
419893eb65 | ||
|
|
2448503e8b | ||
|
|
8b1a193a49 | ||
|
|
69bb4420d8 | ||
|
|
69590f55ac | ||
|
|
69cb9b7578 | ||
|
|
72e4deee9b | ||
|
|
f12f69d2a5 | ||
|
|
ff7a8f8018 | ||
|
|
08cfbf4f99 | ||
|
|
513ea79c19 | ||
|
|
0409f4048b | ||
|
|
3aa6185f09 | ||
|
|
9a7fb38301 | ||
|
|
0b33bf4e5a | ||
|
|
961a7cea8b | ||
|
|
7916877179 | ||
|
|
7df07f31a6 | ||
|
|
928cdaaf87 | ||
|
|
3727bf7cd4 | ||
|
|
845b13d5aa | ||
|
|
fa3e6673d0 | ||
|
|
84033ec80a | ||
|
|
3bceabce93 | ||
|
|
0dd960d8ab | ||
|
|
e1b338cf41 | ||
|
|
f2e8354229 | ||
|
|
abc435466d | ||
|
|
3c49c096a9 | ||
|
|
de754eacbc | ||
|
|
0ccb961ff7 | ||
|
|
c6429e7740 | ||
|
|
ba7439e657 | ||
|
|
013fb9c006 | ||
|
|
9a6bd80613 | ||
|
|
17d11cb587 | ||
|
|
933166b984 | ||
|
|
162add04b9 | ||
|
|
faaeacfaa0 | ||
|
|
bbf3cae316 | ||
|
|
53ebbe4b94 | ||
|
|
2674e2494d | ||
|
|
341f86e2bc | ||
|
|
dd63fb5347 | ||
|
|
b418b2c00d | ||
|
|
382c0a4af6 | ||
|
|
1a0a44d179 | ||
|
|
18e4637042 | ||
|
|
fb68abd6b2 | ||
|
|
2d5999c579 | ||
|
|
525ed41a0a | ||
|
|
4a4fe8c61f | ||
|
|
f9e4bc85e9 | ||
|
|
bde1c721e0 | ||
|
|
285c97e7ea | ||
|
|
d45a889c3f | ||
|
|
1e7294716e | ||
|
|
88c605a344 | ||
|
|
4a41ab583a | ||
|
|
5d86045048 | ||
|
|
2eb067e3e0 |
@@ -43,8 +43,6 @@ variables:
|
||||
value: ansible_collections/community/general
|
||||
- name: coverageBranches
|
||||
value: main
|
||||
- name: pipelinesCoverage
|
||||
value: coverage
|
||||
- name: entryPoint
|
||||
value: tests/utils/shippable/shippable.sh
|
||||
- name: fetchDepth
|
||||
@@ -72,7 +70,6 @@ stages:
|
||||
- test: 2
|
||||
- test: 3
|
||||
- test: 4
|
||||
- test: extra
|
||||
- stage: Sanity_2_18
|
||||
displayName: Sanity 2.18
|
||||
dependsOn: []
|
||||
@@ -190,14 +187,14 @@ stages:
|
||||
parameters:
|
||||
testFormat: devel/{0}
|
||||
targets:
|
||||
- name: macOS 14.3
|
||||
test: macos/14.3
|
||||
- name: macOS 15.3
|
||||
test: macos/15.3
|
||||
- name: RHEL 9.5
|
||||
test: rhel/9.5
|
||||
- name: FreeBSD 14.2
|
||||
test: freebsd/14.2
|
||||
- name: FreeBSD 13.4
|
||||
test: freebsd/13.4
|
||||
- name: FreeBSD 13.5
|
||||
test: freebsd/13.5
|
||||
groups:
|
||||
- 1
|
||||
- 2
|
||||
@@ -210,6 +207,8 @@ stages:
|
||||
parameters:
|
||||
testFormat: 2.18/{0}
|
||||
targets:
|
||||
- name: macOS 14.3
|
||||
test: macos/14.3
|
||||
- name: RHEL 9.4
|
||||
test: rhel/9.4
|
||||
- name: FreeBSD 14.1
|
||||
@@ -230,8 +229,6 @@ stages:
|
||||
test: freebsd/13.3
|
||||
- name: RHEL 9.3
|
||||
test: rhel/9.3
|
||||
- name: FreeBSD 14.0
|
||||
test: freebsd/14.0
|
||||
groups:
|
||||
- 1
|
||||
- 2
|
||||
|
||||
@@ -28,16 +28,6 @@ jobs:
|
||||
- bash: .azure-pipelines/scripts/report-coverage.sh
|
||||
displayName: Generate Coverage Report
|
||||
condition: gt(variables.coverageFileCount, 0)
|
||||
- task: PublishCodeCoverageResults@1
|
||||
inputs:
|
||||
codeCoverageTool: Cobertura
|
||||
# Azure Pipelines only accepts a single coverage data file.
|
||||
# That means only Python or PowerShell coverage can be uploaded, but not both.
|
||||
# Set the "pipelinesCoverage" variable to determine which type is uploaded.
|
||||
# Use "coverage" for Python and "coverage-powershell" for PowerShell.
|
||||
summaryFileLocation: "$(outputPath)/reports/$(pipelinesCoverage).xml"
|
||||
displayName: Publish to Azure Pipelines
|
||||
condition: gt(variables.coverageFileCount, 0)
|
||||
- bash: .azure-pipelines/scripts/publish-codecov.py "$(outputPath)"
|
||||
displayName: Publish to codecov.io
|
||||
condition: gt(variables.coverageFileCount, 0)
|
||||
|
||||
7
.github/workflows/ansible-test.yml
vendored
7
.github/workflows/ansible-test.yml
vendored
@@ -47,6 +47,8 @@ jobs:
|
||||
coverage: ${{ github.event_name == 'schedule' && 'always' || 'never' }}
|
||||
pull-request-change-detection: 'true'
|
||||
testing-type: sanity
|
||||
pre-test-cmd: >-
|
||||
git clone --depth=1 --single-branch https://github.com/ansible-collections/community.internal_test_tools.git ../../community/internal_test_tools
|
||||
|
||||
units:
|
||||
# Ansible-test on various stable branches does not yet work well with cgroups v2.
|
||||
@@ -212,12 +214,15 @@ jobs:
|
||||
integration-continue-on-error: 'false'
|
||||
integration-diff: 'false'
|
||||
integration-retry-on-error: 'true'
|
||||
# TODO: remove "--branch stable-2" from community.crypto install once we're only using ansible-core 2.17 or newer!
|
||||
pre-test-cmd: >-
|
||||
mkdir -p ../../ansible
|
||||
;
|
||||
git clone --depth=1 --single-branch https://github.com/ansible-collections/ansible.posix.git ../../ansible/posix
|
||||
;
|
||||
git clone --depth=1 --single-branch https://github.com/ansible-collections/community.crypto.git ../../community/crypto
|
||||
git clone --depth=1 --single-branch --branch stable-2 https://github.com/ansible-collections/community.crypto.git ../../community/crypto
|
||||
;
|
||||
git clone --depth=1 --single-branch https://github.com/ansible-collections/community.docker.git ../../community/docker
|
||||
;
|
||||
git clone --depth=1 --single-branch https://github.com/ansible-collections/community.internal_test_tools.git ../../community/internal_test_tools
|
||||
pull-request-change-detection: 'true'
|
||||
|
||||
20
.github/workflows/import-galaxy.yml
vendored
20
.github/workflows/import-galaxy.yml
vendored
@@ -1,20 +0,0 @@
|
||||
---
|
||||
# Copyright (c) Ansible Project
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
name: import-galaxy
|
||||
'on':
|
||||
# Run CI against all pushes (direct commits, also merged PRs) to main, and all Pull Requests
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- stable-*
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
import-galaxy:
|
||||
permissions:
|
||||
contents: read
|
||||
name: Test to import built collection artifact with Galaxy importer
|
||||
uses: ansible-community/github-action-test-galaxy-import/.github/workflows/test-galaxy-import.yml@main
|
||||
28
.github/workflows/nox.yml
vendored
Normal file
28
.github/workflows/nox.yml
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
# 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: nox
|
||||
'on':
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- stable-*
|
||||
pull_request:
|
||||
# Run CI once per day (at 08:00 UTC)
|
||||
schedule:
|
||||
- cron: '0 8 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
nox:
|
||||
runs-on: ubuntu-latest
|
||||
name: "Run extra sanity tests"
|
||||
steps:
|
||||
- name: Check out collection
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Run nox
|
||||
uses: ansible-community/antsibull-nox@main
|
||||
35
.github/workflows/reuse.yml
vendored
35
.github/workflows/reuse.yml
vendored
@@ -1,35 +0,0 @@
|
||||
---
|
||||
# Copyright (c) Ansible Project
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
name: Verify REUSE
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- stable-*
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
branches:
|
||||
- main
|
||||
- stable-*
|
||||
# Run CI once per day (at 07:30 UTC)
|
||||
schedule:
|
||||
- cron: '30 7 * * *'
|
||||
|
||||
jobs:
|
||||
check:
|
||||
permissions:
|
||||
contents: read
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
ref: ${{ github.event.pull_request.head.sha || '' }}
|
||||
|
||||
- name: REUSE Compliance Check
|
||||
uses: fsfe/reuse-action@v5
|
||||
@@ -1,5 +0,0 @@
|
||||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
|
||||
Files: changelogs/fragments/*
|
||||
Copyright: Ansible Project
|
||||
License: GPL-3.0-or-later
|
||||
248
CHANGELOG.md
248
CHANGELOG.md
@@ -2,67 +2,82 @@
|
||||
|
||||
**Topics**
|
||||
|
||||
- <a href="#v9-5-4">v9\.5\.4</a>
|
||||
- <a href="#security-fixes">Security Fixes</a>
|
||||
- <a href="#bugfixes">Bugfixes</a>
|
||||
- <a href="#v9-5-3">v9\.5\.3</a>
|
||||
- <a href="#v9-5-8">v9\.5\.8</a>
|
||||
- <a href="#release-summary">Release Summary</a>
|
||||
- <a href="#minor-changes">Minor Changes</a>
|
||||
- <a href="#security-fixes-1">Security Fixes</a>
|
||||
- <a href="#bugfixes-1">Bugfixes</a>
|
||||
- <a href="#v9-5-2">v9\.5\.2</a>
|
||||
- <a href="#bugfixes">Bugfixes</a>
|
||||
- <a href="#v9-5-7">v9\.5\.7</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="#v9-5-6">v9\.5\.6</a>
|
||||
- <a href="#release-summary-2">Release Summary</a>
|
||||
- <a href="#minor-changes-1">Minor Changes</a>
|
||||
- <a href="#bugfixes-2">Bugfixes</a>
|
||||
- <a href="#v9-5-1">v9\.5\.1</a>
|
||||
- <a href="#release-summary-2">Release Summary</a>
|
||||
- <a href="#minor-changes-2">Minor Changes</a>
|
||||
- <a href="#bugfixes-3">Bugfixes</a>
|
||||
- <a href="#v9-5-0">v9\.5\.0</a>
|
||||
- <a href="#v9-5-5">v9\.5\.5</a>
|
||||
- <a href="#release-summary-3">Release Summary</a>
|
||||
- <a href="#minor-changes-3">Minor Changes</a>
|
||||
- <a href="#deprecated-features">Deprecated Features</a>
|
||||
- <a href="#bugfixes-3">Bugfixes</a>
|
||||
- <a href="#v9-5-4">v9\.5\.4</a>
|
||||
- <a href="#security-fixes">Security Fixes</a>
|
||||
- <a href="#bugfixes-4">Bugfixes</a>
|
||||
- <a href="#v9-5-3">v9\.5\.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-5">Bugfixes</a>
|
||||
- <a href="#v9-5-2">v9\.5\.2</a>
|
||||
- <a href="#release-summary-5">Release Summary</a>
|
||||
- <a href="#minor-changes-3">Minor Changes</a>
|
||||
- <a href="#bugfixes-6">Bugfixes</a>
|
||||
- <a href="#v9-5-1">v9\.5\.1</a>
|
||||
- <a href="#release-summary-6">Release Summary</a>
|
||||
- <a href="#minor-changes-4">Minor Changes</a>
|
||||
- <a href="#bugfixes-7">Bugfixes</a>
|
||||
- <a href="#v9-5-0">v9\.5\.0</a>
|
||||
- <a href="#release-summary-7">Release Summary</a>
|
||||
- <a href="#minor-changes-5">Minor Changes</a>
|
||||
- <a href="#deprecated-features">Deprecated Features</a>
|
||||
- <a href="#bugfixes-8">Bugfixes</a>
|
||||
- <a href="#new-modules">New Modules</a>
|
||||
- <a href="#v9-4-0">v9\.4\.0</a>
|
||||
- <a href="#release-summary-4">Release Summary</a>
|
||||
- <a href="#minor-changes-4">Minor Changes</a>
|
||||
- <a href="#release-summary-8">Release Summary</a>
|
||||
- <a href="#minor-changes-6">Minor Changes</a>
|
||||
- <a href="#deprecated-features-1">Deprecated Features</a>
|
||||
- <a href="#bugfixes-5">Bugfixes</a>
|
||||
- <a href="#bugfixes-9">Bugfixes</a>
|
||||
- <a href="#new-modules-1">New Modules</a>
|
||||
- <a href="#v9-3-0">v9\.3\.0</a>
|
||||
- <a href="#release-summary-5">Release Summary</a>
|
||||
- <a href="#minor-changes-5">Minor Changes</a>
|
||||
- <a href="#bugfixes-6">Bugfixes</a>
|
||||
- <a href="#release-summary-9">Release Summary</a>
|
||||
- <a href="#minor-changes-7">Minor Changes</a>
|
||||
- <a href="#bugfixes-10">Bugfixes</a>
|
||||
- <a href="#new-modules-2">New Modules</a>
|
||||
- <a href="#v9-2-0">v9\.2\.0</a>
|
||||
- <a href="#release-summary-6">Release Summary</a>
|
||||
- <a href="#minor-changes-6">Minor Changes</a>
|
||||
- <a href="#bugfixes-7">Bugfixes</a>
|
||||
- <a href="#release-summary-10">Release Summary</a>
|
||||
- <a href="#minor-changes-8">Minor Changes</a>
|
||||
- <a href="#bugfixes-11">Bugfixes</a>
|
||||
- <a href="#new-plugins">New Plugins</a>
|
||||
- <a href="#filter">Filter</a>
|
||||
- <a href="#test">Test</a>
|
||||
- <a href="#v9-1-0">v9\.1\.0</a>
|
||||
- <a href="#release-summary-7">Release Summary</a>
|
||||
- <a href="#minor-changes-7">Minor Changes</a>
|
||||
- <a href="#release-summary-11">Release Summary</a>
|
||||
- <a href="#minor-changes-9">Minor Changes</a>
|
||||
- <a href="#deprecated-features-2">Deprecated Features</a>
|
||||
- <a href="#bugfixes-8">Bugfixes</a>
|
||||
- <a href="#known-issues">Known Issues</a>
|
||||
- <a href="#bugfixes-12">Bugfixes</a>
|
||||
- <a href="#known-issues-1">Known Issues</a>
|
||||
- <a href="#new-plugins-1">New Plugins</a>
|
||||
- <a href="#filter-1">Filter</a>
|
||||
- <a href="#new-modules-3">New Modules</a>
|
||||
- <a href="#v9-0-1">v9\.0\.1</a>
|
||||
- <a href="#release-summary-8">Release Summary</a>
|
||||
- <a href="#minor-changes-8">Minor Changes</a>
|
||||
- <a href="#bugfixes-9">Bugfixes</a>
|
||||
- <a href="#release-summary-12">Release Summary</a>
|
||||
- <a href="#minor-changes-10">Minor Changes</a>
|
||||
- <a href="#bugfixes-13">Bugfixes</a>
|
||||
- <a href="#v9-0-0">v9\.0\.0</a>
|
||||
- <a href="#release-summary-9">Release Summary</a>
|
||||
- <a href="#minor-changes-9">Minor Changes</a>
|
||||
- <a href="#release-summary-13">Release Summary</a>
|
||||
- <a href="#minor-changes-11">Minor Changes</a>
|
||||
- <a href="#breaking-changes--porting-guide">Breaking Changes / Porting Guide</a>
|
||||
- <a href="#deprecated-features-3">Deprecated Features</a>
|
||||
- <a href="#removed-features-previously-deprecated">Removed Features \(previously deprecated\)</a>
|
||||
- <a href="#security-fixes-2">Security Fixes</a>
|
||||
- <a href="#bugfixes-10">Bugfixes</a>
|
||||
- <a href="#bugfixes-14">Bugfixes</a>
|
||||
- <a href="#new-plugins-2">New Plugins</a>
|
||||
- <a href="#become">Become</a>
|
||||
- <a href="#callback">Callback</a>
|
||||
@@ -73,6 +88,107 @@
|
||||
- <a href="#new-modules-4">New Modules</a>
|
||||
This changelog describes changes after version 8\.0\.0\.
|
||||
|
||||
<a id="v9-5-8"></a>
|
||||
## v9\.5\.8
|
||||
|
||||
<a id="release-summary"></a>
|
||||
### Release Summary
|
||||
|
||||
Regular bugfix release\.
|
||||
|
||||
<a id="bugfixes"></a>
|
||||
### Bugfixes
|
||||
|
||||
* cobbler\_system \- fix bug with Cobbler \>\= 3\.4\.0 caused by giving more than 2 positional arguments to <code>CobblerXMLRPCInterface\.get\_system\_handle\(\)</code> \([https\://github\.com/ansible\-collections/community\.general/issues/8506](https\://github\.com/ansible\-collections/community\.general/issues/8506)\, [https\://github\.com/ansible\-collections/community\.general/pull/10145](https\://github\.com/ansible\-collections/community\.general/pull/10145)\)\.
|
||||
* kdeconfig \- allow option values beginning with a dash \([https\://github\.com/ansible\-collections/community\.general/issues/10127](https\://github\.com/ansible\-collections/community\.general/issues/10127)\, [https\://github\.com/ansible\-collections/community\.general/pull/10128](https\://github\.com/ansible\-collections/community\.general/pull/10128)\)\.
|
||||
* keycloak\_user\_rolemapping \- fix <code>\-\-diff</code> mode \([https\://github\.com/ansible\-collections/community\.general/issues/10067](https\://github\.com/ansible\-collections/community\.general/issues/10067)\, [https\://github\.com/ansible\-collections/community\.general/pull/10075](https\://github\.com/ansible\-collections/community\.general/pull/10075)\)\.
|
||||
* pickle cache plugin \- avoid extra JSON serialization with ansible\-core \>\= 2\.19 \([https\://github\.com/ansible\-collections/community\.general/pull/10136](https\://github\.com/ansible\-collections/community\.general/pull/10136)\)\.
|
||||
* rundeck\_acl\_policy \- ensure that project ACLs are sent to the correct endpoint \([https\://github\.com/ansible\-collections/community\.general/pull/10097](https\://github\.com/ansible\-collections/community\.general/pull/10097)\)\.
|
||||
* sysrc \- split the output of <code>sysrc \-e \-a</code> on the first <code>\=</code> only \([https\://github\.com/ansible\-collections/community\.general/issues/10120](https\://github\.com/ansible\-collections/community\.general/issues/10120)\, [https\://github\.com/ansible\-collections/community\.general/pull/10121](https\://github\.com/ansible\-collections/community\.general/pull/10121)\)\.
|
||||
|
||||
<a id="v9-5-7"></a>
|
||||
## v9\.5\.7
|
||||
|
||||
<a id="release-summary-1"></a>
|
||||
### Release Summary
|
||||
|
||||
Regular bugfix release\.
|
||||
|
||||
<a id="minor-changes"></a>
|
||||
### Minor Changes
|
||||
|
||||
* apache2\_module \- added workaround for new PHP module name\, from <code>php7\_module</code> to <code>php\_module</code> \([https\://github\.com/ansible\-collections/community\.general/pull/9951](https\://github\.com/ansible\-collections/community\.general/pull/9951)\)\.
|
||||
|
||||
<a id="bugfixes-1"></a>
|
||||
### Bugfixes
|
||||
|
||||
* dependent look plugin \- make compatible with ansible\-core\'s Data Tagging feature \([https\://github\.com/ansible\-collections/community\.general/pull/9833](https\://github\.com/ansible\-collections/community\.general/pull/9833)\)\.
|
||||
* diy callback plugin \- make compatible with ansible\-core\'s Data Tagging feature \([https\://github\.com/ansible\-collections/community\.general/pull/9833](https\://github\.com/ansible\-collections/community\.general/pull/9833)\)\.
|
||||
* github\_deploy\_key \- check that key really exists on 422 to avoid masking other errors \([https\://github\.com/ansible\-collections/community\.general/issues/6718](https\://github\.com/ansible\-collections/community\.general/issues/6718)\, [https\://github\.com/ansible\-collections/community\.general/pull/10011](https\://github\.com/ansible\-collections/community\.general/pull/10011)\)\.
|
||||
* hashids and unicode\_normalize filter plugins \- avoid deprecated <code>AnsibleFilterTypeError</code> on ansible\-core 2\.19 \([https\://github\.com/ansible\-collections/community\.general/pull/9992](https\://github\.com/ansible\-collections/community\.general/pull/9992)\)\.
|
||||
* keycloak\_authentication \- fix authentification config duplication for Keycloak \< 26\.2\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/9987](https\://github\.com/ansible\-collections/community\.general/pull/9987)\)\.
|
||||
* keycloak\_client \- fix the idempotency regression by normalizing the Keycloak response for <code>after\_client</code> \([https\://github\.com/ansible\-collections/community\.general/issues/9905](https\://github\.com/ansible\-collections/community\.general/issues/9905)\, [https\://github\.com/ansible\-collections/community\.general/pull/9976](https\://github\.com/ansible\-collections/community\.general/pull/9976)\)\.
|
||||
* proxmox inventory plugin \- fix <code>ansible\_host</code> staying empty for certain Proxmox nodes \([https\://github\.com/ansible\-collections/community\.general/issues/5906](https\://github\.com/ansible\-collections/community\.general/issues/5906)\, [https\://github\.com/ansible\-collections/community\.general/pull/9952](https\://github\.com/ansible\-collections/community\.general/pull/9952)\)\.
|
||||
* proxmox\_disk \- fail gracefully if <code>storage</code> is required but not provided by the user \([https\://github\.com/ansible\-collections/community\.general/issues/9941](https\://github\.com/ansible\-collections/community\.general/issues/9941)\, [https\://github\.com/ansible\-collections/community\.general/pull/9963](https\://github\.com/ansible\-collections/community\.general/pull/9963)\)\.
|
||||
* reveal\_ansible\_type filter plugin and ansible\_type test plugin \- make compatible with ansible\-core\'s Data Tagging feature \([https\://github\.com/ansible\-collections/community\.general/pull/9833](https\://github\.com/ansible\-collections/community\.general/pull/9833)\)\.
|
||||
* sysrc \- no longer always reporting <code>changed\=true</code> when <code>state\=absent</code>\. This fixes the method <code>exists\(\)</code> \([https\://github\.com/ansible\-collections/community\.general/issues/10004](https\://github\.com/ansible\-collections/community\.general/issues/10004)\, [https\://github\.com/ansible\-collections/community\.general/pull/10005](https\://github\.com/ansible\-collections/community\.general/pull/10005)\)\.
|
||||
* yaml callback plugin \- use ansible\-core internals to avoid breakage with Data Tagging \([https\://github\.com/ansible\-collections/community\.general/pull/9833](https\://github\.com/ansible\-collections/community\.general/pull/9833)\)\.
|
||||
|
||||
<a id="known-issues"></a>
|
||||
### Known Issues
|
||||
|
||||
* reveal\_ansible\_type filter plugin and ansible\_type test plugin \- note that ansible\-core\'s Data Tagging feature implements new aliases\, such as <code>\_AnsibleTaggedStr</code> for <code>str</code>\, <code>\_AnsibleTaggedInt</code> for <code>int</code>\, and <code>\_AnsibleTaggedFloat</code> for <code>float</code> \([https\://github\.com/ansible\-collections/community\.general/pull/9833](https\://github\.com/ansible\-collections/community\.general/pull/9833)\)\.
|
||||
|
||||
<a id="v9-5-6"></a>
|
||||
## v9\.5\.6
|
||||
|
||||
<a id="release-summary-2"></a>
|
||||
### Release Summary
|
||||
|
||||
Regular bugfix release\.
|
||||
|
||||
<a id="minor-changes-1"></a>
|
||||
### Minor Changes
|
||||
|
||||
* consul\_token \- fix idempotency when <code>policies</code> or <code>roles</code> are supplied by name \([https\://github\.com/ansible\-collections/community\.general/issues/9841](https\://github\.com/ansible\-collections/community\.general/issues/9841)\, [https\://github\.com/ansible\-collections/community\.general/pull/9845](https\://github\.com/ansible\-collections/community\.general/pull/9845)\)\.
|
||||
|
||||
<a id="bugfixes-2"></a>
|
||||
### Bugfixes
|
||||
|
||||
* cloudlare\_dns \- handle exhausted response stream in case of HTTP errors to show nice error message to the user \([https\://github\.com/ansible\-collections/community\.general/issues/9782](https\://github\.com/ansible\-collections/community\.general/issues/9782)\, [https\://github\.com/ansible\-collections/community\.general/pull/9818](https\://github\.com/ansible\-collections/community\.general/pull/9818)\)\.
|
||||
* dnf\_versionlock \- add support for dnf5 \([https\://github\.com/ansible\-collections/community\.general/issues/9556](https\://github\.com/ansible\-collections/community\.general/issues/9556)\)\.
|
||||
* homebrew\_cask \- handle unusual brew version strings \([https\://github\.com/ansible\-collections/community\.general/issues/8432](https\://github\.com/ansible\-collections/community\.general/issues/8432)\, [https\://github\.com/ansible\-collections/community\.general/pull/9881](https\://github\.com/ansible\-collections/community\.general/pull/9881)\)\.
|
||||
* ipa\_host \- module revoked existing host certificates even if <code>user\_certificate</code> was not given \([https\://github\.com/ansible\-collections/community\.general/pull/9694](https\://github\.com/ansible\-collections/community\.general/pull/9694)\)\.
|
||||
* nmcli \- enable changing only the order of DNS servers or search suffixes \([https\://github\.com/ansible\-collections/community\.general/issues/8724](https\://github\.com/ansible\-collections/community\.general/issues/8724)\, [https\://github\.com/ansible\-collections/community\.general/pull/9880](https\://github\.com/ansible\-collections/community\.general/pull/9880)\)\.
|
||||
* proxmox\_vm\_info \- the module no longer expects that the key <code>template</code> exists in a dictionary returned by Proxmox \([https\://github\.com/ansible\-collections/community\.general/issues/9875](https\://github\.com/ansible\-collections/community\.general/issues/9875)\, [https\://github\.com/ansible\-collections/community\.general/pull/9910](https\://github\.com/ansible\-collections/community\.general/pull/9910)\)\.
|
||||
* sudoers \- display stdout and stderr raised while failed validation \([https\://github\.com/ansible\-collections/community\.general/issues/9674](https\://github\.com/ansible\-collections/community\.general/issues/9674)\, [https\://github\.com/ansible\-collections/community\.general/pull/9871](https\://github\.com/ansible\-collections/community\.general/pull/9871)\)\.
|
||||
|
||||
<a id="v9-5-5"></a>
|
||||
## v9\.5\.5
|
||||
|
||||
<a id="release-summary-3"></a>
|
||||
### Release Summary
|
||||
|
||||
Regular bugfix release\.
|
||||
|
||||
<a id="bugfixes-3"></a>
|
||||
### Bugfixes
|
||||
|
||||
* apache2\_mod\_proxy \- make compatible with Python 3 \([https\://github\.com/ansible\-collections/community\.general/pull/9762](https\://github\.com/ansible\-collections/community\.general/pull/9762)\)\.
|
||||
* apache2\_mod\_proxy \- passing the cluster\'s page as referer for the member\'s pages\. This makes the module actually work again for halfway modern Apache versions\. According to some comments founds on the net the referer was required since at least 2019 for some versions of Apache 2 \([https\://github\.com/ansible\-collections/community\.general/pull/9762](https\://github\.com/ansible\-collections/community\.general/pull/9762)\)\.
|
||||
* cloudflare\_dns \- fix crash when deleting a DNS record or when updating a record with <code>solo\=true</code> \([https\://github\.com/ansible\-collections/community\.general/issues/9652](https\://github\.com/ansible\-collections/community\.general/issues/9652)\, [https\://github\.com/ansible\-collections/community\.general/pull/9649](https\://github\.com/ansible\-collections/community\.general/pull/9649)\)\.
|
||||
* elasticsearch\_plugin \- fix <code>ERROR\: D is not a recognized option</code> issue when configuring proxy settings \([https\://github\.com/ansible\-collections/community\.general/pull/9774](https\://github\.com/ansible\-collections/community\.general/pull/9774)\, [https\://github\.com/ansible\-collections/community\.general/issues/9773](https\://github\.com/ansible\-collections/community\.general/issues/9773)\)\.
|
||||
* keycloak\_client \- fix and improve existing tests\. The module showed a diff without actual changes\, solved by improving the <code>normalise\_cr\(\)</code> function \([https\://github\.com/ansible\-collections/community\.general/pull/9644](https\://github\.com/ansible\-collections/community\.general/pull/9644)\)\.
|
||||
* keycloak\_client \- in check mode\, detect whether the lists in before client \(for example redirect URI list\) contain items that the lists in the desired client do not contain \([https\://github\.com/ansible\-collections/community\.general/pull/9739](https\://github\.com/ansible\-collections/community\.general/pull/9739)\)\.
|
||||
* passwordstore lookup plugin \- fix subkey creation even when <code>create\=false</code> \([https\://github\.com/ansible\-collections/community\.general/issues/9105](https\://github\.com/ansible\-collections/community\.general/issues/9105)\, [https\://github\.com/ansible\-collections/community\.general/pull/9106](https\://github\.com/ansible\-collections/community\.general/pull/9106)\)\.
|
||||
* proxmox inventory plugin \- plugin did not update cache correctly after <code>meta\: refresh\_inventory</code> \([https\://github\.com/ansible\-collections/community\.general/issues/9710](https\://github\.com/ansible\-collections/community\.general/issues/9710)\, [https\://github\.com/ansible\-collections/community\.general/pull/9760](https\://github\.com/ansible\-collections/community\.general/pull/9760)\)\.
|
||||
* redhat\_subscription \- use the \"enable\_content\" option \(when available\) when
|
||||
registering using D\-Bus\, to ensure that subscription\-manager enables the
|
||||
content on registration\; this is particular important on EL 10\+ and Fedora
|
||||
41\+
|
||||
\([https\://github\.com/ansible\-collections/community\.general/pull/9778](https\://github\.com/ansible\-collections/community\.general/pull/9778)\)\.
|
||||
* xml \- ensure file descriptor is closed \([https\://github\.com/ansible\-collections/community\.general/pull/9695](https\://github\.com/ansible\-collections/community\.general/pull/9695)\)\.
|
||||
|
||||
<a id="v9-5-4"></a>
|
||||
## v9\.5\.4
|
||||
|
||||
@@ -81,7 +197,7 @@ This changelog describes changes after version 8\.0\.0\.
|
||||
|
||||
* keycloak\_client \- Sanitize <code>saml\.encryption\.private\.key</code> so it does not show in the logs \([https\://github\.com/ansible\-collections/community\.general/pull/9621](https\://github\.com/ansible\-collections/community\.general/pull/9621)\)\.
|
||||
|
||||
<a id="bugfixes"></a>
|
||||
<a id="bugfixes-4"></a>
|
||||
### Bugfixes
|
||||
|
||||
* redhat\_subscription \- do not try to unsubscribe \(i\.e\. remove subscriptions\)
|
||||
@@ -93,12 +209,12 @@ This changelog describes changes after version 8\.0\.0\.
|
||||
<a id="v9-5-3"></a>
|
||||
## v9\.5\.3
|
||||
|
||||
<a id="release-summary"></a>
|
||||
<a id="release-summary-4"></a>
|
||||
### Release Summary
|
||||
|
||||
Regular bugfix release\.
|
||||
|
||||
<a id="minor-changes"></a>
|
||||
<a id="minor-changes-2"></a>
|
||||
### Minor Changes
|
||||
|
||||
* proxmox module utils \- add method <code>api\_task\_complete</code> that can wait for task completion and return error message \([https\://github\.com/ansible\-collections/community\.general/pull/9256](https\://github\.com/ansible\-collections/community\.general/pull/9256)\)\.
|
||||
@@ -108,7 +224,7 @@ Regular bugfix release\.
|
||||
|
||||
* keycloak\_authentication \- API calls did not properly set the <code>priority</code> during update resulting in incorrectly sorted authentication flows\. This apparently only affects Keycloak 25 or newer \([https\://github\.com/ansible\-collections/community\.general/pull/9263](https\://github\.com/ansible\-collections/community\.general/pull/9263)\)\.
|
||||
|
||||
<a id="bugfixes-1"></a>
|
||||
<a id="bugfixes-5"></a>
|
||||
### Bugfixes
|
||||
|
||||
* dig lookup plugin \- correctly handle <code>NoNameserver</code> exception \([https\://github\.com/ansible\-collections/community\.general/pull/9363](https\://github\.com/ansible\-collections/community\.general/pull/9363)\, [https\://github\.com/ansible\-collections/community\.general/issues/9362](https\://github\.com/ansible\-collections/community\.general/issues/9362)\)\.
|
||||
@@ -121,17 +237,17 @@ Regular bugfix release\.
|
||||
<a id="v9-5-2"></a>
|
||||
## v9\.5\.2
|
||||
|
||||
<a id="release-summary-1"></a>
|
||||
<a id="release-summary-5"></a>
|
||||
### Release Summary
|
||||
|
||||
Regular bugfix release\.
|
||||
|
||||
<a id="minor-changes-1"></a>
|
||||
<a id="minor-changes-3"></a>
|
||||
### Minor Changes
|
||||
|
||||
* proxmox inventory plugin \- fix urllib3 <code>InsecureRequestWarnings</code> not being suppressed when a token is used \([https\://github\.com/ansible\-collections/community\.general/pull/9099](https\://github\.com/ansible\-collections/community\.general/pull/9099)\)\.
|
||||
|
||||
<a id="bugfixes-2"></a>
|
||||
<a id="bugfixes-6"></a>
|
||||
### Bugfixes
|
||||
|
||||
* dnf\_config\_manager \- fix hanging when prompting to import GPG keys \([https\://github\.com/ansible\-collections/community\.general/pull/9124](https\://github\.com/ansible\-collections/community\.general/pull/9124)\, [https\://github\.com/ansible\-collections/community\.general/issues/8830](https\://github\.com/ansible\-collections/community\.general/issues/8830)\)\.
|
||||
@@ -148,17 +264,17 @@ Regular bugfix release\.
|
||||
<a id="v9-5-1"></a>
|
||||
## v9\.5\.1
|
||||
|
||||
<a id="release-summary-2"></a>
|
||||
<a id="release-summary-6"></a>
|
||||
### Release Summary
|
||||
|
||||
Regular bugfix release\.
|
||||
|
||||
<a id="minor-changes-2"></a>
|
||||
<a id="minor-changes-4"></a>
|
||||
### Minor Changes
|
||||
|
||||
* redfish\_utils module utils \- schedule a BIOS configuration job at next reboot when the BIOS config is changed \([https\://github\.com/ansible\-collections/community\.general/pull/9012](https\://github\.com/ansible\-collections/community\.general/pull/9012)\)\.
|
||||
|
||||
<a id="bugfixes-3"></a>
|
||||
<a id="bugfixes-7"></a>
|
||||
### Bugfixes
|
||||
|
||||
* bitwarden lookup plugin \- support BWS v0\.3\.0 syntax breaking change \([https\://github\.com/ansible\-collections/community\.general/pull/9028](https\://github\.com/ansible\-collections/community\.general/pull/9028)\)\.
|
||||
@@ -176,7 +292,7 @@ Regular bugfix release\.
|
||||
<a id="v9-5-0"></a>
|
||||
## v9\.5\.0
|
||||
|
||||
<a id="release-summary-3"></a>
|
||||
<a id="release-summary-7"></a>
|
||||
### Release Summary
|
||||
|
||||
Regular bugfix and feature release\.
|
||||
@@ -184,7 +300,7 @@ Regular bugfix and feature release\.
|
||||
Please note that this is the last feature release for community\.general 9\.x\.y\.
|
||||
From now on\, new features will only go into community\.general 10\.x\.y\.
|
||||
|
||||
<a id="minor-changes-3"></a>
|
||||
<a id="minor-changes-5"></a>
|
||||
### Minor Changes
|
||||
|
||||
* dig lookup plugin \- add <code>port</code> option to specify DNS server port \([https\://github\.com/ansible\-collections/community\.general/pull/8966](https\://github\.com/ansible\-collections/community\.general/pull/8966)\)\.
|
||||
@@ -241,7 +357,7 @@ From now on\, new features will only go into community\.general 10\.x\.y\.
|
||||
|
||||
* hipchat \- the hipchat service has been discontinued and the self\-hosted variant has been End of Life since 2020\. The module is therefore deprecated and will be removed from community\.general 11\.0\.0 if nobody provides compelling reasons to still keep it \([https\://github\.com/ansible\-collections/community\.general/pull/8919](https\://github\.com/ansible\-collections/community\.general/pull/8919)\)\.
|
||||
|
||||
<a id="bugfixes-4"></a>
|
||||
<a id="bugfixes-8"></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)\)\.
|
||||
@@ -275,12 +391,12 @@ From now on\, new features will only go into community\.general 10\.x\.y\.
|
||||
<a id="v9-4-0"></a>
|
||||
## v9\.4\.0
|
||||
|
||||
<a id="release-summary-4"></a>
|
||||
<a id="release-summary-8"></a>
|
||||
### Release Summary
|
||||
|
||||
Bugfix and feature release\.
|
||||
|
||||
<a id="minor-changes-4"></a>
|
||||
<a id="minor-changes-6"></a>
|
||||
### Minor Changes
|
||||
|
||||
* MH module utils \- add parameter <code>when</code> to <code>cause\_changes</code> decorator \([https\://github\.com/ansible\-collections/community\.general/pull/8766](https\://github\.com/ansible\-collections/community\.general/pull/8766)\)\.
|
||||
@@ -367,7 +483,7 @@ Bugfix and feature release\.
|
||||
* pipx \- support for versions of the command line tool <code>pipx</code> older than <code>1\.7\.0</code> is deprecated and will be removed in community\.general 11\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/8793](https\://github\.com/ansible\-collections/community\.general/pull/8793)\)\.
|
||||
* pipx\_info \- support for versions of the command line tool <code>pipx</code> older than <code>1\.7\.0</code> is deprecated and will be removed in community\.general 11\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/8793](https\://github\.com/ansible\-collections/community\.general/pull/8793)\)\.
|
||||
|
||||
<a id="bugfixes-5"></a>
|
||||
<a id="bugfixes-9"></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)\)\.
|
||||
@@ -389,12 +505,12 @@ Bugfix and feature release\.
|
||||
<a id="v9-3-0"></a>
|
||||
## v9\.3\.0
|
||||
|
||||
<a id="release-summary-5"></a>
|
||||
<a id="release-summary-9"></a>
|
||||
### Release Summary
|
||||
|
||||
Regular bugfix and feature release\.
|
||||
|
||||
<a id="minor-changes-5"></a>
|
||||
<a id="minor-changes-7"></a>
|
||||
### Minor Changes
|
||||
|
||||
* cgroup\_memory\_recap\, hipchat\, jabber\, log\_plays\, loganalytics\, logentries\, logstash\, slack\, splunk\, sumologic\, syslog\_json callback plugins \- make sure that all options are typed \([https\://github\.com/ansible\-collections/community\.general/pull/8628](https\://github\.com/ansible\-collections/community\.general/pull/8628)\)\.
|
||||
@@ -417,7 +533,7 @@ Regular bugfix and feature release\.
|
||||
* proxmox inventory plugin \- add new fact for LXC interface details \([https\://github\.com/ansible\-collections/community\.general/pull/8713](https\://github\.com/ansible\-collections/community\.general/pull/8713)\)\.
|
||||
* redis\, redis\_info \- add <code>client\_cert</code> and <code>client\_key</code> options to specify path to certificate for Redis authentication \([https\://github\.com/ansible\-collections/community\.general/pull/8654](https\://github\.com/ansible\-collections/community\.general/pull/8654)\)\.
|
||||
|
||||
<a id="bugfixes-6"></a>
|
||||
<a id="bugfixes-10"></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)\)\.
|
||||
@@ -438,12 +554,12 @@ Regular bugfix and feature release\.
|
||||
<a id="v9-2-0"></a>
|
||||
## v9\.2\.0
|
||||
|
||||
<a id="release-summary-6"></a>
|
||||
<a id="release-summary-10"></a>
|
||||
### Release Summary
|
||||
|
||||
Regular bugfix and feature release\.
|
||||
|
||||
<a id="minor-changes-6"></a>
|
||||
<a id="minor-changes-8"></a>
|
||||
### Minor Changes
|
||||
|
||||
* CmdRunner module utils \- the parameter <code>force\_lang</code> now supports the special value <code>auto</code> which will automatically try and determine the best parsable locale in the system \([https\://github\.com/ansible\-collections/community\.general/pull/8517](https\://github\.com/ansible\-collections/community\.general/pull/8517)\)\.
|
||||
@@ -455,7 +571,7 @@ Regular bugfix and feature release\.
|
||||
* virtualbox inventory plugin \- expose a new parameter <code>enable\_advanced\_group\_parsing</code> to change how the VirtualBox dynamic inventory parses VM groups \([https\://github\.com/ansible\-collections/community\.general/issues/8508](https\://github\.com/ansible\-collections/community\.general/issues/8508)\, [https\://github\.com/ansible\-collections/community\.general/pull/8510](https\://github\.com/ansible\-collections/community\.general/pull/8510)\)\.
|
||||
* 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-7"></a>
|
||||
<a id="bugfixes-11"></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)\)\.
|
||||
@@ -480,12 +596,12 @@ Regular bugfix and feature release\.
|
||||
<a id="v9-1-0"></a>
|
||||
## v9\.1\.0
|
||||
|
||||
<a id="release-summary-7"></a>
|
||||
<a id="release-summary-11"></a>
|
||||
### Release Summary
|
||||
|
||||
Regular feature and bugfix release\.
|
||||
|
||||
<a id="minor-changes-7"></a>
|
||||
<a id="minor-changes-9"></a>
|
||||
### Minor Changes
|
||||
|
||||
* CmdRunner module util \- argument formats can be specified as plain functions without calling <code>cmd\_runner\_fmt\.as\_func\(\)</code> \([https\://github\.com/ansible\-collections/community\.general/pull/8479](https\://github\.com/ansible\-collections/community\.general/pull/8479)\)\.
|
||||
@@ -509,7 +625,7 @@ Regular feature and bugfix release\.
|
||||
* git\_config \- the <code>list\_all</code> option has been deprecated and will be removed in community\.general 11\.0\.0\. Use the <code>community\.general\.git\_config\_info</code> module instead \([https\://github\.com/ansible\-collections/community\.general/pull/8453](https\://github\.com/ansible\-collections/community\.general/pull/8453)\)\.
|
||||
* git\_config \- using <code>state\=present</code> without providing <code>value</code> is deprecated and will be disallowed in community\.general 11\.0\.0\. Use the <code>community\.general\.git\_config\_info</code> module instead to read a value \([https\://github\.com/ansible\-collections/community\.general/pull/8453](https\://github\.com/ansible\-collections/community\.general/pull/8453)\)\.
|
||||
|
||||
<a id="bugfixes-8"></a>
|
||||
<a id="bugfixes-12"></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)\)\.
|
||||
@@ -520,7 +636,7 @@ Regular feature and bugfix release\.
|
||||
* opentelemetry callback \- do not save the content response when using the <code>ansible\.builtin\.slurp</code> module \([https\://github\.com/ansible\-collections/community\.general/pull/8430](https\://github\.com/ansible\-collections/community\.general/pull/8430)\)\.
|
||||
* paman \- do not fail if an empty list of packages has been provided and there is nothing to do \([https\://github\.com/ansible\-collections/community\.general/pull/8514](https\://github\.com/ansible\-collections/community\.general/pull/8514)\)\.
|
||||
|
||||
<a id="known-issues"></a>
|
||||
<a id="known-issues-1"></a>
|
||||
### Known Issues
|
||||
|
||||
* homectl \- the module does not work under Python 3\.13 or newer\, since it relies on the removed <code>crypt</code> standard library module \([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/8497](https\://github\.com/ansible\-collections/community\.general/pull/8497)\)\.
|
||||
@@ -547,17 +663,17 @@ Regular feature and bugfix release\.
|
||||
<a id="v9-0-1"></a>
|
||||
## v9\.0\.1
|
||||
|
||||
<a id="release-summary-8"></a>
|
||||
<a id="release-summary-12"></a>
|
||||
### Release Summary
|
||||
|
||||
Bugfix release for inclusion in Ansible 10\.0\.0rc1\.
|
||||
|
||||
<a id="minor-changes-8"></a>
|
||||
<a id="minor-changes-10"></a>
|
||||
### Minor Changes
|
||||
|
||||
* ansible\_galaxy\_install \- minor refactor in the module \([https\://github\.com/ansible\-collections/community\.general/pull/8413](https\://github\.com/ansible\-collections/community\.general/pull/8413)\)\.
|
||||
|
||||
<a id="bugfixes-9"></a>
|
||||
<a id="bugfixes-13"></a>
|
||||
### Bugfixes
|
||||
|
||||
* cpanm \- use new <code>VarDict</code> to prevent deprecation warning \([https\://github\.com/ansible\-collections/community\.general/issues/8410](https\://github\.com/ansible\-collections/community\.general/issues/8410)\, [https\://github\.com/ansible\-collections/community\.general/pull/8411](https\://github\.com/ansible\-collections/community\.general/pull/8411)\)\.
|
||||
@@ -576,12 +692,12 @@ Bugfix release for inclusion in Ansible 10\.0\.0rc1\.
|
||||
<a id="v9-0-0"></a>
|
||||
## v9\.0\.0
|
||||
|
||||
<a id="release-summary-9"></a>
|
||||
<a id="release-summary-13"></a>
|
||||
### Release Summary
|
||||
|
||||
This is release 9\.0\.0 of <code>community\.general</code>\, released on 2024\-05\-20\.
|
||||
|
||||
<a id="minor-changes-9"></a>
|
||||
<a id="minor-changes-11"></a>
|
||||
### Minor Changes
|
||||
|
||||
* PythonRunner module utils \- specialisation of <code>CmdRunner</code> to execute Python scripts \([https\://github\.com/ansible\-collections/community\.general/pull/8289](https\://github\.com/ansible\-collections/community\.general/pull/8289)\)\.
|
||||
@@ -751,7 +867,7 @@ This is release 9\.0\.0 of <code>community\.general</code>\, released on 2024\-0
|
||||
* 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)\)\.
|
||||
* 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-10"></a>
|
||||
<a id="bugfixes-14"></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)\)\.
|
||||
|
||||
101
CHANGELOG.rst
101
CHANGELOG.rst
@@ -6,6 +6,107 @@ Community General Release Notes
|
||||
|
||||
This changelog describes changes after version 8.0.0.
|
||||
|
||||
v9.5.8
|
||||
======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
Regular bugfix release.
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- cobbler_system - fix bug with Cobbler >= 3.4.0 caused by giving more than 2 positional arguments to ``CobblerXMLRPCInterface.get_system_handle()`` (https://github.com/ansible-collections/community.general/issues/8506, https://github.com/ansible-collections/community.general/pull/10145).
|
||||
- kdeconfig - allow option values beginning with a dash (https://github.com/ansible-collections/community.general/issues/10127, https://github.com/ansible-collections/community.general/pull/10128).
|
||||
- keycloak_user_rolemapping - fix ``--diff`` mode (https://github.com/ansible-collections/community.general/issues/10067, https://github.com/ansible-collections/community.general/pull/10075).
|
||||
- pickle cache plugin - avoid extra JSON serialization with ansible-core >= 2.19 (https://github.com/ansible-collections/community.general/pull/10136).
|
||||
- rundeck_acl_policy - ensure that project ACLs are sent to the correct endpoint (https://github.com/ansible-collections/community.general/pull/10097).
|
||||
- sysrc - split the output of ``sysrc -e -a`` on the first ``=`` only (https://github.com/ansible-collections/community.general/issues/10120, https://github.com/ansible-collections/community.general/pull/10121).
|
||||
|
||||
v9.5.7
|
||||
======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
Regular bugfix release.
|
||||
|
||||
Minor Changes
|
||||
-------------
|
||||
|
||||
- apache2_module - added workaround for new PHP module name, from ``php7_module`` to ``php_module`` (https://github.com/ansible-collections/community.general/pull/9951).
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- dependent look plugin - make compatible with ansible-core's Data Tagging feature (https://github.com/ansible-collections/community.general/pull/9833).
|
||||
- diy callback plugin - make compatible with ansible-core's Data Tagging feature (https://github.com/ansible-collections/community.general/pull/9833).
|
||||
- github_deploy_key - check that key really exists on 422 to avoid masking other errors (https://github.com/ansible-collections/community.general/issues/6718, https://github.com/ansible-collections/community.general/pull/10011).
|
||||
- hashids and unicode_normalize filter plugins - avoid deprecated ``AnsibleFilterTypeError`` on ansible-core 2.19 (https://github.com/ansible-collections/community.general/pull/9992).
|
||||
- keycloak_authentication - fix authentification config duplication for Keycloak < 26.2.0 (https://github.com/ansible-collections/community.general/pull/9987).
|
||||
- keycloak_client - fix the idempotency regression by normalizing the Keycloak response for ``after_client`` (https://github.com/ansible-collections/community.general/issues/9905, https://github.com/ansible-collections/community.general/pull/9976).
|
||||
- proxmox inventory plugin - fix ``ansible_host`` staying empty for certain Proxmox nodes (https://github.com/ansible-collections/community.general/issues/5906, https://github.com/ansible-collections/community.general/pull/9952).
|
||||
- proxmox_disk - fail gracefully if ``storage`` is required but not provided by the user (https://github.com/ansible-collections/community.general/issues/9941, https://github.com/ansible-collections/community.general/pull/9963).
|
||||
- reveal_ansible_type filter plugin and ansible_type test plugin - make compatible with ansible-core's Data Tagging feature (https://github.com/ansible-collections/community.general/pull/9833).
|
||||
- sysrc - no longer always reporting ``changed=true`` when ``state=absent``. This fixes the method ``exists()`` (https://github.com/ansible-collections/community.general/issues/10004, https://github.com/ansible-collections/community.general/pull/10005).
|
||||
- yaml callback plugin - use ansible-core internals to avoid breakage with Data Tagging (https://github.com/ansible-collections/community.general/pull/9833).
|
||||
|
||||
Known Issues
|
||||
------------
|
||||
|
||||
- reveal_ansible_type filter plugin and ansible_type test plugin - note that ansible-core's Data Tagging feature implements new aliases, such as ``_AnsibleTaggedStr`` for ``str``, ``_AnsibleTaggedInt`` for ``int``, and ``_AnsibleTaggedFloat`` for ``float`` (https://github.com/ansible-collections/community.general/pull/9833).
|
||||
|
||||
v9.5.6
|
||||
======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
Regular bugfix release.
|
||||
|
||||
Minor Changes
|
||||
-------------
|
||||
|
||||
- consul_token - fix idempotency when ``policies`` or ``roles`` are supplied by name (https://github.com/ansible-collections/community.general/issues/9841, https://github.com/ansible-collections/community.general/pull/9845).
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- cloudlare_dns - handle exhausted response stream in case of HTTP errors to show nice error message to the user (https://github.com/ansible-collections/community.general/issues/9782, https://github.com/ansible-collections/community.general/pull/9818).
|
||||
- dnf_versionlock - add support for dnf5 (https://github.com/ansible-collections/community.general/issues/9556).
|
||||
- homebrew_cask - handle unusual brew version strings (https://github.com/ansible-collections/community.general/issues/8432, https://github.com/ansible-collections/community.general/pull/9881).
|
||||
- ipa_host - module revoked existing host certificates even if ``user_certificate`` was not given (https://github.com/ansible-collections/community.general/pull/9694).
|
||||
- nmcli - enable changing only the order of DNS servers or search suffixes (https://github.com/ansible-collections/community.general/issues/8724, https://github.com/ansible-collections/community.general/pull/9880).
|
||||
- proxmox_vm_info - the module no longer expects that the key ``template`` exists in a dictionary returned by Proxmox (https://github.com/ansible-collections/community.general/issues/9875, https://github.com/ansible-collections/community.general/pull/9910).
|
||||
- sudoers - display stdout and stderr raised while failed validation (https://github.com/ansible-collections/community.general/issues/9674, https://github.com/ansible-collections/community.general/pull/9871).
|
||||
|
||||
v9.5.5
|
||||
======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
Regular bugfix release.
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- apache2_mod_proxy - make compatible with Python 3 (https://github.com/ansible-collections/community.general/pull/9762).
|
||||
- apache2_mod_proxy - passing the cluster's page as referer for the member's pages. This makes the module actually work again for halfway modern Apache versions. According to some comments founds on the net the referer was required since at least 2019 for some versions of Apache 2 (https://github.com/ansible-collections/community.general/pull/9762).
|
||||
- cloudflare_dns - fix crash when deleting a DNS record or when updating a record with ``solo=true`` (https://github.com/ansible-collections/community.general/issues/9652, https://github.com/ansible-collections/community.general/pull/9649).
|
||||
- elasticsearch_plugin - fix ``ERROR: D is not a recognized option`` issue when configuring proxy settings (https://github.com/ansible-collections/community.general/pull/9774, https://github.com/ansible-collections/community.general/issues/9773).
|
||||
- keycloak_client - fix and improve existing tests. The module showed a diff without actual changes, solved by improving the ``normalise_cr()`` function (https://github.com/ansible-collections/community.general/pull/9644).
|
||||
- keycloak_client - in check mode, detect whether the lists in before client (for example redirect URI list) contain items that the lists in the desired client do not contain (https://github.com/ansible-collections/community.general/pull/9739).
|
||||
- passwordstore lookup plugin - fix subkey creation even when ``create=false`` (https://github.com/ansible-collections/community.general/issues/9105, https://github.com/ansible-collections/community.general/pull/9106).
|
||||
- proxmox inventory plugin - plugin did not update cache correctly after ``meta: refresh_inventory`` (https://github.com/ansible-collections/community.general/issues/9710, https://github.com/ansible-collections/community.general/pull/9760).
|
||||
- redhat_subscription - use the "enable_content" option (when available) when
|
||||
registering using D-Bus, to ensure that subscription-manager enables the
|
||||
content on registration; this is particular important on EL 10+ and Fedora
|
||||
41+
|
||||
(https://github.com/ansible-collections/community.general/pull/9778).
|
||||
- xml - ensure file descriptor is closed (https://github.com/ansible-collections/community.general/pull/9695).
|
||||
|
||||
v9.5.4
|
||||
======
|
||||
|
||||
|
||||
@@ -44,7 +44,49 @@ If you want to test a PR locally, refer to [our testing guide](https://github.co
|
||||
|
||||
If you find any inconsistencies or places in this document which can be improved, feel free to raise an issue or pull request to fix it.
|
||||
|
||||
## Run sanity, unit or integration tests locally
|
||||
## Run sanity or unit locally (with antsibull-nox)
|
||||
|
||||
The easiest way to run sanity and unit tests locally is to use [antsibull-nox](https://ansible.readthedocs.io/projects/antsibull-nox/).
|
||||
(If you have [nox](https://nox.thea.codes/en/stable/) installed, it will automatically install antsibull-nox in a virtual environment for you.)
|
||||
|
||||
### Sanity tests
|
||||
|
||||
The following commands show how to run ansible-test sanity tests:
|
||||
|
||||
```.bash
|
||||
# Run basic sanity tests for all files in the collection:
|
||||
nox -Re ansible-test-sanity-devel
|
||||
|
||||
# Run basic sanity tests for the given files and directories:
|
||||
nox -Re ansible-test-sanity-devel -- plugins/modules/system/pids.py tests/integration/targets/pids/
|
||||
|
||||
# Run all other sanity tests for all files in the collection:
|
||||
nox -R
|
||||
```
|
||||
|
||||
If you replace `-Re` with `-e`, respectively. leave `-R` away, then the virtual environments will be re-created. The `-R` re-uses them (if they already exist).
|
||||
|
||||
### Unit tests
|
||||
|
||||
The following commands show how to run unit tests:
|
||||
|
||||
```.bash
|
||||
# Run all unit tests:
|
||||
nox -Re ansible-test-units-devel
|
||||
|
||||
# Run all unit tests for one Python version (a lot faster):
|
||||
nox -Re ansible-test-units-devel -- --python 3.13
|
||||
|
||||
# Run a specific unit test (for the nmcli module) for one Python version:
|
||||
nox -Re ansible-test-units-devel -- --python 3.13 tests/unit/plugins/modules/net_tools/test_nmcli.py
|
||||
```
|
||||
|
||||
If you replace `-Re` with `-e`, then the virtual environments will be re-created. The `-R` re-uses them (if they already exist).
|
||||
|
||||
## Run basic sanity, unit or integration tests locally (with ansible-test)
|
||||
|
||||
Instead of using antsibull-nox, you can also run sanity and unit tests with ansible-test directly.
|
||||
This also allows you to run integration tests.
|
||||
|
||||
You have to check out the repository into a specific path structure to be able to run `ansible-test`. The path to the git checkout must end with `.../ansible_collections/community/general`. Please see [our testing guide](https://github.com/ansible/community-docs/blob/main/test_pr_locally_guide.rst) for instructions on how to check out the repository into a correct path structure. The short version of these instructions is:
|
||||
|
||||
@@ -56,20 +98,27 @@ 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
|
||||
### Basic sanity tests
|
||||
|
||||
The following commands show how to run sanity tests:
|
||||
The following commands show how to run basic sanity tests:
|
||||
|
||||
```.bash
|
||||
# Run sanity tests for all files in the collection:
|
||||
# Run basic sanity tests for all files in the collection:
|
||||
ansible-test sanity --docker -v
|
||||
|
||||
# Run sanity tests for the given files and directories:
|
||||
# Run basic sanity tests for the given files and directories:
|
||||
ansible-test sanity --docker -v plugins/modules/system/pids.py tests/integration/targets/pids/
|
||||
```
|
||||
|
||||
### Unit tests
|
||||
|
||||
Note that for running unit tests, you need to install required collections in the same folder structure that `community.general` is checked out in.
|
||||
Right now, you need to install [`community.internal_test_tools`](https://github.com/ansible-collections/community.internal_test_tools).
|
||||
If you want to use the latest version from GitHub, you can run:
|
||||
```
|
||||
git clone https://github.com/ansible-collections/community.internal_test_tools.git ~/dev/ansible_collections/community/internal_test_tools
|
||||
```
|
||||
|
||||
The following commands show how to run unit tests:
|
||||
|
||||
```.bash
|
||||
@@ -85,6 +134,16 @@ ansible-test units --docker -v --python 3.8 tests/unit/plugins/modules/net_tools
|
||||
|
||||
### Integration tests
|
||||
|
||||
Note that for running integration tests, you need to install required collections in the same folder structure that `community.general` is checked out in.
|
||||
Right now, depending on the test, you need to install [`ansible.posix`](https://github.com/ansible-collections/ansible.posix), [`community.crypto`](https://github.com/ansible-collections/community.crypto), and [`community.docker`](https://github.com/ansible-collections/community.docker):
|
||||
If you want to use the latest versions from GitHub, you can run:
|
||||
```
|
||||
mkdir -p ~/dev/ansible_collections/ansible
|
||||
git clone https://github.com/ansible-collections/ansible.posix.git ~/dev/ansible_collections/ansible/posix
|
||||
git clone https://github.com/ansible-collections/community.crypto.git ~/dev/ansible_collections/community/crypto
|
||||
git clone https://github.com/ansible-collections/community.docker.git ~/dev/ansible_collections/community/docker
|
||||
```
|
||||
|
||||
The following commands show how to run integration tests:
|
||||
|
||||
#### In Docker
|
||||
@@ -92,8 +151,8 @@ The following commands show how to run integration tests:
|
||||
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`.
|
||||
- `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
|
||||
|
||||
@@ -9,6 +9,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
[](https://docs.ansible.com/ansible/latest/collections/community/general/)
|
||||
[](https://dev.azure.com/ansible/community.general/_build?definitionId=31)
|
||||
[](https://github.com/ansible-collections/community.general/actions)
|
||||
[](https://github.com/ansible-collections/community.general/actions)
|
||||
[](https://codecov.io/gh/ansible-collections/community.general)
|
||||
[](https://api.reuse.software/info/github.com/ansible-collections/community.general)
|
||||
|
||||
@@ -140,4 +141,4 @@ See [LICENSES/GPL-3.0-or-later.txt](https://github.com/ansible-collections/commu
|
||||
|
||||
Parts of the collection are licensed under the [BSD 2-Clause license](https://github.com/ansible-collections/community.general/blob/stable-9/LICENSES/BSD-2-Clause.txt), the [MIT license](https://github.com/ansible-collections/community.general/blob/stable-9/LICENSES/MIT.txt), and the [PSF 2.0 license](https://github.com/ansible-collections/community.general/blob/stable-9/LICENSES/PSF-2.0.txt).
|
||||
|
||||
All files have a machine readable `SDPX-License-Identifier:` comment denoting its respective license(s) or an equivalent entry in an accompanying `.license` file. Only changelog fragments (which will not be part of a release) are covered by a blanket statement in `.reuse/dep5`. This conforms to the [REUSE specification](https://reuse.software/spec/).
|
||||
All files have a machine readable `SDPX-License-Identifier:` comment denoting its respective license(s) or an equivalent entry in an accompanying `.license` file. Only changelog fragments (which will not be part of a release) are covered by a blanket statement in `REUSE.toml`. This conforms to the [REUSE specification](https://reuse.software/spec/).
|
||||
|
||||
11
REUSE.toml
Normal file
11
REUSE.toml
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
|
||||
|
||||
version = 1
|
||||
|
||||
[[annotations]]
|
||||
path = "changelogs/fragments/**"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "Ansible Project"
|
||||
SPDX-License-Identifier = "GPL-3.0-or-later"
|
||||
61
antsibull-nox.toml
Normal file
61
antsibull-nox.toml
Normal file
@@ -0,0 +1,61 @@
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
# SPDX-FileCopyrightText: 2025 Felix Fontein <felix@fontein.de>
|
||||
|
||||
[collection_sources]
|
||||
"ansible.posix" = "git+https://github.com/ansible-collections/ansible.posix.git,main"
|
||||
"community.crypto" = "git+https://github.com/ansible-collections/community.crypto.git,main"
|
||||
"community.docker" = "git+https://github.com/ansible-collections/community.docker.git,main"
|
||||
"community.internal_test_tools" = "git+https://github.com/ansible-collections/community.internal_test_tools.git,main"
|
||||
|
||||
[collection_sources_per_ansible.'2.13']
|
||||
"community.crypto" = "git+https://github.com/ansible-collections/community.crypto.git,stable-2"
|
||||
|
||||
[collection_sources_per_ansible.'2.14']
|
||||
"community.crypto" = "git+https://github.com/ansible-collections/community.crypto.git,stable-2"
|
||||
|
||||
[collection_sources_per_ansible.'2.15']
|
||||
# community.crypto's main branch needs ansible-core >= 2.17
|
||||
"community.crypto" = "git+https://github.com/ansible-collections/community.crypto.git,stable-2"
|
||||
|
||||
[collection_sources_per_ansible.'2.16']
|
||||
# community.crypto's main branch needs ansible-core >= 2.17
|
||||
"community.crypto" = "git+https://github.com/ansible-collections/community.crypto.git,stable-2"
|
||||
|
||||
[sessions]
|
||||
|
||||
[sessions.docs_check]
|
||||
validate_collection_refs="all"
|
||||
|
||||
[sessions.license_check]
|
||||
|
||||
[sessions.extra_checks]
|
||||
run_no_unwanted_files = true
|
||||
no_unwanted_files_module_extensions = [".py"]
|
||||
no_unwanted_files_yaml_extensions = [".yml"]
|
||||
run_action_groups = true
|
||||
|
||||
[[sessions.extra_checks.action_groups_config]]
|
||||
name = "consul"
|
||||
pattern = "^consul_.*$"
|
||||
exclusions = [
|
||||
"consul_acl",
|
||||
"consul_acl_bootstrap",
|
||||
"consul_kv",
|
||||
]
|
||||
doc_fragment = "community.general.consul.actiongroup_consul"
|
||||
|
||||
[[sessions.extra_checks.action_groups_config]]
|
||||
name = "proxmox"
|
||||
pattern = "^proxmox(_.*)?$"
|
||||
exclusions = []
|
||||
doc_fragment = "community.general.proxmox.actiongroup_proxmox"
|
||||
|
||||
[sessions.build_import_check]
|
||||
run_galaxy_importer = true
|
||||
|
||||
[sessions.ansible_test_sanity]
|
||||
include_devel = true
|
||||
|
||||
[sessions.ansible_test_units]
|
||||
include_devel = true
|
||||
@@ -1563,3 +1563,165 @@ releases:
|
||||
- 9578-redhat_subscription-no-remove-on-unregister.yml
|
||||
- 9621-keycloak_client-sanitize-saml-encryption-key.yml
|
||||
release_date: '2025-01-27'
|
||||
9.5.5:
|
||||
changes:
|
||||
bugfixes:
|
||||
- apache2_mod_proxy - make compatible with Python 3 (https://github.com/ansible-collections/community.general/pull/9762).
|
||||
- apache2_mod_proxy - passing the cluster's page as referer for the member's
|
||||
pages. This makes the module actually work again for halfway modern Apache
|
||||
versions. According to some comments founds on the net the referer was required
|
||||
since at least 2019 for some versions of Apache 2 (https://github.com/ansible-collections/community.general/pull/9762).
|
||||
- cloudflare_dns - fix crash when deleting a DNS record or when updating a
|
||||
record with ``solo=true`` (https://github.com/ansible-collections/community.general/issues/9652,
|
||||
https://github.com/ansible-collections/community.general/pull/9649).
|
||||
- 'elasticsearch_plugin - fix ``ERROR: D is not a recognized option`` issue
|
||||
when configuring proxy settings (https://github.com/ansible-collections/community.general/pull/9774,
|
||||
https://github.com/ansible-collections/community.general/issues/9773).'
|
||||
- keycloak_client - fix and improve existing tests. The module showed a diff
|
||||
without actual changes, solved by improving the ``normalise_cr()`` function
|
||||
(https://github.com/ansible-collections/community.general/pull/9644).
|
||||
- keycloak_client - in check mode, detect whether the lists in before client
|
||||
(for example redirect URI list) contain items that the lists in the desired
|
||||
client do not contain (https://github.com/ansible-collections/community.general/pull/9739).
|
||||
- passwordstore lookup plugin - fix subkey creation even when ``create=false``
|
||||
(https://github.com/ansible-collections/community.general/issues/9105, https://github.com/ansible-collections/community.general/pull/9106).
|
||||
- 'proxmox inventory plugin - plugin did not update cache correctly after
|
||||
``meta: refresh_inventory`` (https://github.com/ansible-collections/community.general/issues/9710,
|
||||
https://github.com/ansible-collections/community.general/pull/9760).'
|
||||
- 'redhat_subscription - use the "enable_content" option (when available)
|
||||
when
|
||||
|
||||
registering using D-Bus, to ensure that subscription-manager enables the
|
||||
|
||||
content on registration; this is particular important on EL 10+ and Fedora
|
||||
|
||||
41+
|
||||
|
||||
(https://github.com/ansible-collections/community.general/pull/9778).
|
||||
|
||||
'
|
||||
- xml - ensure file descriptor is closed (https://github.com/ansible-collections/community.general/pull/9695).
|
||||
release_summary: Regular bugfix release.
|
||||
fragments:
|
||||
- 9.5.5.yml
|
||||
- 9106-passwordstore-fix-subkey-creation-even-when-create-==-false.yml
|
||||
- 9644-kc_client-test-improvement-and-fix.yaml
|
||||
- 9649-cloudflare_dns-fix-crash-when-deleting-record.yml
|
||||
- 9695-xml-close-file.yml
|
||||
- 9739-keycloak_client-compare-before-desired-directly.yml
|
||||
- 9760-proxmox-inventory.yml
|
||||
- 9762-apache2_mod_proxy.yml
|
||||
- 9774-fix-elasticsearch_plugin-proxy-settings.yml
|
||||
- 9778-redhat_subscription-ensure-to-enable-content.yml
|
||||
release_date: '2025-02-24'
|
||||
9.5.6:
|
||||
changes:
|
||||
bugfixes:
|
||||
- cloudlare_dns - handle exhausted response stream in case of HTTP errors
|
||||
to show nice error message to the user (https://github.com/ansible-collections/community.general/issues/9782,
|
||||
https://github.com/ansible-collections/community.general/pull/9818).
|
||||
- dnf_versionlock - add support for dnf5 (https://github.com/ansible-collections/community.general/issues/9556).
|
||||
- homebrew_cask - handle unusual brew version strings (https://github.com/ansible-collections/community.general/issues/8432,
|
||||
https://github.com/ansible-collections/community.general/pull/9881).
|
||||
- ipa_host - module revoked existing host certificates even if ``user_certificate``
|
||||
was not given (https://github.com/ansible-collections/community.general/pull/9694).
|
||||
- nmcli - enable changing only the order of DNS servers or search suffixes
|
||||
(https://github.com/ansible-collections/community.general/issues/8724, https://github.com/ansible-collections/community.general/pull/9880).
|
||||
- proxmox_vm_info - the module no longer expects that the key ``template``
|
||||
exists in a dictionary returned by Proxmox (https://github.com/ansible-collections/community.general/issues/9875,
|
||||
https://github.com/ansible-collections/community.general/pull/9910).
|
||||
- sudoers - display stdout and stderr raised while failed validation (https://github.com/ansible-collections/community.general/issues/9674,
|
||||
https://github.com/ansible-collections/community.general/pull/9871).
|
||||
minor_changes:
|
||||
- consul_token - fix idempotency when ``policies`` or ``roles`` are supplied
|
||||
by name (https://github.com/ansible-collections/community.general/issues/9841,
|
||||
https://github.com/ansible-collections/community.general/pull/9845).
|
||||
release_summary: Regular bugfix release.
|
||||
fragments:
|
||||
- 9.5.6.yml
|
||||
- 9694-ipa-host-certificate-revoked.yml
|
||||
- 9818-cloudflare-dns-exhausted-response.yml
|
||||
- 9845-consul_token_idempotency.yml
|
||||
- 9875-proxmox-dont-expect-key-template-to-exist.yml
|
||||
- 9880-nmcli-fix-reorder-same-dns-nameservers-search-suffixes.yml
|
||||
- dnf_versionlock.yml
|
||||
- homebrew_cask.yml
|
||||
- sudoers.yml
|
||||
release_date: '2025-03-24'
|
||||
9.5.7:
|
||||
changes:
|
||||
bugfixes:
|
||||
- dependent look plugin - make compatible with ansible-core's Data Tagging
|
||||
feature (https://github.com/ansible-collections/community.general/pull/9833).
|
||||
- diy callback plugin - make compatible with ansible-core's Data Tagging feature
|
||||
(https://github.com/ansible-collections/community.general/pull/9833).
|
||||
- "github_deploy_key - check that key really exists on 422\_to avoid masking\
|
||||
\ other errors (https://github.com/ansible-collections/community.general/issues/6718,\
|
||||
\ https://github.com/ansible-collections/community.general/pull/10011)."
|
||||
- hashids and unicode_normalize filter plugins - avoid deprecated ``AnsibleFilterTypeError``
|
||||
on ansible-core 2.19 (https://github.com/ansible-collections/community.general/pull/9992).
|
||||
- keycloak_authentication - fix authentification config duplication for Keycloak
|
||||
< 26.2.0 (https://github.com/ansible-collections/community.general/pull/9987).
|
||||
- keycloak_client - fix the idempotency regression by normalizing the Keycloak
|
||||
response for ``after_client`` (https://github.com/ansible-collections/community.general/issues/9905,
|
||||
https://github.com/ansible-collections/community.general/pull/9976).
|
||||
- proxmox inventory plugin - fix ``ansible_host`` staying empty for certain
|
||||
Proxmox nodes (https://github.com/ansible-collections/community.general/issues/5906,
|
||||
https://github.com/ansible-collections/community.general/pull/9952).
|
||||
- proxmox_disk - fail gracefully if ``storage`` is required but not provided
|
||||
by the user (https://github.com/ansible-collections/community.general/issues/9941,
|
||||
https://github.com/ansible-collections/community.general/pull/9963).
|
||||
- reveal_ansible_type filter plugin and ansible_type test plugin - make compatible
|
||||
with ansible-core's Data Tagging feature (https://github.com/ansible-collections/community.general/pull/9833).
|
||||
- sysrc - no longer always reporting ``changed=true`` when ``state=absent``.
|
||||
This fixes the method ``exists()`` (https://github.com/ansible-collections/community.general/issues/10004,
|
||||
https://github.com/ansible-collections/community.general/pull/10005).
|
||||
- yaml callback plugin - use ansible-core internals to avoid breakage with
|
||||
Data Tagging (https://github.com/ansible-collections/community.general/pull/9833).
|
||||
known_issues:
|
||||
- reveal_ansible_type filter plugin and ansible_type test plugin - note that
|
||||
ansible-core's Data Tagging feature implements new aliases, such as ``_AnsibleTaggedStr``
|
||||
for ``str``, ``_AnsibleTaggedInt`` for ``int``, and ``_AnsibleTaggedFloat``
|
||||
for ``float`` (https://github.com/ansible-collections/community.general/pull/9833).
|
||||
minor_changes:
|
||||
- apache2_module - added workaround for new PHP module name, from ``php7_module``
|
||||
to ``php_module`` (https://github.com/ansible-collections/community.general/pull/9951).
|
||||
release_summary: Regular bugfix release.
|
||||
fragments:
|
||||
- 10005-fix-method-exists-in-sysrc.yml
|
||||
- 10011-github_deploy_key-check-key-present.yml
|
||||
- 9.5.7.yml
|
||||
- 9833-data-tagging.yml
|
||||
- 9951-mod-php-identifier.yml
|
||||
- 9952-proxmox-inventory-plugin-improve-ansible_host.yml
|
||||
- 9963-proxmox_disk-storage.yml
|
||||
- 9976-keycloak_client-fix-idempotency-regression.yml
|
||||
- 9987-keycloak-auth-flow-fix-config.yaml
|
||||
- 9992-filtertypeerror.yml
|
||||
release_date: '2025-04-21'
|
||||
9.5.8:
|
||||
changes:
|
||||
bugfixes:
|
||||
- cobbler_system - fix bug with Cobbler >= 3.4.0 caused by giving more than
|
||||
2 positional arguments to ``CobblerXMLRPCInterface.get_system_handle()``
|
||||
(https://github.com/ansible-collections/community.general/issues/8506, https://github.com/ansible-collections/community.general/pull/10145).
|
||||
- kdeconfig - allow option values beginning with a dash (https://github.com/ansible-collections/community.general/issues/10127,
|
||||
https://github.com/ansible-collections/community.general/pull/10128).
|
||||
- keycloak_user_rolemapping - fix ``--diff`` mode (https://github.com/ansible-collections/community.general/issues/10067,
|
||||
https://github.com/ansible-collections/community.general/pull/10075).
|
||||
- pickle cache plugin - avoid extra JSON serialization with ansible-core >=
|
||||
2.19 (https://github.com/ansible-collections/community.general/pull/10136).
|
||||
- rundeck_acl_policy - ensure that project ACLs are sent to the correct endpoint
|
||||
(https://github.com/ansible-collections/community.general/pull/10097).
|
||||
- sysrc - split the output of ``sysrc -e -a`` on the first ``=`` only (https://github.com/ansible-collections/community.general/issues/10120,
|
||||
https://github.com/ansible-collections/community.general/pull/10121).
|
||||
release_summary: Regular bugfix release.
|
||||
fragments:
|
||||
- 10075-keycloak_user_rolemapping-diff.yml
|
||||
- 10097-fix-rundeck_acl_policy-project-endpoint.yml
|
||||
- 10121-sysrc-fix-split-first-separator.yml
|
||||
- 10128-mark-end-of-options.yml
|
||||
- 10136-cache-pickle-json.yml
|
||||
- 10145-fix-typeerror-cobbler-xmlrpc.yml
|
||||
- 9.5.8.yml
|
||||
release_date: '2025-05-19'
|
||||
|
||||
@@ -65,7 +65,7 @@ All three statements are equivalent and give:
|
||||
|
||||
.. note:: Be aware that in most cases, filter calls without any argument require ``flatten=true``, otherwise the input is returned as result. The reason for this is, that the input is considered as a variable argument and is wrapped by an additional outer list. ``flatten=true`` ensures that this list is removed before the input is processed by the filter logic.
|
||||
|
||||
The filters ansplugin:`community.general.lists_difference#filter` or :ansplugin:`community.general.lists_symmetric_difference#filter` can be used in the same way as the filters in the examples above. They calculate the difference or the symmetric difference between two or more lists and preserve the item order.
|
||||
The filters :ansplugin:`community.general.lists_difference#filter` or :ansplugin:`community.general.lists_symmetric_difference#filter` can be used in the same way as the filters in the examples above. They calculate the difference or the symmetric difference between two or more lists and preserve the item order.
|
||||
|
||||
For example, the symmetric difference of ``A``, ``B`` and ``C`` may be written as:
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ To get a hash map with all ports and names of a cluster:
|
||||
var: item
|
||||
loop: "{{ domain_definition | community.general.json_query(server_name_cluster1_query) }}"
|
||||
vars:
|
||||
server_name_cluster1_query: "domain.server[?cluster=='cluster2'].{name: name, port: port}"
|
||||
server_name_cluster1_query: "domain.server[?cluster=='cluster1'].{name: name, port: port}"
|
||||
|
||||
To extract ports from all clusters with name starting with 'server1':
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
namespace: community
|
||||
name: general
|
||||
version: 9.5.4
|
||||
version: 9.5.8
|
||||
readme: README.md
|
||||
authors:
|
||||
- Ansible (https://github.com/ansible)
|
||||
|
||||
38
noxfile.py
Normal file
38
noxfile.py
Normal file
@@ -0,0 +1,38 @@
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
# SPDX-FileCopyrightText: 2025 Felix Fontein <felix@fontein.de>
|
||||
|
||||
# /// script
|
||||
# dependencies = ["nox>=2025.02.09", "antsibull-nox"]
|
||||
# ///
|
||||
|
||||
import sys
|
||||
|
||||
import nox
|
||||
|
||||
|
||||
try:
|
||||
import antsibull_nox
|
||||
except ImportError:
|
||||
print("You need to install antsibull-nox in the same Python environment as nox.")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
antsibull_nox.load_antsibull_nox_toml()
|
||||
|
||||
|
||||
@nox.session(name="aliases", python=False, default=True)
|
||||
def aliases(session: nox.Session) -> None:
|
||||
session.run("python", "tests/sanity/extra/aliases.py")
|
||||
|
||||
|
||||
@nox.session(name="botmeta", default=True)
|
||||
def botmeta(session: nox.Session) -> None:
|
||||
session.install("PyYAML", "voluptuous")
|
||||
session.run("python", "tests/sanity/extra/botmeta.py")
|
||||
|
||||
|
||||
# Allow to run the noxfile with `python noxfile.py`, `pipx run noxfile.py`, or similar.
|
||||
# Requires nox >= 2025.02.09
|
||||
if __name__ == "__main__":
|
||||
nox.main()
|
||||
1
plugins/cache/pickle.py
vendored
1
plugins/cache/pickle.py
vendored
@@ -57,6 +57,7 @@ class CacheModule(BaseFileCacheModule):
|
||||
"""
|
||||
A caching module backed by pickle files.
|
||||
"""
|
||||
_persistent = False # prevent unnecessary JSON serialization and key munging
|
||||
|
||||
def _load(self, filepath):
|
||||
# Pickle is a binary format
|
||||
|
||||
@@ -786,6 +786,12 @@ from ansible.vars.manager import VariableManager
|
||||
from ansible.plugins.callback.default import CallbackModule as Default
|
||||
from ansible.module_utils.common.text.converters import to_text
|
||||
|
||||
try:
|
||||
from ansible.template import trust_as_template # noqa: F401, pylint: disable=unused-import
|
||||
SUPPORTS_DATA_TAGGING = True
|
||||
except ImportError:
|
||||
SUPPORTS_DATA_TAGGING = False
|
||||
|
||||
|
||||
class DummyStdout(object):
|
||||
def flush(self):
|
||||
@@ -839,7 +845,10 @@ class CallbackModule(Default):
|
||||
return _ret
|
||||
|
||||
def _using_diy(self, spec):
|
||||
return (spec['msg'] is not None) and (spec['msg'] != spec['vars']['omit'])
|
||||
sentinel = object()
|
||||
omit = spec['vars'].get('omit', sentinel)
|
||||
# With Data Tagging, omit is sentinel
|
||||
return (spec['msg'] is not None) and (spec['msg'] != omit or omit is sentinel)
|
||||
|
||||
def _parent_has_callback(self):
|
||||
return hasattr(super(CallbackModule, self), sys._getframe(1).f_code.co_name)
|
||||
@@ -895,7 +904,7 @@ class CallbackModule(Default):
|
||||
)
|
||||
_ret.update(_all)
|
||||
|
||||
_ret.update(_ret.get(self.DIY_NS, {self.DIY_NS: CallbackDIYDict()}))
|
||||
_ret.update(_ret.get(self.DIY_NS, {self.DIY_NS: {} if SUPPORTS_DATA_TAGGING else CallbackDIYDict()}))
|
||||
|
||||
_ret[self.DIY_NS].update({'playbook': {}})
|
||||
_playbook_attributes = ['entries', 'file_name', 'basedir']
|
||||
|
||||
@@ -49,29 +49,77 @@ def should_use_block(value):
|
||||
return False
|
||||
|
||||
|
||||
class MyDumper(AnsibleDumper):
|
||||
def represent_scalar(self, tag, value, style=None):
|
||||
"""Uses block style for multi-line strings"""
|
||||
if style is None:
|
||||
if should_use_block(value):
|
||||
style = '|'
|
||||
# we care more about readable than accuracy, so...
|
||||
# ...no trailing space
|
||||
value = value.rstrip()
|
||||
# ...and non-printable characters
|
||||
value = ''.join(x for x in value if x in string.printable or ord(x) >= 0xA0)
|
||||
# ...tabs prevent blocks from expanding
|
||||
value = value.expandtabs()
|
||||
# ...and odd bits of whitespace
|
||||
value = re.sub(r'[\x0b\x0c\r]', '', value)
|
||||
# ...as does trailing space
|
||||
value = re.sub(r' +\n', '\n', value)
|
||||
else:
|
||||
style = self.default_style
|
||||
node = yaml.representer.ScalarNode(tag, value, style=style)
|
||||
if self.alias_key is not None:
|
||||
self.represented_objects[self.alias_key] = node
|
||||
return node
|
||||
try:
|
||||
class MyDumper(AnsibleDumper): # pylint: disable=inherit-non-class
|
||||
def represent_scalar(self, tag, value, style=None):
|
||||
"""Uses block style for multi-line strings"""
|
||||
if style is None:
|
||||
if should_use_block(value):
|
||||
style = '|'
|
||||
# we care more about readable than accuracy, so...
|
||||
# ...no trailing space
|
||||
value = value.rstrip()
|
||||
# ...and non-printable characters
|
||||
value = ''.join(x for x in value if x in string.printable or ord(x) >= 0xA0)
|
||||
# ...tabs prevent blocks from expanding
|
||||
value = value.expandtabs()
|
||||
# ...and odd bits of whitespace
|
||||
value = re.sub(r'[\x0b\x0c\r]', '', value)
|
||||
# ...as does trailing space
|
||||
value = re.sub(r' +\n', '\n', value)
|
||||
else:
|
||||
style = self.default_style
|
||||
node = yaml.representer.ScalarNode(tag, value, style=style)
|
||||
if self.alias_key is not None:
|
||||
self.represented_objects[self.alias_key] = node
|
||||
return node
|
||||
except: # noqa: E722, pylint: disable=bare-except
|
||||
# This happens with Data Tagging, see https://github.com/ansible/ansible/issues/84781
|
||||
# Until there is a better solution we'll resort to using ansible-core internals.
|
||||
from ansible._internal._yaml import _dumper
|
||||
import typing as t
|
||||
|
||||
class MyDumper(_dumper._BaseDumper):
|
||||
# This code is mostly taken from ansible._internal._yaml._dumper
|
||||
@classmethod
|
||||
def _register_representers(cls) -> None:
|
||||
cls.add_multi_representer(_dumper.AnsibleTaggedObject, cls.represent_ansible_tagged_object)
|
||||
cls.add_multi_representer(_dumper.Tripwire, cls.represent_tripwire)
|
||||
cls.add_multi_representer(_dumper.c.Mapping, _dumper.SafeRepresenter.represent_dict)
|
||||
cls.add_multi_representer(_dumper.c.Sequence, _dumper.SafeRepresenter.represent_list)
|
||||
|
||||
def represent_ansible_tagged_object(self, data):
|
||||
if ciphertext := _dumper.VaultHelper.get_ciphertext(data, with_tags=False):
|
||||
return self.represent_scalar('!vault', ciphertext, style='|')
|
||||
|
||||
return self.represent_data(_dumper.AnsibleTagHelper.as_native_type(data)) # automatically decrypts encrypted strings
|
||||
|
||||
def represent_tripwire(self, data: _dumper.Tripwire) -> t.NoReturn:
|
||||
data.trip()
|
||||
|
||||
# The following function is the same as in the try/except
|
||||
def represent_scalar(self, tag, value, style=None):
|
||||
"""Uses block style for multi-line strings"""
|
||||
if style is None:
|
||||
if should_use_block(value):
|
||||
style = '|'
|
||||
# we care more about readable than accuracy, so...
|
||||
# ...no trailing space
|
||||
value = value.rstrip()
|
||||
# ...and non-printable characters
|
||||
value = ''.join(x for x in value if x in string.printable or ord(x) >= 0xA0)
|
||||
# ...tabs prevent blocks from expanding
|
||||
value = value.expandtabs()
|
||||
# ...and odd bits of whitespace
|
||||
value = re.sub(r'[\x0b\x0c\r]', '', value)
|
||||
# ...as does trailing space
|
||||
value = re.sub(r' +\n', '\n', value)
|
||||
else:
|
||||
style = self.default_style
|
||||
node = yaml.representer.ScalarNode(tag, value, style=style)
|
||||
if self.alias_key is not None:
|
||||
self.represented_objects[self.alias_key] = node
|
||||
return node
|
||||
|
||||
|
||||
class CallbackModule(Default):
|
||||
|
||||
@@ -10,12 +10,16 @@ __metaclass__ = type
|
||||
from ansible.errors import (
|
||||
AnsibleError,
|
||||
AnsibleFilterError,
|
||||
AnsibleFilterTypeError,
|
||||
)
|
||||
|
||||
from ansible.module_utils.common.text.converters import to_native
|
||||
from ansible.module_utils.common.collections import is_sequence
|
||||
|
||||
try:
|
||||
from ansible.errors import AnsibleTypeError
|
||||
except ImportError:
|
||||
from ansible.errors import AnsibleFilterTypeError as AnsibleTypeError
|
||||
|
||||
try:
|
||||
from hashids import Hashids
|
||||
HAS_HASHIDS = True
|
||||
@@ -64,7 +68,7 @@ def hashids_encode(nums, salt=None, alphabet=None, min_length=None):
|
||||
try:
|
||||
hashid = hashids.encode(*nums)
|
||||
except TypeError as e:
|
||||
raise AnsibleFilterTypeError(
|
||||
raise AnsibleTypeError(
|
||||
"Data to encode must by a tuple or list of ints: %s" % to_native(e)
|
||||
)
|
||||
|
||||
|
||||
@@ -23,93 +23,107 @@ DOCUMENTATION = '''
|
||||
type: dictionary
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# Substitution converts str to AnsibleUnicode
|
||||
# -------------------------------------------
|
||||
EXAMPLES = r"""
|
||||
# Substitution converts str to AnsibleUnicode or _AnsibleTaggedStr
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# String. AnsibleUnicode.
|
||||
data: "abc"
|
||||
result: '{{ data | community.general.reveal_ansible_type }}'
|
||||
# result => AnsibleUnicode
|
||||
# String. AnsibleUnicode or _AnsibleTaggedStr.
|
||||
- data: "abc"
|
||||
result: '{{ data | community.general.reveal_ansible_type }}'
|
||||
# result => AnsibleUnicode (or _AnsibleTaggedStr)
|
||||
|
||||
# String. AnsibleUnicode alias str.
|
||||
alias: {"AnsibleUnicode": "str"}
|
||||
data: "abc"
|
||||
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
|
||||
# String. AnsibleUnicode/_AnsibleTaggedStr alias str.
|
||||
- alias: {"AnsibleUnicode": "str", "_AnsibleTaggedStr": "str"}
|
||||
data: "abc"
|
||||
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
|
||||
# result => str
|
||||
|
||||
# List. All items are AnsibleUnicode.
|
||||
data: ["a", "b", "c"]
|
||||
result: '{{ data | community.general.reveal_ansible_type }}'
|
||||
# result => list[AnsibleUnicode]
|
||||
# List. All items are AnsibleUnicode/_AnsibleTaggedStr.
|
||||
- data: ["a", "b", "c"]
|
||||
result: '{{ data | community.general.reveal_ansible_type }}'
|
||||
# result => list[AnsibleUnicode] or list[_AnsibleTaggedStr]
|
||||
|
||||
# Dictionary. All keys are AnsibleUnicode. All values are AnsibleUnicode.
|
||||
data: {"a": "foo", "b": "bar", "c": "baz"}
|
||||
result: '{{ data | community.general.reveal_ansible_type }}'
|
||||
# result => dict[AnsibleUnicode, AnsibleUnicode]
|
||||
# Dictionary. All keys and values are AnsibleUnicode/_AnsibleTaggedStr.
|
||||
- data: {"a": "foo", "b": "bar", "c": "baz"}
|
||||
result: '{{ data | community.general.reveal_ansible_type }}'
|
||||
# result => dict[AnsibleUnicode, AnsibleUnicode] or dict[_AnsibleTaggedStr, _AnsibleTaggedStr]
|
||||
|
||||
# No substitution and no alias. Type of strings is str
|
||||
# ----------------------------------------------------
|
||||
|
||||
# String
|
||||
result: '{{ "abc" | community.general.reveal_ansible_type }}'
|
||||
- result: '{{ "abc" | community.general.reveal_ansible_type }}'
|
||||
# result => str
|
||||
|
||||
# Integer
|
||||
result: '{{ 123 | community.general.reveal_ansible_type }}'
|
||||
- result: '{{ 123 | community.general.reveal_ansible_type }}'
|
||||
# result => int
|
||||
|
||||
# Float
|
||||
result: '{{ 123.45 | community.general.reveal_ansible_type }}'
|
||||
- result: '{{ 123.45 | community.general.reveal_ansible_type }}'
|
||||
# result => float
|
||||
|
||||
# Boolean
|
||||
result: '{{ true | community.general.reveal_ansible_type }}'
|
||||
- result: '{{ true | community.general.reveal_ansible_type }}'
|
||||
# result => bool
|
||||
|
||||
# List. All items are strings.
|
||||
result: '{{ ["a", "b", "c"] | community.general.reveal_ansible_type }}'
|
||||
- result: '{{ ["a", "b", "c"] | community.general.reveal_ansible_type }}'
|
||||
# result => list[str]
|
||||
|
||||
# List of dictionaries.
|
||||
result: '{{ [{"a": 1}, {"b": 2}] | community.general.reveal_ansible_type }}'
|
||||
- result: '{{ [{"a": 1}, {"b": 2}] | community.general.reveal_ansible_type }}'
|
||||
# result => list[dict]
|
||||
|
||||
# Dictionary. All keys are strings. All values are integers.
|
||||
result: '{{ {"a": 1} | community.general.reveal_ansible_type }}'
|
||||
- result: '{{ {"a": 1} | community.general.reveal_ansible_type }}'
|
||||
# result => dict[str, int]
|
||||
|
||||
# Dictionary. All keys are strings. All values are integers.
|
||||
result: '{{ {"a": 1, "b": 2} | community.general.reveal_ansible_type }}'
|
||||
- result: '{{ {"a": 1, "b": 2} | community.general.reveal_ansible_type }}'
|
||||
# result => dict[str, int]
|
||||
|
||||
# Type of strings is AnsibleUnicode or str
|
||||
# ----------------------------------------
|
||||
# Type of strings is AnsibleUnicode, _AnsibleTaggedStr, or str
|
||||
# ------------------------------------------------------------
|
||||
|
||||
# Dictionary. The keys are integers or strings. All values are strings.
|
||||
alias: {"AnsibleUnicode": "str"}
|
||||
data: {1: 'a', 'b': 'b'}
|
||||
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
|
||||
- alias:
|
||||
AnsibleUnicode: str
|
||||
_AnsibleTaggedStr: str
|
||||
_AnsibleTaggedInt: int
|
||||
data: {1: 'a', 'b': 'b'}
|
||||
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
|
||||
# result => dict[int|str, str]
|
||||
|
||||
# Dictionary. All keys are integers. All values are keys.
|
||||
alias: {"AnsibleUnicode": "str"}
|
||||
data: {1: 'a', 2: 'b'}
|
||||
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
|
||||
- alias:
|
||||
AnsibleUnicode: str
|
||||
_AnsibleTaggedStr: str
|
||||
_AnsibleTaggedInt: int
|
||||
data: {1: 'a', 2: 'b'}
|
||||
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
|
||||
# result => dict[int, str]
|
||||
|
||||
# Dictionary. All keys are strings. Multiple types values.
|
||||
alias: {"AnsibleUnicode": "str"}
|
||||
data: {'a': 1, 'b': 1.1, 'c': 'abc', 'd': True, 'e': ['x', 'y', 'z'], 'f': {'x': 1, 'y': 2}}
|
||||
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
|
||||
- alias:
|
||||
AnsibleUnicode: str
|
||||
_AnsibleTaggedStr: str
|
||||
_AnsibleTaggedInt: int
|
||||
_AnsibleTaggedFloat: float
|
||||
data: {'a': 1, 'b': 1.1, 'c': 'abc', 'd': true, 'e': ['x', 'y', 'z'], 'f': {'x': 1, 'y': 2}}
|
||||
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
|
||||
# result => dict[str, bool|dict|float|int|list|str]
|
||||
|
||||
# List. Multiple types items.
|
||||
alias: {"AnsibleUnicode": "str"}
|
||||
data: [1, 2, 1.1, 'abc', True, ['x', 'y', 'z'], {'x': 1, 'y': 2}]
|
||||
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
|
||||
- alias:
|
||||
AnsibleUnicode: str
|
||||
_AnsibleTaggedStr: str
|
||||
_AnsibleTaggedInt: int
|
||||
_AnsibleTaggedFloat: float
|
||||
data: [1, 2, 1.1, 'abc', true, ['x', 'y', 'z'], {'x': 1, 'y': 2}]
|
||||
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
|
||||
# result => list[bool|dict|float|int|list|str]
|
||||
'''
|
||||
"""
|
||||
|
||||
RETURN = '''
|
||||
_value:
|
||||
@@ -123,6 +137,7 @@ from ansible_collections.community.general.plugins.plugin_utils.ansible_type imp
|
||||
def reveal_ansible_type(data, alias=None):
|
||||
"""Returns data type"""
|
||||
|
||||
# TODO: expose use_native_type parameter
|
||||
return _ansible_type(data, alias)
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
DOCUMENTATION:
|
||||
name: to_days
|
||||
short_description: Converte a duration string to days
|
||||
short_description: Converts a duration string to days
|
||||
version_added: 0.2.0
|
||||
description:
|
||||
- Parse a human readable time duration string and convert to days.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
DOCUMENTATION:
|
||||
name: to_hours
|
||||
short_description: Converte a duration string to hours
|
||||
short_description: Converts a duration string to hours
|
||||
version_added: 0.2.0
|
||||
description:
|
||||
- Parse a human readable time duration string and convert to hours.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
DOCUMENTATION:
|
||||
name: to_milliseconds
|
||||
short_description: Converte a duration string to milliseconds
|
||||
short_description: Converts a duration string to milliseconds
|
||||
version_added: 0.2.0
|
||||
description:
|
||||
- Parse a human readable time duration string and convert to milliseconds.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
DOCUMENTATION:
|
||||
name: to_minutes
|
||||
short_description: Converte a duration string to minutes
|
||||
short_description: Converts a duration string to minutes
|
||||
version_added: 0.2.0
|
||||
description:
|
||||
- Parse a human readable time duration string and convert to minutes.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
DOCUMENTATION:
|
||||
name: to_months
|
||||
short_description: Converte a duration string to months
|
||||
short_description: Convert a duration string to months
|
||||
version_added: 0.2.0
|
||||
description:
|
||||
- Parse a human readable time duration string and convert to months.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
DOCUMENTATION:
|
||||
name: to_seconds
|
||||
short_description: Converte a duration string to seconds
|
||||
short_description: Converts a duration string to seconds
|
||||
version_added: 0.2.0
|
||||
description:
|
||||
- Parse a human readable time duration string and convert to seconds.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
DOCUMENTATION:
|
||||
name: to_time_unit
|
||||
short_description: Converte a duration string to the given time unit
|
||||
short_description: Converts a duration string to the given time unit
|
||||
version_added: 0.2.0
|
||||
description:
|
||||
- Parse a human readable time duration string and convert to the given time unit.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
DOCUMENTATION:
|
||||
name: to_weeks
|
||||
short_description: Converte a duration string to weeks
|
||||
short_description: Converts a duration string to weeks
|
||||
version_added: 0.2.0
|
||||
description:
|
||||
- Parse a human readable time duration string and convert to weeks.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
DOCUMENTATION:
|
||||
name: to_years
|
||||
short_description: Converte a duration string to years
|
||||
short_description: Converts a duration string to years
|
||||
version_added: 0.2.0
|
||||
description:
|
||||
- Parse a human readable time duration string and convert to years.
|
||||
|
||||
@@ -49,9 +49,14 @@ RETURN = '''
|
||||
|
||||
from unicodedata import normalize
|
||||
|
||||
from ansible.errors import AnsibleFilterError, AnsibleFilterTypeError
|
||||
from ansible.errors import AnsibleFilterError
|
||||
from ansible.module_utils.six import text_type
|
||||
|
||||
try:
|
||||
from ansible.errors import AnsibleTypeError
|
||||
except ImportError:
|
||||
from ansible.errors import AnsibleFilterTypeError as AnsibleTypeError
|
||||
|
||||
|
||||
def unicode_normalize(data, form='NFC'):
|
||||
"""Applies normalization to 'unicode' strings.
|
||||
@@ -66,7 +71,7 @@ def unicode_normalize(data, form='NFC'):
|
||||
"""
|
||||
|
||||
if not isinstance(data, text_type):
|
||||
raise AnsibleFilterTypeError("%s is not a valid input type" % type(data))
|
||||
raise AnsibleTypeError("%s is not a valid input type" % type(data))
|
||||
|
||||
if form not in ('NFC', 'NFD', 'NFKC', 'NFKD'):
|
||||
raise AnsibleFilterError("%s is not a valid form" % form)
|
||||
|
||||
@@ -304,12 +304,17 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
|
||||
def _get_json(self, url, ignore_errors=None):
|
||||
|
||||
if not self.use_cache or url not in self._cache.get(self.cache_key, {}):
|
||||
data = []
|
||||
has_data = False
|
||||
|
||||
if self.cache_key not in self._cache:
|
||||
self._cache[self.cache_key] = {'url': ''}
|
||||
if self.use_cache:
|
||||
try:
|
||||
data = self._cache[self.cache_key][url]
|
||||
has_data = True
|
||||
except KeyError:
|
||||
self.update_cache = True
|
||||
|
||||
data = []
|
||||
if not has_data:
|
||||
s = self._get_session()
|
||||
while True:
|
||||
ret = s.get(url, headers=self.headers)
|
||||
@@ -335,9 +340,8 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
data = data + json['data']
|
||||
break
|
||||
|
||||
self._cache[self.cache_key][url] = data
|
||||
|
||||
return make_unsafe(self._cache[self.cache_key][url])
|
||||
self._results[url] = data
|
||||
return make_unsafe(data)
|
||||
|
||||
def _get_nodes(self):
|
||||
return self._get_json("%s/api2/json/nodes" % self.proxmox_url)
|
||||
@@ -358,11 +362,26 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
def _get_node_ip(self, node):
|
||||
ret = self._get_json("%s/api2/json/nodes/%s/network" % (self.proxmox_url, node))
|
||||
|
||||
# sort interface by iface name to make selection as stable as possible
|
||||
ret.sort(key=lambda x: x['iface'])
|
||||
|
||||
for iface in ret:
|
||||
try:
|
||||
# only process interfaces adhering to these rules
|
||||
if 'active' not in iface:
|
||||
self.display.vvv(f"Interface {iface['iface']} on node {node} does not have an active state")
|
||||
continue
|
||||
if 'address' not in iface:
|
||||
self.display.vvv(f"Interface {iface['iface']} on node {node} does not have an address")
|
||||
continue
|
||||
if 'gateway' not in iface:
|
||||
self.display.vvv(f"Interface {iface['iface']} on node {node} does not have a gateway")
|
||||
continue
|
||||
self.display.vv(f"Using interface {iface['iface']} on node {node} with address {iface['address']} as node ip for ansible_host")
|
||||
return iface['address']
|
||||
except Exception:
|
||||
return None
|
||||
continue
|
||||
return None
|
||||
|
||||
def _get_lxc_interfaces(self, properties, node, vmid):
|
||||
status_key = self._fact('status')
|
||||
@@ -678,10 +697,14 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
self.exclude_nodes = self.get_option('exclude_nodes')
|
||||
self.cache_key = self.get_cache_key(path)
|
||||
self.use_cache = cache and self.get_option('cache')
|
||||
self.update_cache = not cache and self.get_option('cache')
|
||||
self.host_filters = self.get_option('filters')
|
||||
self.group_prefix = self.get_option('group_prefix')
|
||||
self.facts_prefix = self.get_option('facts_prefix')
|
||||
self.strict = self.get_option('strict')
|
||||
|
||||
# actually populate inventory
|
||||
self._results = {}
|
||||
self._populate()
|
||||
if self.update_cache:
|
||||
self._cache[self.cache_key] = self._results
|
||||
|
||||
@@ -130,12 +130,24 @@ from ansible.template import Templar
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
|
||||
|
||||
try:
|
||||
from ansible.template import trust_as_template as _trust_as_template
|
||||
HAS_DATATAGGING = True
|
||||
except ImportError:
|
||||
HAS_DATATAGGING = False
|
||||
|
||||
|
||||
# Whether Templar has a cache, which can be controlled by Templar.template()'s cache option.
|
||||
# The cache was removed for ansible-core 2.14 (https://github.com/ansible/ansible/pull/78419)
|
||||
_TEMPLAR_HAS_TEMPLATE_CACHE = LooseVersion(ansible_version) < LooseVersion('2.14.0')
|
||||
|
||||
|
||||
def _make_safe(value):
|
||||
if HAS_DATATAGGING and isinstance(value, str):
|
||||
return _trust_as_template(value)
|
||||
return value
|
||||
|
||||
|
||||
class LookupModule(LookupBase):
|
||||
def __evaluate(self, expression, templar, variables):
|
||||
"""Evaluate expression with templar.
|
||||
@@ -144,10 +156,13 @@ class LookupModule(LookupBase):
|
||||
``variables`` are the variables to use.
|
||||
"""
|
||||
templar.available_variables = variables or {}
|
||||
expression = "{0}{1}{2}".format("{{", expression, "}}")
|
||||
quoted_expression = "{0}{1}{2}".format("{{", expression, "}}")
|
||||
if _TEMPLAR_HAS_TEMPLATE_CACHE:
|
||||
return templar.template(expression, cache=False)
|
||||
return templar.template(expression)
|
||||
return templar.template(quoted_expression, cache=False)
|
||||
if hasattr(templar, 'evaluate_expression'):
|
||||
# This is available since the Data Tagging PR has been merged
|
||||
return templar.evaluate_expression(_make_safe(expression))
|
||||
return templar.template(quoted_expression)
|
||||
|
||||
def __process(self, result, terms, index, current, templar, variables):
|
||||
"""Fills ``result`` list with evaluated items.
|
||||
|
||||
@@ -578,16 +578,20 @@ class LookupModule(LookupBase):
|
||||
for term in terms:
|
||||
self.parse_params(term) # parse the input into paramvals
|
||||
with self.opt_lock('readwrite'):
|
||||
if self.check_pass(): # password exists
|
||||
if self.paramvals['overwrite']:
|
||||
if self.check_pass(): # password file exists
|
||||
if self.paramvals['overwrite']: # if "overwrite", always update password
|
||||
with self.opt_lock('write'):
|
||||
result.append(self.update_password())
|
||||
elif self.paramvals["subkey"] != "password" and not self.passdict.get(self.paramvals['subkey']): # password exists but not the subkey
|
||||
elif (
|
||||
self.paramvals["subkey"] != "password"
|
||||
and not self.passdict.get(self.paramvals["subkey"])
|
||||
and self.paramvals["missing"] == "create"
|
||||
): # target is a subkey, this subkey is not in passdict BUT missing == create
|
||||
with self.opt_lock('write'):
|
||||
result.append(self.update_password())
|
||||
else:
|
||||
result.append(self.get_passresult())
|
||||
else: # password does not exist
|
||||
else: # password does not exist
|
||||
if self.paramvals['missing'] == 'create':
|
||||
with self.opt_lock('write'):
|
||||
if self.locked == 'write' and self.check_pass(): # lookup password again if under write lock
|
||||
|
||||
@@ -2228,6 +2228,23 @@ class KeycloakAPI(object):
|
||||
except Exception as e:
|
||||
self.fail_open_url(e, msg="Unable to add authenticationConfig %s: %s" % (executionId, str(e)))
|
||||
|
||||
def delete_authentication_config(self, configId, realm='master'):
|
||||
""" Delete authenticator config
|
||||
|
||||
:param configId: id of authentication config
|
||||
:param realm: realm of authentication config to be deleted
|
||||
"""
|
||||
try:
|
||||
# Send a DELETE request to remove the specified authentication config from the Keycloak server.
|
||||
self._request(
|
||||
URL_AUTHENTICATION_CONFIG.format(
|
||||
url=self.baseurl,
|
||||
realm=realm,
|
||||
id=configId),
|
||||
method='DELETE')
|
||||
except Exception as e:
|
||||
self.fail_request(e, msg="Unable to delete authentication config %s: %s" % (configId, str(e)))
|
||||
|
||||
def create_subflow(self, subflowName, flowAlias, realm='master', flowType='basic-flow'):
|
||||
""" Create new sublow on the flow
|
||||
|
||||
|
||||
@@ -18,10 +18,11 @@ description:
|
||||
- Set and/or get members' attributes of an Apache httpd 2.4 mod_proxy balancer
|
||||
pool, using HTTP POST and GET requests. The httpd mod_proxy balancer-member
|
||||
status page has to be enabled and accessible, as this module relies on parsing
|
||||
this page. This module supports ansible check_mode, and requires BeautifulSoup
|
||||
python module.
|
||||
this page.
|
||||
extends_documentation_fragment:
|
||||
- community.general.attributes
|
||||
requirements:
|
||||
- Python package C(BeautifulSoup) on Python 2, C(beautifulsoup4) on Python 3.
|
||||
attributes:
|
||||
check_mode:
|
||||
support: full
|
||||
@@ -207,12 +208,16 @@ import re
|
||||
import traceback
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||
from ansible.module_utils.common.text.converters import to_text
|
||||
from ansible.module_utils.urls import fetch_url
|
||||
from ansible.module_utils.six import iteritems
|
||||
from ansible.module_utils.six import iteritems, PY2
|
||||
|
||||
BEAUTIFUL_SOUP_IMP_ERR = None
|
||||
try:
|
||||
from BeautifulSoup import BeautifulSoup
|
||||
if PY2:
|
||||
from BeautifulSoup import BeautifulSoup
|
||||
else:
|
||||
from bs4 import BeautifulSoup
|
||||
except ImportError:
|
||||
BEAUTIFUL_SOUP_IMP_ERR = traceback.format_exc()
|
||||
HAS_BEAUTIFULSOUP = False
|
||||
@@ -220,9 +225,15 @@ else:
|
||||
HAS_BEAUTIFULSOUP = True
|
||||
|
||||
# balancer member attributes extraction regexp:
|
||||
EXPRESSION = r"(b=([\w\.\-]+)&w=(https?|ajp|wss?|ftp|[sf]cgi)://([\w\.\-]+):?(\d*)([/\w\.\-]*)&?[\w\-\=]*)"
|
||||
EXPRESSION = to_text(r"(b=([\w\.\-]+)&w=(https?|ajp|wss?|ftp|[sf]cgi)://([\w\.\-]+):?(\d*)([/\w\.\-]*)&?[\w\-\=]*)")
|
||||
# Apache2 server version extraction regexp:
|
||||
APACHE_VERSION_EXPRESSION = r"SERVER VERSION: APACHE/([\d.]+)"
|
||||
APACHE_VERSION_EXPRESSION = to_text(r"SERVER VERSION: APACHE/([\d.]+)")
|
||||
|
||||
|
||||
def find_all(where, what):
|
||||
if PY2:
|
||||
return where.findAll(what)
|
||||
return where.find_all(what)
|
||||
|
||||
|
||||
def regexp_extraction(string, _regexp, groups=1):
|
||||
@@ -262,7 +273,7 @@ class BalancerMember(object):
|
||||
def get_member_attributes(self):
|
||||
""" Returns a dictionary of a balancer member's attributes."""
|
||||
|
||||
balancer_member_page = fetch_url(self.module, self.management_url)
|
||||
balancer_member_page = fetch_url(self.module, self.management_url, headers={'Referer': self.management_url})
|
||||
|
||||
if balancer_member_page[1]['status'] != 200:
|
||||
self.module.fail_json(msg="Could not get balancer_member_page, check for connectivity! " + balancer_member_page[1])
|
||||
@@ -272,11 +283,11 @@ class BalancerMember(object):
|
||||
except TypeError as exc:
|
||||
self.module.fail_json(msg="Cannot parse balancer_member_page HTML! " + str(exc))
|
||||
else:
|
||||
subsoup = soup.findAll('table')[1].findAll('tr')
|
||||
keys = subsoup[0].findAll('th')
|
||||
subsoup = find_all(find_all(soup, 'table')[1], 'tr')
|
||||
keys = find_all(subsoup[0], 'th')
|
||||
for valuesset in subsoup[1::1]:
|
||||
if re.search(pattern=self.host, string=str(valuesset)):
|
||||
values = valuesset.findAll('td')
|
||||
values = find_all(valuesset, 'td')
|
||||
return {keys[x].string: values[x].string for x in range(0, len(keys))}
|
||||
|
||||
def get_member_status(self):
|
||||
@@ -300,9 +311,9 @@ class BalancerMember(object):
|
||||
values_url = "".join("{0}={1}".format(url_param, 1 if values[mode] else 0) for mode, url_param in iteritems(values_mapping))
|
||||
request_body = "{0}{1}".format(request_body, values_url)
|
||||
|
||||
response = fetch_url(self.module, self.management_url, data=request_body)
|
||||
response = fetch_url(self.module, self.management_url, data=request_body, headers={'Referer': self.management_url})
|
||||
if response[1]['status'] != 200:
|
||||
self.module.fail_json(msg="Could not set the member status! " + self.host + " " + response[1]['status'])
|
||||
self.module.fail_json(msg="Could not set the member status! {host} {status}".format(host=self.host, status=response[1]['status']))
|
||||
|
||||
attributes = property(get_member_attributes)
|
||||
status = property(get_member_status, set_member_status)
|
||||
@@ -329,11 +340,15 @@ class Balancer(object):
|
||||
if page[1]['status'] != 200:
|
||||
self.module.fail_json(msg="Could not get balancer page! HTTP status response: " + str(page[1]['status']))
|
||||
else:
|
||||
content = page[0].read()
|
||||
content = to_text(page[0].read())
|
||||
apache_version = regexp_extraction(content.upper(), APACHE_VERSION_EXPRESSION, 1)
|
||||
if apache_version:
|
||||
if not re.search(pattern=r"2\.4\.[\d]*", string=apache_version):
|
||||
self.module.fail_json(msg="This module only acts on an Apache2 2.4+ instance, current Apache2 version: " + str(apache_version))
|
||||
self.module.fail_json(
|
||||
msg="This module only acts on an Apache2 2.4+ instance, current Apache2 version: {version}".format(
|
||||
version=apache_version
|
||||
)
|
||||
)
|
||||
return content
|
||||
else:
|
||||
self.module.fail_json(msg="Could not get the Apache server version from the balancer-manager")
|
||||
@@ -345,7 +360,8 @@ class Balancer(object):
|
||||
except TypeError:
|
||||
self.module.fail_json(msg="Cannot parse balancer page HTML! " + str(self.page))
|
||||
else:
|
||||
for element in soup.findAll('a')[1::1]:
|
||||
elements = find_all(soup, 'a')
|
||||
for element in elements[1::1]:
|
||||
balancer_member_suffix = str(element.get('href'))
|
||||
if not balancer_member_suffix:
|
||||
self.module.fail_json(msg="Argument 'balancer_member_suffix' is empty!")
|
||||
|
||||
@@ -196,6 +196,7 @@ def create_apache_identifier(name):
|
||||
|
||||
# re expressions to extract subparts of names
|
||||
re_workarounds = [
|
||||
('php8', re.compile(r'^(php)[\d\.]+')),
|
||||
('php', re.compile(r'^(php\d)\.')),
|
||||
]
|
||||
|
||||
|
||||
@@ -511,6 +511,9 @@ class CloudflareAPI(object):
|
||||
try:
|
||||
content = resp.read()
|
||||
except AttributeError:
|
||||
content = None
|
||||
|
||||
if not content:
|
||||
if info['body']:
|
||||
content = info['body']
|
||||
else:
|
||||
@@ -645,6 +648,7 @@ class CloudflareAPI(object):
|
||||
else:
|
||||
search_value = content
|
||||
|
||||
zone_id = self._get_zone_id(params['zone'])
|
||||
records = self.get_dns_records(params['zone'], params['type'], search_record, search_value)
|
||||
|
||||
for rr in records:
|
||||
@@ -652,11 +656,11 @@ class CloudflareAPI(object):
|
||||
if not ((rr['type'] == params['type']) and (rr['name'] == search_record) and (rr['content'] == content)):
|
||||
self.changed = True
|
||||
if not self.module.check_mode:
|
||||
result, info = self._cf_api_call('/zones/{0}/dns_records/{1}'.format(rr['zone_id'], rr['id']), 'DELETE')
|
||||
result, info = self._cf_api_call('/zones/{0}/dns_records/{1}'.format(zone_id, rr['id']), 'DELETE')
|
||||
else:
|
||||
self.changed = True
|
||||
if not self.module.check_mode:
|
||||
result, info = self._cf_api_call('/zones/{0}/dns_records/{1}'.format(rr['zone_id'], rr['id']), 'DELETE')
|
||||
result, info = self._cf_api_call('/zones/{0}/dns_records/{1}'.format(zone_id, rr['id']), 'DELETE')
|
||||
return self.changed
|
||||
|
||||
def ensure_dns_record(self, **kwargs):
|
||||
|
||||
@@ -162,6 +162,8 @@ from ansible.module_utils.common.text.converters import to_text
|
||||
from ansible_collections.community.general.plugins.module_utils.datetime import (
|
||||
now,
|
||||
)
|
||||
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
|
||||
|
||||
|
||||
IFPROPS_MAPPING = dict(
|
||||
bondingopts='bonding_opts',
|
||||
@@ -279,7 +281,11 @@ def main():
|
||||
|
||||
if system:
|
||||
# Update existing entry
|
||||
system_id = conn.get_system_handle(name, token)
|
||||
system_id = None
|
||||
if LooseVersion(str(conn.version())) >= LooseVersion('3.4.0'):
|
||||
system_id = conn.get_system_handle(name)
|
||||
else:
|
||||
system_id = conn.get_system_handle(name, token)
|
||||
|
||||
for key, value in iteritems(module.params['properties']):
|
||||
if key not in system:
|
||||
|
||||
@@ -225,7 +225,7 @@ def normalize_link_obj(api_obj, module_obj, key):
|
||||
|
||||
for obj in module_objs:
|
||||
identifier = obj.get("ID")
|
||||
name = obj.get("Name)")
|
||||
name = obj.get("Name")
|
||||
if identifier and not name and identifier in id_to_name:
|
||||
obj["Name"] = id_to_name[identifier]
|
||||
if not identifier and name and name in name_to_id:
|
||||
|
||||
@@ -78,6 +78,13 @@ EXAMPLES = r"""
|
||||
community.general.copr:
|
||||
state: absent
|
||||
name: '@copr/integration_tests'
|
||||
|
||||
- name: Install Caddy
|
||||
community.general.copr:
|
||||
name: '@caddy/caddy'
|
||||
chroot: fedora-rawhide-{{ ansible_facts.architecture }}
|
||||
includepkgs:
|
||||
- caddy
|
||||
"""
|
||||
|
||||
RETURN = r"""
|
||||
|
||||
@@ -77,7 +77,7 @@ EXAMPLES = r'''
|
||||
state: opts_present
|
||||
opts: discard
|
||||
loop: '{{ ansible_mounts }}'
|
||||
when: "'/dev/mapper/luks-' in {{ item.device }}"
|
||||
when: "'/dev/mapper/luks-' in item.device"
|
||||
'''
|
||||
|
||||
import os
|
||||
|
||||
@@ -235,6 +235,43 @@ def get_packages(module, patterns, only_installed=False):
|
||||
return packages_available_map_name_evrs
|
||||
|
||||
|
||||
def get_package_mgr():
|
||||
for bin_path in (DNF_BIN,):
|
||||
if os.path.exists(bin_path):
|
||||
return "dnf5" if os.path.realpath(bin_path) == "/usr/bin/dnf5" else "dnf"
|
||||
# fallback to dnf
|
||||
return "dnf"
|
||||
|
||||
|
||||
def get_package_list(module, package_mgr="dnf"):
|
||||
if package_mgr == "dnf":
|
||||
return do_versionlock(module, "list").split()
|
||||
|
||||
package_list = []
|
||||
if package_mgr == "dnf5":
|
||||
stanza_start = False
|
||||
package_name = None
|
||||
for line in do_versionlock(module, "list").splitlines():
|
||||
if line.startswith(("#", " ")):
|
||||
continue
|
||||
if line.startswith("Package name:"):
|
||||
stanza_start = True
|
||||
dummy, name = line.split(":", 1)
|
||||
name = name.strip()
|
||||
pkg_name = get_packages(module, patterns=[name])
|
||||
package_name = "%s-%s.*" % (name, pkg_name[name].pop())
|
||||
if package_name and package_name not in package_list:
|
||||
package_list.append(package_name)
|
||||
if line.startswith("evr"):
|
||||
dummy, package_version = line.split("=", 1)
|
||||
package_version = package_version.strip()
|
||||
if stanza_start:
|
||||
if package_name and package_name not in package_list:
|
||||
package_list.append(package_name)
|
||||
stanza_start = False
|
||||
return package_list
|
||||
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
@@ -253,9 +290,10 @@ def main():
|
||||
msg = ""
|
||||
|
||||
# Check module pre-requisites.
|
||||
if not os.path.exists(DNF_BIN):
|
||||
module.fail_json(msg="%s was not found" % DNF_BIN)
|
||||
if not os.path.exists(VERSIONLOCK_CONF):
|
||||
global DNF_BIN
|
||||
DNF_BIN = module.get_bin_path('dnf', True)
|
||||
package_mgr = get_package_mgr()
|
||||
if package_mgr == "dnf" and not os.path.exists(VERSIONLOCK_CONF):
|
||||
module.fail_json(msg="plugin versionlock is required")
|
||||
|
||||
# Check incompatible options.
|
||||
@@ -264,7 +302,7 @@ def main():
|
||||
if state != "clean" and not patterns:
|
||||
module.fail_json(msg="name list is required for %s state" % state)
|
||||
|
||||
locklist_pre = do_versionlock(module, "list").split()
|
||||
locklist_pre = get_package_list(module, package_mgr=package_mgr)
|
||||
|
||||
specs_toadd = []
|
||||
specs_todelete = []
|
||||
@@ -343,7 +381,7 @@ def main():
|
||||
"specs_todelete": specs_todelete
|
||||
}
|
||||
if not module.check_mode:
|
||||
response["locklist_post"] = do_versionlock(module, "list").split()
|
||||
response["locklist_post"] = get_package_list(module, package_mgr=package_mgr)
|
||||
else:
|
||||
if state == "clean":
|
||||
response["locklist_post"] = []
|
||||
|
||||
@@ -166,33 +166,38 @@ def parse_error(string):
|
||||
|
||||
|
||||
def install_plugin(module, plugin_bin, plugin_name, version, src, url, proxy_host, proxy_port, timeout, force):
|
||||
cmd_args = [plugin_bin, PACKAGE_STATE_MAP["present"]]
|
||||
cmd = [plugin_bin, PACKAGE_STATE_MAP["present"]]
|
||||
is_old_command = (os.path.basename(plugin_bin) == 'plugin')
|
||||
|
||||
# Timeout and version are only valid for plugin, not elasticsearch-plugin
|
||||
if is_old_command:
|
||||
if timeout:
|
||||
cmd_args.append("--timeout %s" % timeout)
|
||||
cmd.append("--timeout")
|
||||
cmd.append(timeout)
|
||||
|
||||
if version:
|
||||
plugin_name = plugin_name + '/' + version
|
||||
cmd_args[2] = plugin_name
|
||||
cmd[2] = plugin_name
|
||||
|
||||
if proxy_host and proxy_port:
|
||||
cmd_args.append("-DproxyHost=%s -DproxyPort=%s" % (proxy_host, proxy_port))
|
||||
java_opts = ["-Dhttp.proxyHost=%s" % proxy_host,
|
||||
"-Dhttp.proxyPort=%s" % proxy_port,
|
||||
"-Dhttps.proxyHost=%s" % proxy_host,
|
||||
"-Dhttps.proxyPort=%s" % proxy_port]
|
||||
module.run_command_environ_update = dict(CLI_JAVA_OPTS=" ".join(java_opts), # Elasticsearch 8.x
|
||||
ES_JAVA_OPTS=" ".join(java_opts)) # Older Elasticsearch versions
|
||||
|
||||
# Legacy ES 1.x
|
||||
if url:
|
||||
cmd_args.append("--url %s" % url)
|
||||
cmd.append("--url")
|
||||
cmd.append(url)
|
||||
|
||||
if force:
|
||||
cmd_args.append("--batch")
|
||||
cmd.append("--batch")
|
||||
if src:
|
||||
cmd_args.append(src)
|
||||
cmd.append(src)
|
||||
else:
|
||||
cmd_args.append(plugin_name)
|
||||
|
||||
cmd = " ".join(cmd_args)
|
||||
cmd.append(plugin_name)
|
||||
|
||||
if module.check_mode:
|
||||
rc, out, err = 0, "check mode", ""
|
||||
@@ -207,9 +212,7 @@ def install_plugin(module, plugin_bin, plugin_name, version, src, url, proxy_hos
|
||||
|
||||
|
||||
def remove_plugin(module, plugin_bin, plugin_name):
|
||||
cmd_args = [plugin_bin, PACKAGE_STATE_MAP["absent"], parse_plugin_repo(plugin_name)]
|
||||
|
||||
cmd = " ".join(cmd_args)
|
||||
cmd = [plugin_bin, PACKAGE_STATE_MAP["absent"], parse_plugin_repo(plugin_name)]
|
||||
|
||||
if module.check_mode:
|
||||
rc, out, err = 0, "check mode", ""
|
||||
|
||||
@@ -259,7 +259,12 @@ class GithubDeployKey(object):
|
||||
key_id = response_body["id"]
|
||||
self.module.exit_json(changed=True, msg="Deploy key successfully added", id=key_id)
|
||||
elif status_code == 422:
|
||||
self.module.exit_json(changed=False, msg="Deploy key already exists")
|
||||
# there might be multiple reasons for a 422
|
||||
# so we must check if the reason is that the key already exists
|
||||
if self.get_existing_key():
|
||||
self.module.exit_json(changed=False, msg="Deploy key already exists")
|
||||
else:
|
||||
self.handle_error(method="POST", info=info)
|
||||
else:
|
||||
self.handle_error(method="POST", info=info)
|
||||
|
||||
|
||||
@@ -425,10 +425,7 @@ class HomebrewCask(object):
|
||||
cmd = base_opts + [self.current_cask]
|
||||
rc, out, err = self.module.run_command(cmd)
|
||||
|
||||
if rc == 0:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
return rc == 0
|
||||
|
||||
def _get_brew_version(self):
|
||||
if self.brew_version:
|
||||
@@ -436,11 +433,13 @@ class HomebrewCask(object):
|
||||
|
||||
cmd = [self.brew_path, '--version']
|
||||
|
||||
rc, out, err = self.module.run_command(cmd, check_rc=True)
|
||||
dummy, out, dummy = self.module.run_command(cmd, check_rc=True)
|
||||
|
||||
# get version string from first line of "brew --version" output
|
||||
version = out.split('\n')[0].split(' ')[1]
|
||||
self.brew_version = version
|
||||
pattern = r"Homebrew (.*)(\d+\.\d+\.\d+)(-dirty)?"
|
||||
rematch = re.search(pattern, out)
|
||||
if not rematch:
|
||||
self.module.fail_json(msg="Failed to match regex to get brew version", stdout=out)
|
||||
self.brew_version = rematch.groups()[1]
|
||||
return self.brew_version
|
||||
|
||||
def _brew_cask_command_is_deprecated(self):
|
||||
|
||||
@@ -72,7 +72,7 @@ EXAMPLES = r"""
|
||||
- name: Remove the foo service (equivalent to `brew services stop foo`)
|
||||
community.general.homebrew_services:
|
||||
name: foo
|
||||
service_state: absent
|
||||
state: absent
|
||||
"""
|
||||
|
||||
RETURN = r"""
|
||||
|
||||
@@ -272,6 +272,10 @@ def ensure(module, client):
|
||||
data = {}
|
||||
for key in diff:
|
||||
data[key] = module_host.get(key)
|
||||
if "usercertificate" not in data:
|
||||
data["usercertificate"] = [
|
||||
cert['__base64__'] for cert in ipa_host.get("usercertificate", [])
|
||||
]
|
||||
ipa_host_show = client.host_show(name=name)
|
||||
if ipa_host_show.get('has_keytab', True) and (state == 'disabled' or module.params.get('random_password')):
|
||||
client.host_disable(name=name)
|
||||
|
||||
@@ -144,7 +144,7 @@ def run_kwriteconfig(module, cmd, path, groups, key, value):
|
||||
else:
|
||||
args.append('false')
|
||||
else:
|
||||
args.append(value)
|
||||
args.extend(['--', value])
|
||||
module.run_command(args, check_rc=True)
|
||||
|
||||
|
||||
|
||||
@@ -308,6 +308,8 @@ def create_or_update_executions(kc, config, realm='master'):
|
||||
}
|
||||
# add the execution configuration
|
||||
if new_exec["authenticationConfig"] is not None:
|
||||
if "authenticationConfig" in execution and "id" in execution["authenticationConfig"]:
|
||||
kc.delete_authentication_config(execution["authenticationConfig"]["id"], realm=realm)
|
||||
kc.add_authenticationConfig_to_execution(updated_exec["id"], new_exec["authenticationConfig"], realm=realm)
|
||||
for key in new_exec:
|
||||
# remove unwanted key for the next API call
|
||||
|
||||
@@ -782,7 +782,7 @@ end_state:
|
||||
'''
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.identity.keycloak.keycloak import KeycloakAPI, camel, \
|
||||
keycloak_argument_spec, get_token, KeycloakError, is_struct_included
|
||||
keycloak_argument_spec, get_token, KeycloakError
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
import copy
|
||||
|
||||
@@ -820,12 +820,30 @@ def normalise_cr(clientrep, remove_ids=False):
|
||||
if remove_ids:
|
||||
mapper.pop('id', None)
|
||||
|
||||
# Convert bool to string
|
||||
if 'config' in mapper:
|
||||
for key, value in mapper['config'].items():
|
||||
if isinstance(value, bool):
|
||||
mapper['config'][key] = str(value).lower()
|
||||
|
||||
# Set to a default value.
|
||||
mapper['consentRequired'] = mapper.get('consentRequired', False)
|
||||
|
||||
if 'attributes' in clientrep:
|
||||
for key, value in clientrep['attributes'].items():
|
||||
if isinstance(value, bool):
|
||||
clientrep['attributes'][key] = str(value).lower()
|
||||
clientrep['attributes'].pop('client.secret.creation.time', None)
|
||||
return clientrep
|
||||
|
||||
|
||||
def normalize_kc_resp(clientrep):
|
||||
# kc drops the variable 'authorizationServicesEnabled' if set to false
|
||||
# to minimize diff/changes we set it to false if not set by kc
|
||||
if clientrep and 'authorizationServicesEnabled' not in clientrep:
|
||||
clientrep['authorizationServicesEnabled'] = False
|
||||
|
||||
|
||||
def sanitize_cr(clientrep):
|
||||
""" Removes probably sensitive details from a client representation.
|
||||
|
||||
@@ -1015,6 +1033,8 @@ def main():
|
||||
else:
|
||||
before_client = kc.get_client_by_id(cid, realm=realm)
|
||||
|
||||
normalize_kc_resp(before_client)
|
||||
|
||||
if before_client is None:
|
||||
before_client = {}
|
||||
|
||||
@@ -1086,7 +1106,7 @@ def main():
|
||||
if module._diff:
|
||||
result['diff'] = dict(before=sanitize_cr(before_norm),
|
||||
after=sanitize_cr(desired_norm))
|
||||
result['changed'] = not is_struct_included(desired_norm, before_norm, CLIENT_META_DATA)
|
||||
result['changed'] = desired_norm != before_norm
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
@@ -1094,6 +1114,8 @@ def main():
|
||||
kc.update_client(cid, desired_client, realm=realm)
|
||||
|
||||
after_client = kc.get_client_by_id(cid, realm=realm)
|
||||
normalize_kc_resp(after_client)
|
||||
|
||||
if before_client == after_client:
|
||||
result['changed'] = False
|
||||
if module._diff:
|
||||
|
||||
@@ -369,7 +369,7 @@ def main():
|
||||
# Assign roles
|
||||
result['changed'] = True
|
||||
if module._diff:
|
||||
result['diff'] = dict(before=assigned_roles_before, after=update_roles)
|
||||
result['diff'] = dict(before={"roles": assigned_roles_before}, after={"roles": update_roles})
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
kc.add_user_rolemapping(uid=uid, cid=cid, role_rep=update_roles, realm=realm)
|
||||
@@ -384,7 +384,7 @@ def main():
|
||||
# Remove mapping of role
|
||||
result['changed'] = True
|
||||
if module._diff:
|
||||
result['diff'] = dict(before=assigned_roles_before, after=update_roles)
|
||||
result['diff'] = dict(before={"roles": assigned_roles_before}, after={"roles": update_roles})
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
kc.delete_user_rolemapping(uid=uid, cid=cid, role_rep=update_roles, realm=realm)
|
||||
|
||||
@@ -1335,7 +1335,7 @@ EXAMPLES = r'''
|
||||
community.general.nmcli:
|
||||
conn_name: my-eth1
|
||||
state: up
|
||||
reload: true
|
||||
conn_reload: true
|
||||
|
||||
- name: Add second ip4 address
|
||||
community.general.nmcli:
|
||||
@@ -2416,9 +2416,11 @@ class Nmcli(object):
|
||||
|
||||
if isinstance(current_value, list) and isinstance(value, list):
|
||||
# compare values between two lists
|
||||
if key in ('ipv4.addresses', 'ipv6.addresses'):
|
||||
if key in ('ipv4.addresses', 'ipv6.addresses', 'ipv4.dns', 'ipv6.dns', 'ipv4.dns-search', 'ipv6.dns-search'):
|
||||
# The order of IP addresses matters because the first one
|
||||
# is the default source address for outbound connections.
|
||||
# Similarly, the order of DNS nameservers and search
|
||||
# suffixes is important.
|
||||
changed |= current_value != value
|
||||
else:
|
||||
changed |= sorted(current_value) != sorted(value)
|
||||
|
||||
@@ -567,6 +567,8 @@ class ProxmoxDiskAnsible(ProxmoxAnsible):
|
||||
ok_str = "CD-ROM was created on %s bus in VM %s"
|
||||
else:
|
||||
config_str = self.module.params["storage"]
|
||||
if not config_str:
|
||||
self.module.fail_json(msg="The storage option must be specified.")
|
||||
if self.module.params.get("media") != "cdrom":
|
||||
config_str += ":%s" % (self.module.params["size"])
|
||||
ok_str = "Disk %s created in VM %s"
|
||||
|
||||
@@ -201,7 +201,7 @@ class ProxmoxVmInfoAnsible(ProxmoxAnsible):
|
||||
if desired_vm:
|
||||
desired_vm.update(detected_vm)
|
||||
desired_vm["vmid"] = this_vm_id
|
||||
desired_vm["template"] = proxmox_to_ansible_bool(desired_vm["template"])
|
||||
desired_vm["template"] = proxmox_to_ansible_bool(desired_vm.get("template", 0))
|
||||
# When user wants to retrieve the VM configuration
|
||||
if config != "none":
|
||||
# pending = 0, current = 1
|
||||
|
||||
@@ -589,6 +589,45 @@ class Rhsm(object):
|
||||
(distro_version[0] == 9 and distro_version[1] >= 2) or
|
||||
distro_version[0] > 9)):
|
||||
dbus_force_option_works = True
|
||||
# We need to use the 'enable_content' D-Bus option to ensure that
|
||||
# content is enabled; sadly the option is available depending on the
|
||||
# version of the distro, and also depending on which API/method is used
|
||||
# for registration.
|
||||
dbus_has_enable_content_option = False
|
||||
if activationkey:
|
||||
def supports_enable_content_for_activation_keys():
|
||||
# subscription-manager in Fedora >= 41 has the new option.
|
||||
if distro_id == 'fedora' and distro_version[0] >= 41:
|
||||
return True
|
||||
# Assume EL distros here.
|
||||
if distro_version[0] >= 10:
|
||||
return True
|
||||
return False
|
||||
dbus_has_enable_content_option = supports_enable_content_for_activation_keys()
|
||||
else:
|
||||
def supports_enable_content_for_credentials():
|
||||
# subscription-manager in any supported Fedora version
|
||||
# has the new option.
|
||||
if distro_id == 'fedora':
|
||||
return True
|
||||
# Check for RHEL 8 >= 8.6, or RHEL >= 9.
|
||||
if distro_id == 'rhel' and \
|
||||
((distro_version[0] == 8 and distro_version[1] >= 6) or
|
||||
distro_version[0] >= 9):
|
||||
return True
|
||||
# CentOS: similar checks as for RHEL, with one extra bit:
|
||||
# if the 2nd part of the version is empty, it means it is
|
||||
# CentOS Stream, and thus we can assume it has the latest
|
||||
# version of subscription-manager.
|
||||
if distro_id == 'centos' and \
|
||||
((distro_version[0] == 8 and
|
||||
(distro_version[1] >= 6 or distro_version_parts[1] == '')) or
|
||||
distro_version[0] >= 9):
|
||||
return True
|
||||
# Unknown or old distro: assume it does not support
|
||||
# the new option.
|
||||
return False
|
||||
dbus_has_enable_content_option = supports_enable_content_for_credentials()
|
||||
|
||||
if force_register and not dbus_force_option_works and was_registered:
|
||||
self.unregister()
|
||||
@@ -661,6 +700,8 @@ class Rhsm(object):
|
||||
register_opts[environment_key] = environment
|
||||
if force_register and dbus_force_option_works and was_registered:
|
||||
register_opts['force'] = True
|
||||
if dbus_has_enable_content_option:
|
||||
register_opts['enable_content'] = "1"
|
||||
# Wrap it as proper D-Bus dict
|
||||
register_opts = dbus.Dictionary(register_opts, signature='sv', variant_level=1)
|
||||
|
||||
|
||||
@@ -130,11 +130,18 @@ from ansible_collections.community.general.plugins.module_utils.rundeck import (
|
||||
class RundeckACLManager:
|
||||
def __init__(self, module):
|
||||
self.module = module
|
||||
if module.params.get("project"):
|
||||
self.endpoint = "project/%s/acl/%s.aclpolicy" % (
|
||||
self.module.params["project"],
|
||||
self.module.params["name"],
|
||||
)
|
||||
else:
|
||||
self.endpoint = "system/acl/%s.aclpolicy" % self.module.params["name"]
|
||||
|
||||
def get_acl(self):
|
||||
resp, info = api_request(
|
||||
module=self.module,
|
||||
endpoint="system/acl/%s.aclpolicy" % self.module.params["name"],
|
||||
endpoint=self.endpoint,
|
||||
)
|
||||
|
||||
return resp
|
||||
@@ -148,7 +155,7 @@ class RundeckACLManager:
|
||||
|
||||
resp, info = api_request(
|
||||
module=self.module,
|
||||
endpoint="system/acl/%s.aclpolicy" % self.module.params["name"],
|
||||
endpoint=self.endpoint,
|
||||
method="POST",
|
||||
data={"contents": self.module.params["policy"]},
|
||||
)
|
||||
@@ -172,7 +179,7 @@ class RundeckACLManager:
|
||||
|
||||
resp, info = api_request(
|
||||
module=self.module,
|
||||
endpoint="system/acl/%s.aclpolicy" % self.module.params["name"],
|
||||
endpoint=self.endpoint,
|
||||
method="PUT",
|
||||
data={"contents": self.module.params["policy"]},
|
||||
)
|
||||
@@ -195,7 +202,7 @@ class RundeckACLManager:
|
||||
if not self.module.check_mode:
|
||||
api_request(
|
||||
module=self.module,
|
||||
endpoint="system/acl/%s.aclpolicy" % self.module.params["name"],
|
||||
endpoint=self.endpoint,
|
||||
method="DELETE",
|
||||
)
|
||||
|
||||
|
||||
@@ -246,7 +246,7 @@ class Sudoers(object):
|
||||
rc, stdout, stderr = self.module.run_command(check_command, data=self.content())
|
||||
|
||||
if rc != 0:
|
||||
raise Exception('Failed to validate sudoers rule:\n{stdout}'.format(stdout=stdout))
|
||||
self.module.fail_json(msg='Failed to validate sudoers rule:\n{stdout}'.format(stdout=stdout or stderr), stdout=stdout, stderr=stderr)
|
||||
|
||||
def run(self):
|
||||
if self.state == 'absent':
|
||||
|
||||
@@ -122,14 +122,19 @@ class Sysrc(object):
|
||||
return err.find("unknown variable") > 0 or out.find("unknown variable") > 0
|
||||
|
||||
def exists(self):
|
||||
# sysrc doesn't really use exit codes
|
||||
(rc, out, err) = self.run_sysrc(self.name)
|
||||
"""
|
||||
Tests whether the name is in the file. If parameter value is defined,
|
||||
then tests whether name=value is in the file. These tests are necessary
|
||||
because sysrc doesn't use exit codes. Instead, let sysrc read the
|
||||
file's content and create a dictionary comprising the configuration.
|
||||
Use this dictionary to preform the tests.
|
||||
"""
|
||||
(rc, out, err) = self.run_sysrc('-e', '-a')
|
||||
conf = dict([i.split('=', 1) for i in out.splitlines()])
|
||||
if self.value is None:
|
||||
regex = "%s: " % re.escape(self.name)
|
||||
return self.name in conf
|
||||
else:
|
||||
regex = "%s: %s$" % (re.escape(self.name), re.escape(self.value))
|
||||
|
||||
return not self.has_unknown_variable(out, err) and re.match(regex, out) is not None
|
||||
return self.name in conf and conf[self.name] == '"%s"' % self.value
|
||||
|
||||
def contains(self):
|
||||
(rc, out, err) = self.run_sysrc('-n', self.name)
|
||||
@@ -142,13 +147,10 @@ class Sysrc(object):
|
||||
if self.exists():
|
||||
return
|
||||
|
||||
if self.module.check_mode:
|
||||
self.changed = True
|
||||
return
|
||||
if not self.module.check_mode:
|
||||
(rc, out, err) = self.run_sysrc("%s=%s" % (self.name, self.value))
|
||||
|
||||
(rc, out, err) = self.run_sysrc("%s=%s" % (self.name, self.value))
|
||||
if out.find("%s:" % self.name) == 0 and re.search("-> %s$" % re.escape(self.value), out) is not None:
|
||||
self.changed = True
|
||||
self.changed = True
|
||||
|
||||
def absent(self):
|
||||
if not self.exists():
|
||||
|
||||
@@ -923,29 +923,34 @@ def main():
|
||||
elif LooseVersion('.'.join(to_native(f) for f in etree.LXML_VERSION)) < LooseVersion('3.0.0'):
|
||||
module.warn('Using lxml version lower than 3.0.0 does not guarantee predictable element attribute order.')
|
||||
|
||||
# Check if the file exists
|
||||
if xml_string:
|
||||
infile = BytesIO(to_bytes(xml_string, errors='surrogate_or_strict'))
|
||||
elif os.path.isfile(xml_file):
|
||||
infile = open(xml_file, 'rb')
|
||||
else:
|
||||
module.fail_json(msg="The target XML source '%s' does not exist." % xml_file)
|
||||
|
||||
# Parse and evaluate xpath expression
|
||||
if xpath is not None:
|
||||
try:
|
||||
etree.XPath(xpath)
|
||||
except etree.XPathSyntaxError as e:
|
||||
module.fail_json(msg="Syntax error in xpath expression: %s (%s)" % (xpath, e))
|
||||
except etree.XPathEvalError as e:
|
||||
module.fail_json(msg="Evaluation error in xpath expression: %s (%s)" % (xpath, e))
|
||||
|
||||
# Try to parse in the target XML file
|
||||
infile = None
|
||||
try:
|
||||
parser = etree.XMLParser(remove_blank_text=pretty_print, strip_cdata=strip_cdata_tags)
|
||||
doc = etree.parse(infile, parser)
|
||||
except etree.XMLSyntaxError as e:
|
||||
module.fail_json(msg="Error while parsing document: %s (%s)" % (xml_file or 'xml_string', e))
|
||||
# Check if the file exists
|
||||
if xml_string:
|
||||
infile = BytesIO(to_bytes(xml_string, errors='surrogate_or_strict'))
|
||||
elif os.path.isfile(xml_file):
|
||||
infile = open(xml_file, 'rb')
|
||||
else:
|
||||
module.fail_json(msg="The target XML source '%s' does not exist." % xml_file)
|
||||
|
||||
# Parse and evaluate xpath expression
|
||||
if xpath is not None:
|
||||
try:
|
||||
etree.XPath(xpath)
|
||||
except etree.XPathSyntaxError as e:
|
||||
module.fail_json(msg="Syntax error in xpath expression: %s (%s)" % (xpath, e))
|
||||
except etree.XPathEvalError as e:
|
||||
module.fail_json(msg="Evaluation error in xpath expression: %s (%s)" % (xpath, e))
|
||||
|
||||
# Try to parse in the target XML file
|
||||
try:
|
||||
parser = etree.XMLParser(remove_blank_text=pretty_print, strip_cdata=strip_cdata_tags)
|
||||
doc = etree.parse(infile, parser)
|
||||
except etree.XMLSyntaxError as e:
|
||||
module.fail_json(msg="Error while parsing document: %s (%s)" % (xml_file or 'xml_string', e))
|
||||
finally:
|
||||
if infile:
|
||||
infile.close()
|
||||
|
||||
# Ensure we have the original copy to compare
|
||||
global orig_doc
|
||||
|
||||
@@ -16,7 +16,8 @@ DOCUMENTATION = '''
|
||||
module: yarn
|
||||
short_description: Manage node.js packages with Yarn
|
||||
description:
|
||||
- Manage node.js packages with the Yarn package manager (https://yarnpkg.com/)
|
||||
- Manage Node.js packages with the Yarn package manager U(https://yarnpkg.com/).
|
||||
- Note that at the moment, this module B(only works with Yarn Classic).
|
||||
author:
|
||||
- "David Gunter (@verkaufer)"
|
||||
- "Chris Hoffman (@chrishoffman), creator of NPM Ansible module)"
|
||||
@@ -85,7 +86,7 @@ options:
|
||||
default: present
|
||||
choices: [ "present", "absent", "latest" ]
|
||||
requirements:
|
||||
- Yarn installed in bin path (typically /usr/local/bin)
|
||||
- Yarn Classic installed in bin path (typically C(/usr/local/bin))
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
|
||||
@@ -8,17 +8,31 @@ __metaclass__ = type
|
||||
from ansible.errors import AnsibleFilterError
|
||||
from ansible.module_utils.common._collections_compat import Mapping
|
||||
|
||||
try:
|
||||
# Introduced with Data Tagging (https://github.com/ansible/ansible/pull/84621):
|
||||
from ansible.module_utils.datatag import native_type_name as _native_type_name
|
||||
except ImportError:
|
||||
_native_type_name = None
|
||||
|
||||
def _atype(data, alias):
|
||||
|
||||
def _atype(data, alias, *, use_native_type: bool = False):
|
||||
"""
|
||||
Returns the name of the type class.
|
||||
"""
|
||||
|
||||
data_type = type(data).__name__
|
||||
if use_native_type and _native_type_name:
|
||||
data_type = _native_type_name(data)
|
||||
else:
|
||||
data_type = type(data).__name__
|
||||
# The following types were introduced with Data Tagging (https://github.com/ansible/ansible/pull/84621):
|
||||
if data_type == "_AnsibleLazyTemplateDict":
|
||||
data_type = "dict"
|
||||
elif data_type == "_AnsibleLazyTemplateList":
|
||||
data_type = "list"
|
||||
return alias.get(data_type, data_type)
|
||||
|
||||
|
||||
def _ansible_type(data, alias):
|
||||
def _ansible_type(data, alias, *, use_native_type: bool = False):
|
||||
"""
|
||||
Returns the Ansible data type.
|
||||
"""
|
||||
@@ -30,16 +44,16 @@ def _ansible_type(data, alias):
|
||||
msg = "The argument alias must be a dictionary. %s is %s"
|
||||
raise AnsibleFilterError(msg % (alias, type(alias)))
|
||||
|
||||
data_type = _atype(data, alias)
|
||||
data_type = _atype(data, alias, use_native_type=use_native_type)
|
||||
|
||||
if data_type == 'list' and len(data) > 0:
|
||||
items = [_atype(i, alias) for i in data]
|
||||
items = [_atype(i, alias, use_native_type=use_native_type) for i in data]
|
||||
items_type = '|'.join(sorted(set(items)))
|
||||
return ''.join((data_type, '[', items_type, ']'))
|
||||
|
||||
if data_type == 'dict' and len(data) > 0:
|
||||
keys = [_atype(i, alias) for i in data.keys()]
|
||||
vals = [_atype(i, alias) for i in data.values()]
|
||||
keys = [_atype(i, alias, use_native_type=use_native_type) for i in data.keys()]
|
||||
vals = [_atype(i, alias, use_native_type=use_native_type) for i in data.values()]
|
||||
keys_type = '|'.join(sorted(set(keys)))
|
||||
vals_type = '|'.join(sorted(set(vals)))
|
||||
return ''.join((data_type, '[', keys_type, ', ', vals_type, ']'))
|
||||
|
||||
@@ -28,30 +28,36 @@ DOCUMENTATION = '''
|
||||
|
||||
EXAMPLES = '''
|
||||
|
||||
# Substitution converts str to AnsibleUnicode
|
||||
# -------------------------------------------
|
||||
# Substitution converts str to AnsibleUnicode or _AnsibleTaggedStr
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# String. AnsibleUnicode.
|
||||
dtype: AnsibleUnicode
|
||||
# String. AnsibleUnicode or _AnsibleTaggedStr.
|
||||
dtype:
|
||||
- AnsibleUnicode
|
||||
- _AnsibleTaggedStr
|
||||
data: "abc"
|
||||
result: '{{ data is community.general.ansible_type(dtype) }}'
|
||||
# result => true
|
||||
|
||||
# String. AnsibleUnicode alias str.
|
||||
alias: {"AnsibleUnicode": "str"}
|
||||
# String. AnsibleUnicode/_AnsibleTaggedStr alias str.
|
||||
alias: {"AnsibleUnicode": "str", "_AnsibleTaggedStr": "str"}
|
||||
dtype: str
|
||||
data: "abc"
|
||||
result: '{{ data is community.general.ansible_type(dtype, alias) }}'
|
||||
# result => true
|
||||
|
||||
# List. All items are AnsibleUnicode.
|
||||
dtype: list[AnsibleUnicode]
|
||||
# List. All items are AnsibleUnicode/_AnsibleTaggedStr.
|
||||
dtype:
|
||||
- list[AnsibleUnicode]
|
||||
- list[_AnsibleTaggedStr]
|
||||
data: ["a", "b", "c"]
|
||||
result: '{{ data is community.general.ansible_type(dtype) }}'
|
||||
# result => true
|
||||
|
||||
# Dictionary. All keys are AnsibleUnicode. All values are AnsibleUnicode.
|
||||
dtype: dict[AnsibleUnicode, AnsibleUnicode]
|
||||
# Dictionary. All keys and values are AnsibleUnicode/_AnsibleTaggedStr.
|
||||
dtype:
|
||||
- dict[AnsibleUnicode, AnsibleUnicode]
|
||||
- dict[_AnsibleTaggedStr, _AnsibleTaggedStr]
|
||||
data: {"a": "foo", "b": "bar", "c": "baz"}
|
||||
result: '{{ data is community.general.ansible_type(dtype) }}'
|
||||
# result => true
|
||||
@@ -99,32 +105,46 @@ dtype: dict[str, int]
|
||||
result: '{{ {"a": 1, "b": 2} is community.general.ansible_type(dtype) }}'
|
||||
# result => true
|
||||
|
||||
# Type of strings is AnsibleUnicode or str
|
||||
# ----------------------------------------
|
||||
# Type of strings is AnsibleUnicode, _AnsibleTaggedStr, or str
|
||||
# ------------------------------------------------------------
|
||||
|
||||
# Dictionary. The keys are integers or strings. All values are strings.
|
||||
alias: {"AnsibleUnicode": "str"}
|
||||
alias:
|
||||
AnsibleUnicode: str
|
||||
_AnsibleTaggedStr: str
|
||||
_AnsibleTaggedInt: int
|
||||
dtype: dict[int|str, str]
|
||||
data: {1: 'a', 'b': 'b'}
|
||||
result: '{{ data is community.general.ansible_type(dtype, alias) }}'
|
||||
# result => true
|
||||
|
||||
# Dictionary. All keys are integers. All values are keys.
|
||||
alias: {"AnsibleUnicode": "str"}
|
||||
alias:
|
||||
AnsibleUnicode: str
|
||||
_AnsibleTaggedStr: str
|
||||
_AnsibleTaggedInt: int
|
||||
dtype: dict[int, str]
|
||||
data: {1: 'a', 2: 'b'}
|
||||
result: '{{ data is community.general.ansible_type(dtype, alias) }}'
|
||||
# result => true
|
||||
|
||||
# Dictionary. All keys are strings. Multiple types values.
|
||||
alias: {"AnsibleUnicode": "str"}
|
||||
alias:
|
||||
AnsibleUnicode: str
|
||||
_AnsibleTaggedStr: str
|
||||
_AnsibleTaggedInt: int
|
||||
_AnsibleTaggedFloat: float
|
||||
dtype: dict[str, bool|dict|float|int|list|str]
|
||||
data: {'a': 1, 'b': 1.1, 'c': 'abc', 'd': True, 'e': ['x', 'y', 'z'], 'f': {'x': 1, 'y': 2}}
|
||||
result: '{{ data is community.general.ansible_type(dtype, alias) }}'
|
||||
# result => true
|
||||
|
||||
# List. Multiple types items.
|
||||
alias: {"AnsibleUnicode": "str"}
|
||||
alias:
|
||||
AnsibleUnicode: str
|
||||
_AnsibleTaggedStr: str
|
||||
_AnsibleTaggedInt: int
|
||||
_AnsibleTaggedFloat: float
|
||||
dtype: list[bool|dict|float|int|list|str]
|
||||
data: [1, 2, 1.1, 'abc', True, ['x', 'y', 'z'], {'x': 1, 'y': 2}]
|
||||
result: '{{ data is community.general.ansible_type(dtype, alias) }}'
|
||||
@@ -133,20 +153,20 @@ result: '{{ data is community.general.ansible_type(dtype, alias) }}'
|
||||
# Option dtype is list
|
||||
# --------------------
|
||||
|
||||
# AnsibleUnicode or str
|
||||
dtype: ['AnsibleUnicode', 'str']
|
||||
# AnsibleUnicode, _AnsibleTaggedStr, or str
|
||||
dtype: ['AnsibleUnicode', '_AnsibleTaggedStr', 'str']
|
||||
data: abc
|
||||
result: '{{ data is community.general.ansible_type(dtype) }}'
|
||||
# result => true
|
||||
|
||||
# float or int
|
||||
dtype: ['float', 'int']
|
||||
dtype: ['float', 'int', "_AnsibleTaggedInt", "_AnsibleTaggedFloat"]
|
||||
data: 123
|
||||
result: '{{ data is community.general.ansible_type(dtype) }}'
|
||||
# result => true
|
||||
|
||||
# float or int
|
||||
dtype: ['float', 'int']
|
||||
dtype: ['float', 'int', "_AnsibleTaggedInt", "_AnsibleTaggedFloat"]
|
||||
data: 123.45
|
||||
result: '{{ data is community.general.ansible_type(dtype) }}'
|
||||
# result => true
|
||||
@@ -155,14 +175,22 @@ result: '{{ data is community.general.ansible_type(dtype) }}'
|
||||
# --------------
|
||||
|
||||
# int alias number
|
||||
alias: {"int": "number", "float": "number"}
|
||||
alias:
|
||||
int: number
|
||||
float: number
|
||||
_AnsibleTaggedInt: number
|
||||
_AnsibleTaggedFloat: float
|
||||
dtype: number
|
||||
data: 123
|
||||
result: '{{ data is community.general.ansible_type(dtype, alias) }}'
|
||||
# result => true
|
||||
|
||||
# float alias number
|
||||
alias: {"int": "number", "float": "number"}
|
||||
alias:
|
||||
int: number
|
||||
float: number
|
||||
_AnsibleTaggedInt: number
|
||||
_AnsibleTaggedFloat: float
|
||||
dtype: number
|
||||
data: 123.45
|
||||
result: '{{ data is community.general.ansible_type(dtype, alias) }}'
|
||||
@@ -192,6 +220,7 @@ def ansible_type(data, dtype, alias=None):
|
||||
else:
|
||||
data_types = dtype
|
||||
|
||||
# TODO: expose use_native_type parameter
|
||||
return _ansible_type(data, alias) in data_types
|
||||
|
||||
|
||||
|
||||
7
tests/integration/targets/apache2_mod_proxy/aliases
Normal file
7
tests/integration/targets/apache2_mod_proxy/aliases
Normal file
@@ -0,0 +1,7 @@
|
||||
# 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
|
||||
|
||||
azp/posix/3
|
||||
destructive
|
||||
skip/aix
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
# 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
|
||||
|
||||
dependencies:
|
||||
- setup_remote_constraints
|
||||
- setup_apache2
|
||||
253
tests/integration/targets/apache2_mod_proxy/tasks/main.yml
Normal file
253
tests/integration/targets/apache2_mod_proxy/tasks/main.yml
Normal file
@@ -0,0 +1,253 @@
|
||||
---
|
||||
####################################################################
|
||||
# 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
|
||||
|
||||
- meta: end_play
|
||||
when: ansible_os_family not in ['Debian', 'Suse']
|
||||
|
||||
- name: Enable mod_proxy
|
||||
community.general.apache2_module:
|
||||
state: present
|
||||
name: "{{ item }}"
|
||||
loop:
|
||||
- status
|
||||
- proxy
|
||||
- proxy_http
|
||||
- proxy_balancer
|
||||
- lbmethod_byrequests
|
||||
|
||||
- name: Add port 81
|
||||
lineinfile:
|
||||
path: "/etc/apache2/{{ 'ports.conf' if ansible_os_family == 'Debian' else 'listen.conf' }}"
|
||||
line: Listen 81
|
||||
|
||||
- name: Set up virtual host
|
||||
copy:
|
||||
dest: "/etc/apache2/{{ 'sites-available' if ansible_os_family == 'Debian' else 'vhosts.d' }}/000-apache2_mod_proxy-test.conf"
|
||||
content: |
|
||||
<VirtualHost *:81>
|
||||
<Proxy balancer://mycluster>
|
||||
BalancerMember http://127.0.0.1:8080
|
||||
BalancerMember http://127.0.0.1:8081
|
||||
</Proxy>
|
||||
|
||||
<IfModule mod_evasive20.c>
|
||||
DOSBlockingPeriod 0
|
||||
DOSWhiteList 127.0.0.1
|
||||
DOSWhiteList ::1
|
||||
</IfModule>
|
||||
|
||||
<Location "/app/">
|
||||
ProxyPreserveHost On
|
||||
ProxyPass balancer://mycluster/
|
||||
ProxyPassReverse balancer://mycluster/
|
||||
</Location>
|
||||
|
||||
<Location "/balancer-manager">
|
||||
SetHandler balancer-manager
|
||||
Require all granted
|
||||
</Location>
|
||||
</VirtualHost>
|
||||
|
||||
- name: Enable virtual host
|
||||
file:
|
||||
src: /etc/apache2/sites-available/000-apache2_mod_proxy-test.conf
|
||||
dest: /etc/apache2/sites-enabled/000-apache2_mod_proxy-test.conf
|
||||
owner: root
|
||||
group: root
|
||||
state: link
|
||||
when: ansible_os_family not in ['Suse']
|
||||
|
||||
- name: Restart Apache
|
||||
service:
|
||||
name: apache2
|
||||
state: restarted
|
||||
|
||||
- name: Install BeautifulSoup
|
||||
pip:
|
||||
name: "{{ 'BeautifulSoup' if ansible_python_version is version('3', '<') else 'BeautifulSoup4' }}"
|
||||
extra_args: "-c {{ remote_constraints }}"
|
||||
|
||||
- name: Get all current balancer pool members attributes
|
||||
community.general.apache2_mod_proxy:
|
||||
balancer_vhost: localhost:81
|
||||
register: result
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- result is not changed
|
||||
- result.members | length == 2
|
||||
- result.members[0].port in ["8080", "8081"]
|
||||
- result.members[0].balancer_url == "http://localhost:81/balancer-manager/"
|
||||
- result.members[0].host == "127.0.0.1"
|
||||
- result.members[0].path is none
|
||||
- result.members[0].protocol == "http"
|
||||
- result.members[1].port in ["8080", "8081"]
|
||||
- result.members[1].balancer_url == "http://localhost:81/balancer-manager/"
|
||||
- result.members[1].host == "127.0.0.1"
|
||||
- result.members[1].path is none
|
||||
- result.members[1].protocol == "http"
|
||||
|
||||
- name: Enable member
|
||||
community.general.apache2_mod_proxy:
|
||||
balancer_vhost: localhost:81
|
||||
member_host: 127.0.0.1
|
||||
state: present
|
||||
register: result
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- result is not changed
|
||||
|
||||
- name: Get all current balancer pool members attributes
|
||||
community.general.apache2_mod_proxy:
|
||||
balancer_vhost: localhost:81
|
||||
register: result
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- result is not changed
|
||||
- result.members | length == 2
|
||||
- result.members[0].port in ["8080", "8081"]
|
||||
- result.members[0].balancer_url == "http://localhost:81/balancer-manager/"
|
||||
- result.members[0].host == "127.0.0.1"
|
||||
- result.members[0].path is none
|
||||
- result.members[0].protocol == "http"
|
||||
- result.members[0].status.disabled == false
|
||||
- result.members[0].status.drained == false
|
||||
- result.members[0].status.hot_standby == false
|
||||
- result.members[0].status.ignore_errors == false
|
||||
- result.members[1].port in ["8080", "8081"]
|
||||
- result.members[1].balancer_url == "http://localhost:81/balancer-manager/"
|
||||
- result.members[1].host == "127.0.0.1"
|
||||
- result.members[1].path is none
|
||||
- result.members[1].protocol == "http"
|
||||
- result.members[1].status.disabled == false
|
||||
- result.members[1].status.drained == false
|
||||
- result.members[1].status.hot_standby == false
|
||||
- result.members[1].status.ignore_errors == false
|
||||
|
||||
- name: Drain member
|
||||
community.general.apache2_mod_proxy:
|
||||
balancer_vhost: localhost:81
|
||||
member_host: 127.0.0.1
|
||||
state: drained
|
||||
register: result
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- result is changed
|
||||
|
||||
# Note that since both members are on the same host, this always affects **both** members!
|
||||
|
||||
- name: Get all current balancer pool members attributes
|
||||
community.general.apache2_mod_proxy:
|
||||
balancer_vhost: localhost:81
|
||||
register: result
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- result is not changed
|
||||
- result.members | length == 2
|
||||
- result.members[0].port in ["8080", "8081"]
|
||||
- result.members[0].balancer_url == "http://localhost:81/balancer-manager/"
|
||||
- result.members[0].host == "127.0.0.1"
|
||||
- result.members[0].path is none
|
||||
- result.members[0].protocol == "http"
|
||||
- result.members[0].status.disabled == false
|
||||
- result.members[0].status.drained == true
|
||||
- result.members[0].status.hot_standby == false
|
||||
- result.members[0].status.ignore_errors == false
|
||||
- result.members[1].port in ["8080", "8081"]
|
||||
- result.members[1].balancer_url == "http://localhost:81/balancer-manager/"
|
||||
- result.members[1].host == "127.0.0.1"
|
||||
- result.members[1].path is none
|
||||
- result.members[1].protocol == "http"
|
||||
- result.members[1].status.disabled == false
|
||||
- result.members[1].status.drained == true
|
||||
- result.members[1].status.hot_standby == false
|
||||
- result.members[1].status.ignore_errors == false
|
||||
|
||||
- name: Disable member
|
||||
community.general.apache2_mod_proxy:
|
||||
balancer_vhost: localhost:81
|
||||
member_host: 127.0.0.1
|
||||
state: absent
|
||||
register: result
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- result is changed
|
||||
|
||||
- name: Get all current balancer pool members attributes
|
||||
community.general.apache2_mod_proxy:
|
||||
balancer_vhost: localhost:81
|
||||
register: result
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- result is not changed
|
||||
- result.members | length == 2
|
||||
- result.members[0].port in ["8080", "8081"]
|
||||
- result.members[0].balancer_url == "http://localhost:81/balancer-manager/"
|
||||
- result.members[0].host == "127.0.0.1"
|
||||
- result.members[0].path is none
|
||||
- result.members[0].protocol == "http"
|
||||
- result.members[0].status.disabled == true
|
||||
- result.members[0].status.drained == false
|
||||
- result.members[0].status.hot_standby == false
|
||||
- result.members[0].status.ignore_errors == false
|
||||
- result.members[1].port in ["8080", "8081"]
|
||||
- result.members[1].balancer_url == "http://localhost:81/balancer-manager/"
|
||||
- result.members[1].host == "127.0.0.1"
|
||||
- result.members[1].path is none
|
||||
- result.members[1].protocol == "http"
|
||||
- result.members[1].status.disabled == true
|
||||
- result.members[1].status.drained == false
|
||||
- result.members[1].status.hot_standby == false
|
||||
- result.members[1].status.ignore_errors == false
|
||||
|
||||
- name: Enable member
|
||||
community.general.apache2_mod_proxy:
|
||||
balancer_vhost: localhost:81
|
||||
member_host: 127.0.0.1
|
||||
state: present
|
||||
register: result
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- result is changed
|
||||
|
||||
- name: Get all current balancer pool members attributes
|
||||
community.general.apache2_mod_proxy:
|
||||
balancer_vhost: localhost:81
|
||||
register: result
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- result is not changed
|
||||
- result.members | length == 2
|
||||
- result.members[0].port in ["8080", "8081"]
|
||||
- result.members[0].balancer_url == "http://localhost:81/balancer-manager/"
|
||||
- result.members[0].host == "127.0.0.1"
|
||||
- result.members[0].path is none
|
||||
- result.members[0].protocol == "http"
|
||||
- result.members[0].status.disabled == false
|
||||
- result.members[0].status.drained == false
|
||||
- result.members[0].status.hot_standby == false
|
||||
- result.members[0].status.ignore_errors == false
|
||||
- result.members[1].port in ["8080", "8081"]
|
||||
- result.members[1].balancer_url == "http://localhost:81/balancer-manager/"
|
||||
- result.members[1].host == "127.0.0.1"
|
||||
- result.members[1].path is none
|
||||
- result.members[1].protocol == "http"
|
||||
- result.members[1].status.disabled == false
|
||||
- result.members[1].status.drained == false
|
||||
- result.members[1].status.hot_standby == false
|
||||
- result.members[1].status.ignore_errors == false
|
||||
7
tests/integration/targets/apache2_module/meta/main.yml
Normal file
7
tests/integration/targets/apache2_module/meta/main.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
# 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
|
||||
|
||||
dependencies:
|
||||
- setup_apache2
|
||||
@@ -8,21 +8,6 @@
|
||||
# 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: install apache via apt
|
||||
apt:
|
||||
name: "{{item}}"
|
||||
state: present
|
||||
when: "ansible_os_family == 'Debian'"
|
||||
with_items:
|
||||
- apache2
|
||||
- libapache2-mod-evasive
|
||||
|
||||
- name: install apache via zypper
|
||||
community.general.zypper:
|
||||
name: apache2
|
||||
state: present
|
||||
when: "ansible_os_family == 'Suse'"
|
||||
|
||||
- name: test apache2_module
|
||||
block:
|
||||
- name: get list of enabled modules
|
||||
|
||||
54
tests/integration/targets/callback/filter_plugins/helper.py
Normal file
54
tests/integration/targets/callback/filter_plugins/helper.py
Normal file
@@ -0,0 +1,54 @@
|
||||
# Copyright (c) Ansible Project
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
from ansible.module_utils.six import string_types
|
||||
|
||||
|
||||
def callback_results_extractor(outputs_results):
|
||||
results = []
|
||||
for result in outputs_results:
|
||||
differences = []
|
||||
expected_output = result['test']['expected_output']
|
||||
stdout_lines = result['stdout_lines']
|
||||
for i in range(max(len(expected_output), len(stdout_lines))):
|
||||
line = "line_%s" % (i + 1)
|
||||
test_line = stdout_lines[i] if i < len(stdout_lines) else None
|
||||
expected_lines = expected_output[i] if i < len(expected_output) else None
|
||||
if not isinstance(expected_lines, string_types) and expected_lines is not None:
|
||||
if test_line not in expected_lines:
|
||||
differences.append({
|
||||
'line': {
|
||||
'expected_one_of': expected_lines,
|
||||
'got': test_line,
|
||||
}
|
||||
})
|
||||
else:
|
||||
if test_line != expected_lines:
|
||||
differences.append({
|
||||
'line': {
|
||||
'expected': expected_lines,
|
||||
'got': test_line,
|
||||
}
|
||||
})
|
||||
results.append({
|
||||
'name': result['test']['name'],
|
||||
'output': {
|
||||
'differences': differences,
|
||||
'expected': expected_output,
|
||||
'got': stdout_lines,
|
||||
},
|
||||
})
|
||||
return results
|
||||
|
||||
|
||||
class FilterModule:
|
||||
''' Jinja2 compat filters '''
|
||||
|
||||
def filters(self):
|
||||
return {
|
||||
'callback_results_extractor': callback_results_extractor,
|
||||
}
|
||||
@@ -50,44 +50,11 @@
|
||||
- name: Assert test output equals expected output
|
||||
assert:
|
||||
that: result.output.differences | length == 0
|
||||
loop: "{{ results }}"
|
||||
loop: "{{ outputs.results | callback_results_extractor }}"
|
||||
loop_control:
|
||||
loop_var: result
|
||||
label: "{{ result.name }}"
|
||||
register: assertions
|
||||
vars:
|
||||
results: >-
|
||||
{%- set results = [] -%}
|
||||
{%- for result in outputs.results -%}
|
||||
{%- set differences = [] -%}
|
||||
{%- for i in range([result.test.expected_output | count, result.stdout_lines | count] | max) -%}
|
||||
{%- set line = "line_%s" | format(i+1) -%}
|
||||
{%- set test_line = result.stdout_lines[i] | default(none) -%}
|
||||
{%- set expected_lines = result.test.expected_output[i] | default(none) -%}
|
||||
{%- if expected_lines is not string and expected_lines is not none -%}
|
||||
{%- if test_line not in expected_lines -%}
|
||||
{{- differences.append({
|
||||
line: {
|
||||
'expected_one_of': expected_lines,
|
||||
'got': test_line }}) -}}
|
||||
{%- endif -%}
|
||||
{%- else -%}
|
||||
{%- if expected_lines != test_line -%}
|
||||
{{- differences.append({
|
||||
line: {
|
||||
'expected': expected_lines,
|
||||
'got': test_line }}) -}}
|
||||
{%- endif -%}
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
{{- results.append({
|
||||
'name': result.test.name,
|
||||
'output': {
|
||||
'differences': differences,
|
||||
'expected': result.test.expected_output,
|
||||
'got': result.stdout_lines }}) -}}
|
||||
{%- endfor -%}
|
||||
{{- results -}}
|
||||
|
||||
always:
|
||||
- name: Remove temporary playbooks
|
||||
|
||||
@@ -17,5 +17,5 @@ ansible-playbook ping_log.yml -v "$@"
|
||||
# now force it to fail
|
||||
export ANSIBLE_LOG_FOLDER="logit.file"
|
||||
touch "${ANSIBLE_LOG_FOLDER}"
|
||||
ansible-playbook ping_log.yml -v "$@" 2>&1| grep 'Failure using method (v2_runner_on_ok) in callback plugin'
|
||||
ansible-playbook ping_log.yml -v "$@" 2>&1| grep -E "(Failure using method \(v2_runner_on_ok\) in callback plugin|Callback dispatch 'v2_runner_on_ok' failed for plugin)"
|
||||
[[ ! -f "${ANSIBLE_LOG_FOLDER}/localhost" ]]
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
ANSIBLE_NOCOLOR: 'true'
|
||||
ANSIBLE_FORCE_COLOR: 'false'
|
||||
ANSIBLE_STDOUT_CALLBACK: community.general.yaml
|
||||
playbook: |
|
||||
playbook: !unsafe |
|
||||
- hosts: testhost
|
||||
gather_facts: false
|
||||
vars:
|
||||
@@ -78,9 +78,7 @@
|
||||
tasks:
|
||||
- name: Test to_yaml
|
||||
debug:
|
||||
msg: "{{ '{{' }}'{{ '{{' }}'{{ '}}' }} data | to_yaml {{ '{{' }}'{{ '}}' }}'{{ '}}' }}"
|
||||
# The above should be: msg: "{{ data | to_yaml }}"
|
||||
# Unfortunately, the way Ansible handles templating, we need to do some funny 'escaping' tricks...
|
||||
msg: "{{ data | to_yaml }}"
|
||||
expected_output: [
|
||||
"",
|
||||
"PLAY [testhost] ****************************************************************",
|
||||
|
||||
@@ -20,4 +20,4 @@
|
||||
environment: "{{ cargo_environment }}"
|
||||
when: has_cargo | default(false)
|
||||
- import_tasks: test_rustup_cargo.yml
|
||||
when: rustup_cargo_bin | default(false)
|
||||
when: (rustup_cargo_bin | default(false)) is truthy
|
||||
|
||||
@@ -9,6 +9,12 @@ from ansible.errors import AnsibleError
|
||||
from ansible.playbook.conditional import Conditional
|
||||
from ansible.plugins.action import ActionBase
|
||||
|
||||
try:
|
||||
from ansible.utils.datatag import trust_value as _trust_value
|
||||
except ImportError:
|
||||
def _trust_value(input):
|
||||
return input
|
||||
|
||||
|
||||
class ActionModule(ActionBase):
|
||||
''' Fail with custom message '''
|
||||
@@ -36,12 +42,16 @@ class ActionModule(ActionBase):
|
||||
|
||||
thats = self._task.args['that']
|
||||
|
||||
cond = Conditional(loader=self._loader)
|
||||
result['_ansible_verbose_always'] = True
|
||||
|
||||
for that in thats:
|
||||
cond.when = [str(self._make_safe(that))]
|
||||
test_result = cond.evaluate_conditional(templar=self._templar, all_vars=task_vars)
|
||||
if hasattr(self._templar, 'evaluate_conditional'):
|
||||
trusted_that = _trust_value(that) if _trust_value else that
|
||||
test_result = self._templar.evaluate_conditional(conditional=trusted_that)
|
||||
else:
|
||||
cond = Conditional(loader=self._loader)
|
||||
cond.when = [str(self._make_safe(that))]
|
||||
test_result = cond.evaluate_conditional(templar=self._templar, all_vars=task_vars)
|
||||
if not test_result:
|
||||
result['failed'] = True
|
||||
result['evaluated_to'] = test_result
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
import traceback
|
||||
|
||||
|
||||
DOCUMENTATION = ""
|
||||
|
||||
@@ -43,15 +45,18 @@ def main():
|
||||
|
||||
arg_formats[arg] = func(*args)
|
||||
|
||||
runner = CmdRunner(module, [module.params["cmd"], '--'], arg_formats=arg_formats, path_prefix=module.params["path_prefix"])
|
||||
try:
|
||||
runner = CmdRunner(module, [module.params["cmd"], '--'], arg_formats=arg_formats, path_prefix=module.params["path_prefix"])
|
||||
|
||||
with runner.context(p['arg_order'], check_mode_skip=p['check_mode_skip']) as ctx:
|
||||
result = ctx.run(**p['arg_values'])
|
||||
info = ctx.run_info
|
||||
check = "check"
|
||||
rc, out, err = result if result is not None else (None, None, None)
|
||||
with runner.context(p['arg_order'], check_mode_skip=p['check_mode_skip']) as ctx:
|
||||
result = ctx.run(**p['arg_values'])
|
||||
info = ctx.run_info
|
||||
check = "check"
|
||||
rc, out, err = result if result is not None else (None, None, None)
|
||||
|
||||
module.exit_json(rc=rc, out=out, err=err, info=info)
|
||||
module.exit_json(rc=rc, out=out, err=err, info=info)
|
||||
except Exception as exc:
|
||||
module.fail_json(rc=1, module_stderr=traceback.format_exc(), msg="Module crashed with exception")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
that:
|
||||
- result is changed
|
||||
- result.binding_rule.AuthMethod == 'test'
|
||||
- result.binding.Description == 'test-binding: my description'
|
||||
- "result.binding_rule.Description == 'test-binding: my description'"
|
||||
- result.operation == 'create'
|
||||
|
||||
- name: Update a binding rule
|
||||
@@ -46,7 +46,7 @@
|
||||
- assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.binding.Description == 'test-binding: my description'
|
||||
- "result.binding_rule.Description == 'test-binding: my description'"
|
||||
- result.operation == 'update'
|
||||
|
||||
- name: Update a binding rule (noop)
|
||||
@@ -58,7 +58,7 @@
|
||||
- assert:
|
||||
that:
|
||||
- result is not changed
|
||||
- result.binding.Description == 'test-binding: my description'
|
||||
- "result.binding_rule.Description == 'test-binding: my description'"
|
||||
- result.operation is not defined
|
||||
|
||||
- name: Delete a binding rule
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
- assert:
|
||||
that:
|
||||
- simple_create_result is changed
|
||||
- simple_create_result.token.AccessorID
|
||||
- simple_create_result.token.AccessorID is truthy
|
||||
- simple_create_result.operation == 'create'
|
||||
|
||||
- name: Create token
|
||||
@@ -67,7 +67,7 @@
|
||||
state: present
|
||||
accessor_id: 07a7de84-c9c7-448a-99cc-beaf682efd21
|
||||
policies:
|
||||
- id: "{{ create_result.token.Policies[-1].ID }}"
|
||||
- name: foo-access2
|
||||
register: result
|
||||
|
||||
- assert:
|
||||
@@ -84,5 +84,5 @@
|
||||
- assert:
|
||||
that:
|
||||
- result is changed
|
||||
- not result.token
|
||||
- result.token is falsy
|
||||
- result.operation == 'remove'
|
||||
|
||||
@@ -123,11 +123,12 @@
|
||||
register: releases_path
|
||||
- stat: path={{ deploy_helper.shared_path }}
|
||||
register: shared_path
|
||||
when: deploy_helper.shared_path is truthy
|
||||
- name: Assert State=present with shared_path set to False
|
||||
assert:
|
||||
that:
|
||||
- "releases_path.stat.exists"
|
||||
- "not shared_path.stat.exists"
|
||||
- "deploy_helper.shared_path is falsy or not shared_path.stat.exists"
|
||||
|
||||
# Setup older releases for tests
|
||||
- file: path={{ deploy_helper.releases_path }}/{{ item }} state=directory
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
- include_tasks: install.yml
|
||||
- include_tasks: lock_bash.yml
|
||||
- include_tasks: lock_updates.yml
|
||||
when: (ansible_distribution == 'Fedora' and ansible_distribution_major_version is version('23', '>=') and ansible_distribution_major_version is version('41', '<')) or
|
||||
when: (ansible_distribution == 'Fedora' and ansible_distribution_major_version is version('23', '>=')) or
|
||||
(ansible_distribution in ['RedHat', 'CentOS'] and ansible_distribution_major_version is version('8', '>='))
|
||||
# TODO: Fix on Fedora 41, apparently the output changed!
|
||||
...
|
||||
|
||||
@@ -59,6 +59,8 @@
|
||||
item.0.key == "reiserfs")'
|
||||
# reiserfs packages apparently not available with Alpine
|
||||
- 'not (ansible_distribution == "Alpine" and item.0.key == "reiserfs")'
|
||||
# reiserfsprogs packages no longer available with Arch Linux
|
||||
- 'not (ansible_distribution == "Archlinux" and item.0.key == "reiserfs")'
|
||||
# ocfs2 only available on Debian based distributions
|
||||
- 'not (item.0.key == "ocfs2" and ansible_os_family != "Debian")'
|
||||
# Tests use losetup which can not be used inside unprivileged container
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
state: present
|
||||
when:
|
||||
- ansible_system == 'Linux'
|
||||
- ansible_os_family not in ['Suse', 'RedHat', 'Alpine']
|
||||
- ansible_os_family not in ['Suse', 'RedHat', 'Alpine', 'Archlinux']
|
||||
|
||||
- name: "Install reiserfs progs (FreeBSD)"
|
||||
ansible.builtin.package:
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
assert:
|
||||
that:
|
||||
- res is failed
|
||||
- res.msg is match('Argument for community.general.counter must be a sequence')
|
||||
- res.msg is search('Argument for community.general.counter must be a sequence')
|
||||
|
||||
- name: test fail element not hashable
|
||||
debug:
|
||||
@@ -38,4 +38,4 @@
|
||||
assert:
|
||||
that:
|
||||
- res is failed
|
||||
- res.msg is match('community.general.counter needs a sequence with hashable elements')
|
||||
- res.msg is search('community.general.counter needs a sequence with hashable elements')
|
||||
|
||||
@@ -51,4 +51,4 @@
|
||||
assert:
|
||||
that:
|
||||
- _invalid_csv_strict_true is failed
|
||||
- _invalid_csv_strict_true.msg is match('Unable to process file:.*')
|
||||
- _invalid_csv_strict_true.msg is search('Unable to process file:.*')
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- result.msg == 'Input is not a sequence'
|
||||
- result.msg is search('Input is not a sequence')
|
||||
|
||||
- name: 'Test error: list element not a mapping'
|
||||
set_fact:
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- "result.msg == 'Sequence element #0 is not a mapping'"
|
||||
- "result.msg is search('Sequence element #0 is not a mapping')"
|
||||
|
||||
- name: 'Test error: list element does not have attribute'
|
||||
set_fact:
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- "result.msg == 'Attribute not contained in element #1 of sequence'"
|
||||
- "result.msg is search('Attribute not contained in element #1 of sequence')"
|
||||
|
||||
- name: 'Test error: attribute collision'
|
||||
set_fact:
|
||||
@@ -46,4 +46,4 @@
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- result.msg == "Multiple sequence entries have attribute value 'a'" or result.msg == "Multiple sequence entries have attribute value u'a'"
|
||||
- result.msg is search("Multiple sequence entries have attribute value u?'a'")
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
- name: Register result of invalid salt
|
||||
debug:
|
||||
var: "invalid_input | community.general.hashids_encode(salt=10)"
|
||||
var: "single_int | community.general.hashids_encode(salt=10)"
|
||||
register: invalid_salt_message
|
||||
ignore_errors: true
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
|
||||
- name: Register result of invalid alphabet
|
||||
debug:
|
||||
var: "invalid_input | community.general.hashids_encode(alphabet='abc')"
|
||||
var: "single_int | community.general.hashids_encode(alphabet='abc')"
|
||||
register: invalid_alphabet_message
|
||||
ignore_errors: true
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
|
||||
- name: Register result of invalid min_length
|
||||
debug:
|
||||
var: "invalid_input | community.general.hashids_encode(min_length='foo')"
|
||||
var: "single_int | community.general.hashids_encode(min_length='foo')"
|
||||
register: invalid_min_length_message
|
||||
ignore_errors: true
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
- name: Debug ansible_version
|
||||
ansible.builtin.debug:
|
||||
var: ansible_version
|
||||
when: not quite_test | d(true) | bool
|
||||
when: not (quiet_test | default(true) | bool)
|
||||
tags: ansible_version
|
||||
|
||||
- name: Tests
|
||||
@@ -19,13 +19,13 @@
|
||||
fail_msg: |
|
||||
[ERR] result:
|
||||
{{ result | to_yaml }}
|
||||
quiet: "{{ quiet_test | d(true) | bool }}"
|
||||
quiet: "{{ quiet_test | default(true) | bool }}"
|
||||
loop: "{{ tests | subelements('group') }}"
|
||||
loop_control:
|
||||
loop_var: i
|
||||
label: "{{ i.1.mp | d('default') }}: {{ i.1.tt }}"
|
||||
label: "{{ i.1.mp | default('default') }}: {{ i.1.tt }}"
|
||||
vars:
|
||||
input: "{{ i.0.input }}"
|
||||
target: "{{ i.1.tt }}"
|
||||
mp: "{{ i.1.mp | d('default') }}"
|
||||
mp: "{{ i.1.mp | default('default') }}"
|
||||
result: "{{ lookup('template', i.0.template) }}"
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
{{ my_list|to_nice_yaml|indent(2) }}
|
||||
my_list|difference(result101):
|
||||
{{ my_list|difference(result101)|to_nice_yaml|indent(2) }}
|
||||
when: debug_test|d(false)|bool
|
||||
when: debug_test|default(false)|bool
|
||||
- name: Merge 2 lists by attribute name. list_merge='keep'. assert
|
||||
assert:
|
||||
that: my_list | difference(result101) | length == 0
|
||||
@@ -35,7 +35,7 @@
|
||||
{{ my_list|to_nice_yaml|indent(2) }}
|
||||
my_list|difference(result102):
|
||||
{{ my_list|difference(result102)|to_nice_yaml|indent(2) }}
|
||||
when: debug_test|d(false)|bool
|
||||
when: debug_test|default(false)|bool
|
||||
- name: Merge 2 lists by attribute name. list_merge='append'. assert
|
||||
assert:
|
||||
that: my_list | difference(result102) | length == 0
|
||||
@@ -54,7 +54,7 @@
|
||||
{{ my_list|to_nice_yaml|indent(2) }}
|
||||
my_list|difference(result103):
|
||||
{{ my_list|difference(result103)|to_nice_yaml|indent(2) }}
|
||||
when: debug_test|d(false)|bool
|
||||
when: debug_test|default(false)|bool
|
||||
- name: Merge 2 lists by attribute name. list_merge='prepend'. assert
|
||||
assert:
|
||||
that: my_list | difference(result103) | length == 0
|
||||
@@ -73,7 +73,7 @@
|
||||
{{ my_list|to_nice_yaml|indent(2) }}
|
||||
my_list|difference(result104):
|
||||
{{ my_list|difference(result104)|to_nice_yaml|indent(2) }}
|
||||
when: debug_test|d(false)|bool
|
||||
when: debug_test|default(false)|bool
|
||||
- name: Merge 2 lists by attribute name. list_merge='append_rp'. assert
|
||||
assert:
|
||||
that: my_list | difference(result104) | length == 0
|
||||
@@ -92,7 +92,7 @@
|
||||
{{ my_list|to_nice_yaml|indent(2) }}
|
||||
my_list|difference(result105):
|
||||
{{ my_list|difference(result105)|to_nice_yaml|indent(2) }}
|
||||
when: debug_test|d(false)|bool
|
||||
when: debug_test|default(false)|bool
|
||||
- name: Merge 2 lists by attribute name. list_merge='prepend_rp'. assert
|
||||
assert:
|
||||
that: my_list | difference(result105) | length == 0
|
||||
@@ -115,7 +115,7 @@
|
||||
{{ my_list|to_nice_yaml|indent(2) }}
|
||||
my_list|difference(result200):
|
||||
{{ my_list|difference(result200)|to_nice_yaml|indent(2) }}
|
||||
when: debug_test|d(false)|bool
|
||||
when: debug_test|default(false)|bool
|
||||
- name: Merge by name. recursive=True list_merge='append_rp'. assert
|
||||
assert:
|
||||
that: my_list | difference(result200) | length == 0
|
||||
@@ -136,7 +136,7 @@
|
||||
{{ my_list|to_nice_yaml|indent(2) }}
|
||||
my_list|difference(result201):
|
||||
{{ my_list|difference(result201)|to_nice_yaml|indent(2) }}
|
||||
when: debug_test|d(false)|bool
|
||||
when: debug_test|default(false)|bool
|
||||
- name: Merge by name. recursive=False list_merge='append_rp'. assert
|
||||
assert:
|
||||
that: my_list | difference(result201) | length == 0
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
- name: Debug ansible_version
|
||||
debug:
|
||||
var: ansible_version
|
||||
when: debug_test|d(false)|bool
|
||||
when: debug_test|default(false)|bool
|
||||
tags: t0
|
||||
|
||||
- name: 1. Test lists merged by attribute name
|
||||
@@ -14,7 +14,7 @@
|
||||
- name: Test lists merged by attribute name debug
|
||||
debug:
|
||||
msg: "{{ list1 | community.general.lists_mergeby(list2, 'name') }}"
|
||||
when: debug_test|d(false)|bool
|
||||
when: debug_test|default(false)|bool
|
||||
- name: Test lists merged by attribute name assert
|
||||
assert:
|
||||
that:
|
||||
@@ -27,7 +27,7 @@
|
||||
- name: Test list1 empty debug
|
||||
debug:
|
||||
msg: "{{ [] | community.general.lists_mergeby(list2, 'name') }}"
|
||||
when: debug_test|d(false)|bool
|
||||
when: debug_test|default(false)|bool
|
||||
- name: Test list1 empty assert
|
||||
assert:
|
||||
that:
|
||||
@@ -40,7 +40,7 @@
|
||||
- name: Test all lists empty debug
|
||||
debug:
|
||||
msg: "{{ [] | community.general.lists_mergeby([], 'name') }}"
|
||||
when: debug_test|d(false)|bool
|
||||
when: debug_test|default(false)|bool
|
||||
- name: Test all lists empty assert
|
||||
assert:
|
||||
that:
|
||||
@@ -58,7 +58,7 @@
|
||||
- name: First argument must be list debug
|
||||
debug:
|
||||
var: my_list
|
||||
when: debug_test|d(false)|bool
|
||||
when: debug_test|default(false)|bool
|
||||
- name: First argument must be list assert
|
||||
assert:
|
||||
that:
|
||||
@@ -76,7 +76,7 @@
|
||||
- name: Second argument must be list set debug
|
||||
debug:
|
||||
var: my_list
|
||||
when: debug_test|d(false)|bool
|
||||
when: debug_test|default(false)|bool
|
||||
- name: Second argument must be list set assert
|
||||
assert:
|
||||
that:
|
||||
@@ -94,7 +94,7 @@
|
||||
- name: First arguments after the lists must be string debug
|
||||
debug:
|
||||
var: my_list
|
||||
when: debug_test|d(false)|bool
|
||||
when: debug_test|default(false)|bool
|
||||
- name: First arguments after the lists must be string assert
|
||||
assert:
|
||||
that:
|
||||
@@ -112,7 +112,7 @@
|
||||
- name: Elements of list must be dictionaries debug
|
||||
debug:
|
||||
var: my_list
|
||||
when: debug_test|d(false)|bool
|
||||
when: debug_test|default(false)|bool
|
||||
- name: Elements of list must be dictionaries assert
|
||||
assert:
|
||||
that:
|
||||
@@ -128,7 +128,7 @@
|
||||
- name: Merge 3 lists by attribute name. 1 list in params. debug
|
||||
debug:
|
||||
var: my_list
|
||||
when: debug_test|d(false)|bool
|
||||
when: debug_test|default(false)|bool
|
||||
- name: Merge 3 lists by attribute name. 1 list in params. assert
|
||||
assert:
|
||||
that: my_list | difference(result1) | length == 0
|
||||
@@ -142,7 +142,7 @@
|
||||
- name: Merge 3 lists by attribute name. No list in the params. debug
|
||||
debug:
|
||||
var: my_list
|
||||
when: debug_test|d(false)|bool
|
||||
when: debug_test|default(false)|bool
|
||||
- name: Merge 3 lists by attribute name. No list in the params. asset
|
||||
assert:
|
||||
that: my_list | difference(result1) | length == 0
|
||||
@@ -162,7 +162,7 @@
|
||||
{{ my_list|to_nice_yaml|indent(2) }}
|
||||
my_list|difference(result100):
|
||||
{{ my_list|difference(result100)|to_nice_yaml|indent(2) }}
|
||||
when: debug_test|d(false)|bool
|
||||
when: debug_test|default(false)|bool
|
||||
- name: Merge 2 lists by attribute name. list_merge='replace'. assert
|
||||
assert:
|
||||
that: my_list | difference(result100) | length == 0
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
assert:
|
||||
that:
|
||||
- _bad_random_mac_filter is failed
|
||||
- "_bad_random_mac_filter.msg is match('Invalid value type (.*int.*) for random_mac .*')"
|
||||
- "_bad_random_mac_filter.msg is search('Invalid value type (.*int.*) for random_mac .*')"
|
||||
|
||||
- name: Test random_mac filter bad argument value
|
||||
debug:
|
||||
@@ -31,7 +31,7 @@
|
||||
assert:
|
||||
that:
|
||||
- _bad_random_mac_filter is failed
|
||||
- "_bad_random_mac_filter.msg is match('Invalid value (.*) for random_mac: .* not hexa byte')"
|
||||
- "_bad_random_mac_filter.msg is search('Invalid value (.*) for random_mac: .* not hexa byte')"
|
||||
|
||||
- name: Test random_mac filter prefix too big
|
||||
debug:
|
||||
@@ -43,7 +43,7 @@
|
||||
assert:
|
||||
that:
|
||||
- _bad_random_mac_filter is failed
|
||||
- "_bad_random_mac_filter.msg is match('Invalid value (.*) for random_mac: 5 colon.* separated items max')"
|
||||
- "_bad_random_mac_filter.msg is search('Invalid value (.*) for random_mac: 5 colon.* separated items max')"
|
||||
|
||||
- name: Verify random_mac filter
|
||||
assert:
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
- name: Debug ansible_version
|
||||
ansible.builtin.debug:
|
||||
var: ansible_version
|
||||
when: not quite_test | d(true) | bool
|
||||
when: not (quiet_test | default(true) | bool)
|
||||
tags: ansible_version
|
||||
|
||||
- name: Tests
|
||||
@@ -19,13 +19,13 @@
|
||||
fail_msg: |
|
||||
[ERR] result:
|
||||
{{ result | to_yaml }}
|
||||
quiet: "{{ quiet_test | d(true) | bool }}"
|
||||
quiet: "{{ quiet_test | default(true) | bool }}"
|
||||
loop: "{{ tests | subelements('group') }}"
|
||||
loop_control:
|
||||
loop_var: i
|
||||
label: "{{ i.1.mp | d('default') }}: {{ i.1.tt }}"
|
||||
label: "{{ i.1.mp | default('default') }}: {{ i.1.tt }}"
|
||||
vars:
|
||||
input: "{{ i.0.input }}"
|
||||
target: "{{ i.1.tt }}"
|
||||
mp: "{{ i.1.mp | d('default') }}"
|
||||
mp: "{{ i.1.mp | default('default') }}"
|
||||
result: "{{ lookup('template', i.0.template) }}"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
- name: Debug ansible_version
|
||||
ansible.builtin.debug:
|
||||
var: ansible_version
|
||||
when: not quite_test | d(true) | bool
|
||||
when: not (quiet_test | default(true) | bool)
|
||||
tags: ansible_version
|
||||
|
||||
- name: Tests
|
||||
@@ -19,13 +19,13 @@
|
||||
fail_msg: |
|
||||
[ERR] result:
|
||||
{{ result | to_yaml }}
|
||||
quiet: "{{ quiet_test | d(true) | bool }}"
|
||||
quiet: "{{ quiet_test | default(true) | bool }}"
|
||||
loop: "{{ tests | subelements('group') }}"
|
||||
loop_control:
|
||||
loop_var: i
|
||||
label: "{{ i.1.mp | d('default') }}: {{ i.1.tt }}"
|
||||
label: "{{ i.1.mp | default('default') }}: {{ i.1.tt }}"
|
||||
vars:
|
||||
input: "{{ i.0.input }}"
|
||||
target: "{{ i.1.tt }}"
|
||||
mp: "{{ i.1.mp | d('default') }}"
|
||||
mp: "{{ i.1.mp | default('default') }}"
|
||||
result: "{{ lookup('template', i.0.template) }}"
|
||||
|
||||
@@ -2,53 +2,60 @@
|
||||
# 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
|
||||
|
||||
# Substitution converts str to AnsibleUnicode
|
||||
# -------------------------------------------
|
||||
# Substitution converts str to AnsibleUnicode/_AnsibleTaggedStr
|
||||
# -------------------------------------------------------------
|
||||
|
||||
- name: String. AnsibleUnicode.
|
||||
- name: String. AnsibleUnicode/_AnsibleTaggedStr.
|
||||
assert:
|
||||
that: result == dtype
|
||||
success_msg: '"abc" is {{ dtype }}'
|
||||
fail_msg: '"abc" is {{ result }}'
|
||||
quiet: '{{ quiet_test | d(true) | bool }}'
|
||||
that: result in dtype
|
||||
success_msg: '"abc" is one of {{ dtype }}'
|
||||
fail_msg: '"abc" is {{ result }}, not one of {{ dtype }}'
|
||||
quiet: '{{ quiet_test | default(true) | bool }}'
|
||||
vars:
|
||||
data: "abc"
|
||||
result: '{{ data | community.general.reveal_ansible_type }}'
|
||||
dtype: 'AnsibleUnicode'
|
||||
dtype:
|
||||
- 'AnsibleUnicode'
|
||||
- '_AnsibleTaggedStr'
|
||||
|
||||
- name: String. AnsibleUnicode alias str.
|
||||
- name: String. AnsibleUnicode/_AnsibleTaggedStr alias str.
|
||||
assert:
|
||||
that: result == dtype
|
||||
success_msg: '"abc" is {{ dtype }}'
|
||||
fail_msg: '"abc" is {{ result }}'
|
||||
quiet: '{{ quiet_test | d(true) | bool }}'
|
||||
that: result in dtype
|
||||
success_msg: '"abc" is one of {{ dtype }}'
|
||||
fail_msg: '"abc" is {{ result }}, not one of {{ dtype }}'
|
||||
quiet: '{{ quiet_test | default(true) | bool }}'
|
||||
vars:
|
||||
alias: {"AnsibleUnicode": "str"}
|
||||
alias: {"AnsibleUnicode": "str", "_AnsibleTaggedStr": "str"}
|
||||
data: "abc"
|
||||
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
|
||||
dtype: 'str'
|
||||
dtype:
|
||||
- 'str'
|
||||
|
||||
- name: List. All items are AnsibleUnicode.
|
||||
- name: List. All items are AnsibleUnicode/_AnsibleTaggedStr.
|
||||
assert:
|
||||
that: result == dtype
|
||||
success_msg: '["a", "b", "c"] is {{ dtype }}'
|
||||
fail_msg: '["a", "b", "c"] is {{ result }}'
|
||||
quiet: '{{ quiet_test | d(true) | bool }}'
|
||||
that: result in dtype
|
||||
success_msg: '["a", "b", "c"] is one of {{ dtype }}'
|
||||
fail_msg: '["a", "b", "c"] is {{ result }}, not one of {{ dtype }}'
|
||||
quiet: '{{ quiet_test | default(true) | bool }}'
|
||||
vars:
|
||||
data: ["a", "b", "c"]
|
||||
result: '{{ data | community.general.reveal_ansible_type }}'
|
||||
dtype: 'list[AnsibleUnicode]'
|
||||
dtype:
|
||||
- 'list[AnsibleUnicode]'
|
||||
- 'list[_AnsibleTaggedStr]'
|
||||
|
||||
- name: Dictionary. All keys are AnsibleUnicode. All values are AnsibleUnicode.
|
||||
- name: Dictionary. All keys and values are AnsibleUnicode/_AnsibleTaggedStr.
|
||||
assert:
|
||||
that: result == dtype
|
||||
success_msg: '{"a": "foo", "b": "bar", "c": "baz"} is {{ dtype }}'
|
||||
fail_msg: '{"a": "foo", "b": "bar", "c": "baz"} is {{ result }}'
|
||||
quiet: '{{ quiet_test | d(true) | bool }}'
|
||||
that: result in dtype
|
||||
success_msg: '{"a": "foo", "b": "bar", "c": "baz"} is one of {{ dtype }}'
|
||||
fail_msg: '{"a": "foo", "b": "bar", "c": "baz"} is {{ result }}, not one of {{ dtype }}'
|
||||
quiet: '{{ quiet_test | default(true) | bool }}'
|
||||
vars:
|
||||
data: {"a": "foo", "b": "bar", "c": "baz"}
|
||||
result: '{{ data | community.general.reveal_ansible_type }}'
|
||||
dtype: 'dict[AnsibleUnicode, AnsibleUnicode]'
|
||||
dtype:
|
||||
- 'dict[AnsibleUnicode, AnsibleUnicode]'
|
||||
- 'dict[_AnsibleTaggedStr, _AnsibleTaggedStr]'
|
||||
|
||||
# No substitution and no alias. Type of strings is str
|
||||
# ----------------------------------------------------
|
||||
@@ -57,8 +64,8 @@
|
||||
assert:
|
||||
that: result == dtype
|
||||
success_msg: '"abc" is {{ dtype }}'
|
||||
fail_msg: '"abc" is {{ result }}'
|
||||
quiet: '{{ quiet_test | d(true) | bool }}'
|
||||
fail_msg: '"abc" is {{ result }}, not {{ dtype }}'
|
||||
quiet: '{{ quiet_test | default(true) | bool }}'
|
||||
vars:
|
||||
result: '{{ "abc" | community.general.reveal_ansible_type }}'
|
||||
dtype: str
|
||||
@@ -67,8 +74,8 @@
|
||||
assert:
|
||||
that: result == dtype
|
||||
success_msg: '123 is {{ dtype }}'
|
||||
fail_msg: '123 is {{ result }}'
|
||||
quiet: '{{ quiet_test | d(true) | bool }}'
|
||||
fail_msg: '123 is {{ result }}, not {{ dtype }}'
|
||||
quiet: '{{ quiet_test | default(true) | bool }}'
|
||||
vars:
|
||||
result: '{{ 123 | community.general.reveal_ansible_type }}'
|
||||
dtype: int
|
||||
@@ -77,8 +84,8 @@
|
||||
assert:
|
||||
that: result == dtype
|
||||
success_msg: '123.45 is {{ dtype }}'
|
||||
fail_msg: '123.45 is {{ result }}'
|
||||
quiet: '{{ quiet_test | d(true) | bool }}'
|
||||
fail_msg: '123.45 is {{ result }}, not {{ dtype }}'
|
||||
quiet: '{{ quiet_test | default(true) | bool }}'
|
||||
vars:
|
||||
result: '{{ 123.45 | community.general.reveal_ansible_type }}'
|
||||
dtype: float
|
||||
@@ -87,8 +94,8 @@
|
||||
assert:
|
||||
that: result == dtype
|
||||
success_msg: 'true is {{ dtype }}'
|
||||
fail_msg: 'true is {{ result }}'
|
||||
quiet: '{{ quiet_test | d(true) | bool }}'
|
||||
fail_msg: 'true is {{ result }}, not {{ dtype }}'
|
||||
quiet: '{{ quiet_test | default(true) | bool }}'
|
||||
vars:
|
||||
result: '{{ true | community.general.reveal_ansible_type }}'
|
||||
dtype: bool
|
||||
@@ -97,8 +104,8 @@
|
||||
assert:
|
||||
that: result == dtype
|
||||
success_msg: '["a", "b", "c"] is {{ dtype }}'
|
||||
fail_msg: '["a", "b", "c"] is {{ result }}'
|
||||
quiet: '{{ quiet_test | d(true) | bool }}'
|
||||
fail_msg: '["a", "b", "c"] is {{ result }}, not {{ dtype }}'
|
||||
quiet: '{{ quiet_test | default(true) | bool }}'
|
||||
vars:
|
||||
result: '{{ ["a", "b", "c"] | community.general.reveal_ansible_type }}'
|
||||
dtype: list[str]
|
||||
@@ -107,8 +114,8 @@
|
||||
assert:
|
||||
that: result == dtype
|
||||
success_msg: '[{"a": 1}, {"b": 2}] is {{ dtype }}'
|
||||
fail_msg: '[{"a": 1}, {"b": 2}] is {{ result }}'
|
||||
quiet: '{{ quiet_test | d(true) | bool }}'
|
||||
fail_msg: '[{"a": 1}, {"b": 2}] is {{ result }}, not {{ dtype }}'
|
||||
quiet: '{{ quiet_test | default(true) | bool }}'
|
||||
vars:
|
||||
result: '{{ [{"a": 1}, {"b": 2}] | community.general.reveal_ansible_type }}'
|
||||
dtype: list[dict]
|
||||
@@ -117,8 +124,8 @@
|
||||
assert:
|
||||
that: result == dtype
|
||||
success_msg: '{"a": 1} is {{ dtype }}'
|
||||
fail_msg: '{"a": 1} is {{ result }}'
|
||||
quiet: '{{ quiet_test | d(true) | bool }}'
|
||||
fail_msg: '{"a": 1} is {{ result }}, not {{ dtype }}'
|
||||
quiet: '{{ quiet_test | default(true) | bool }}'
|
||||
vars:
|
||||
result: '{{ {"a": 1} | community.general.reveal_ansible_type }}'
|
||||
dtype: dict[str, int]
|
||||
@@ -127,23 +134,23 @@
|
||||
assert:
|
||||
that: result == dtype
|
||||
success_msg: '{"a": 1, "b": 2} is {{ dtype }}'
|
||||
fail_msg: '{"a": 1, "b": 2} is {{ result }}'
|
||||
quiet: '{{ quiet_test | d(true) | bool }}'
|
||||
fail_msg: '{"a": 1, "b": 2} is {{ result }}, not {{ dtype }}'
|
||||
quiet: '{{ quiet_test | default(true) | bool }}'
|
||||
vars:
|
||||
result: '{{ {"a": 1, "b": 2} | community.general.reveal_ansible_type }}'
|
||||
dtype: dict[str, int]
|
||||
|
||||
# Type of strings is AnsibleUnicode or str
|
||||
# ----------------------------------------
|
||||
# Type of strings is AnsibleUnicode/_AnsibleTaggedStr or str
|
||||
# ----------------------------------------------------------
|
||||
|
||||
- name: Dictionary. The keys are integers or strings. All values are strings.
|
||||
assert:
|
||||
that: result == dtype
|
||||
success_msg: 'data is {{ dtype }}'
|
||||
fail_msg: 'data is {{ result }}'
|
||||
quiet: '{{ quiet_test | d(true) | bool }}'
|
||||
fail_msg: 'data is {{ result }}, not {{ dtype }}'
|
||||
quiet: '{{ quiet_test | default(true) | bool }}'
|
||||
vars:
|
||||
alias: {"AnsibleUnicode": "str"}
|
||||
alias: {"AnsibleUnicode": "str", "_AnsibleTaggedStr": "str", "_AnsibleTaggedInt": "int"}
|
||||
data: {1: 'a', 'b': 'b'}
|
||||
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
|
||||
dtype: dict[int|str, str]
|
||||
@@ -152,10 +159,10 @@
|
||||
assert:
|
||||
that: result == dtype
|
||||
success_msg: 'data is {{ dtype }}'
|
||||
fail_msg: 'data is {{ result }}'
|
||||
quiet: '{{ quiet_test | d(true) | bool }}'
|
||||
fail_msg: 'data is {{ result }}, not {{ dtype }}'
|
||||
quiet: '{{ quiet_test | default(true) | bool }}'
|
||||
vars:
|
||||
alias: {"AnsibleUnicode": "str"}
|
||||
alias: {"AnsibleUnicode": "str", "_AnsibleTaggedStr": "str", "_AnsibleTaggedInt": "int"}
|
||||
data: {1: 'a', 2: 'b'}
|
||||
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
|
||||
dtype: dict[int, str]
|
||||
@@ -164,10 +171,10 @@
|
||||
assert:
|
||||
that: result == dtype
|
||||
success_msg: 'data is {{ dtype }}'
|
||||
fail_msg: 'data is {{ result }}'
|
||||
quiet: '{{ quiet_test | d(true) | bool }}'
|
||||
fail_msg: 'data is {{ result }}, not {{ dtype }}'
|
||||
quiet: '{{ quiet_test | default(true) | bool }}'
|
||||
vars:
|
||||
alias: {"AnsibleUnicode": "str"}
|
||||
alias: {"AnsibleUnicode": "str", "_AnsibleTaggedStr": "str", "_AnsibleTaggedInt": "int", "_AnsibleTaggedFloat": "float"}
|
||||
data: {'a': 1, 'b': 1.1, 'c': 'abc', 'd': True, 'e': ['x', 'y', 'z'], 'f': {'x': 1, 'y': 2}}
|
||||
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
|
||||
dtype: dict[str, bool|dict|float|int|list|str]
|
||||
@@ -176,10 +183,10 @@
|
||||
assert:
|
||||
that: result == dtype
|
||||
success_msg: 'data is {{ dtype }}'
|
||||
fail_msg: 'data is {{ result }}'
|
||||
quiet: '{{ quiet_test | d(true) | bool }}'
|
||||
fail_msg: 'data is {{ result }}, not {{ dtype }}'
|
||||
quiet: '{{ quiet_test | default(true) | bool }}'
|
||||
vars:
|
||||
alias: {"AnsibleUnicode": "str"}
|
||||
alias: {"AnsibleUnicode": "str", "_AnsibleTaggedStr": "str", "_AnsibleTaggedInt": "int", "_AnsibleTaggedFloat": "float"}
|
||||
data: [1, 2, 1.1, 'abc', True, ['x', 'y', 'z'], {'x': 1, 'y': 2}]
|
||||
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
|
||||
dtype: list[bool|dict|float|int|list|str]
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
azp/posix/2
|
||||
skip/python3
|
||||
skip/aix
|
||||
skip/macos
|
||||
disabled # TODO osdn.net is out of business, so cloning a repo from there does not work
|
||||
|
||||
@@ -6,3 +6,4 @@
|
||||
dependencies:
|
||||
- setup_pkg_mgr
|
||||
- setup_remote_tmp_dir
|
||||
- setup_epel
|
||||
|
||||
@@ -26,6 +26,12 @@
|
||||
shell: apt-get -y update && apt-get -y install mercurial
|
||||
when: ansible_facts.pkg_mgr == 'apt'
|
||||
|
||||
- name: install packages (apk)
|
||||
package:
|
||||
name: mercurial
|
||||
state: present
|
||||
when: ansible_facts.pkg_mgr in ['apk', 'community.general.apk']
|
||||
|
||||
- name: install mercurial (dnf)
|
||||
dnf:
|
||||
name: mercurial
|
||||
@@ -36,6 +42,11 @@
|
||||
name: mercurial
|
||||
when: ansible_facts.pkg_mgr == 'yum'
|
||||
|
||||
- name: install mercurial (pacman)
|
||||
package:
|
||||
name: mercurial
|
||||
when: ansible_facts.pkg_mgr in ['pacman', 'community.general.pacman']
|
||||
|
||||
- name: install mercurial (pkgng)
|
||||
package:
|
||||
name: mercurial
|
||||
|
||||
@@ -16,6 +16,12 @@
|
||||
line: "#!{{ stat_hg_interpreter.stat.path }}"
|
||||
when: stat_hg_interpreter.stat.islnk
|
||||
|
||||
- name: uninstall packages which were not originally installed (apk)
|
||||
package:
|
||||
name: mercurial
|
||||
state: absent
|
||||
when: ansible_facts.pkg_mgr in ['apk', 'community.general.apk']
|
||||
|
||||
# using the apt module prevents autoremove from working, so call apt-get via shell instead
|
||||
- name: uninstall packages which were not originally installed (apt)
|
||||
shell: apt-get -y remove mercurial && apt-get -y autoremove
|
||||
@@ -33,6 +39,12 @@
|
||||
shell: yum -y autoremove mercurial
|
||||
when: ansible_facts.pkg_mgr == 'yum'
|
||||
|
||||
- name: uninstall packages which were not originally installed (pacman)
|
||||
package:
|
||||
name: mercurial
|
||||
state: absent
|
||||
when: ansible_facts.pkg_mgr in ['pacman', 'community.general.pacman']
|
||||
|
||||
- name: uninstall packages which were not originally installed (pkgng)
|
||||
package:
|
||||
name: mercurial
|
||||
|
||||
@@ -7,3 +7,5 @@ skip/aix
|
||||
skip/freebsd
|
||||
skip/rhel
|
||||
skip/docker
|
||||
skip/macos14.3
|
||||
skip/macos13.2
|
||||
|
||||
@@ -253,7 +253,7 @@
|
||||
path: "{{ output_file }}"
|
||||
section: mysqld
|
||||
option: "{{ item.o }}"
|
||||
value: "{{ item.v | d(omit) }}"
|
||||
value: "{{ item.v | default(omit) }}"
|
||||
allow_no_value: true
|
||||
loop:
|
||||
- { o: "skip-name-resolve" }
|
||||
@@ -512,10 +512,10 @@
|
||||
- name: test-value 20 - Tests with empty strings
|
||||
ini_file:
|
||||
path: "{{ output_file }}"
|
||||
section: "{{ item.section | d('extensions') }}"
|
||||
section: "{{ item.section | default('extensions') }}"
|
||||
option: "{{ item.option }}"
|
||||
value: ""
|
||||
allow_no_value: "{{ item.no_value | d(omit) }}"
|
||||
allow_no_value: "{{ item.no_value | default(omit) }}"
|
||||
loop:
|
||||
- option: evolve
|
||||
- option: regress
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user