mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-04-30 10:26:52 +00:00
Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80fbcf2f98 | ||
|
|
a722e038cc | ||
|
|
19c8d2164d | ||
|
|
d4656ffca2 | ||
|
|
b49607f12d | ||
|
|
af0ce4284f | ||
|
|
f5f862617a | ||
|
|
a1a4ba4337 | ||
|
|
b0b783f8ff | ||
|
|
e670ca666a | ||
|
|
49b991527e | ||
|
|
e6cc671a0d | ||
|
|
797ea23e50 | ||
|
|
4d23b7a48b | ||
|
|
020b47a1a9 | ||
|
|
0da9d956a0 | ||
|
|
5691e3aff3 | ||
|
|
007333dbfe | ||
|
|
05666b0e4d | ||
|
|
c934d9aeb5 | ||
|
|
5b15e4089a | ||
|
|
a6379e45ce | ||
|
|
b95176dbc8 | ||
|
|
b752fea121 | ||
|
|
cf50990fed | ||
|
|
45343e6bc0 | ||
|
|
51540f6345 | ||
|
|
74eba52028 | ||
|
|
b920e8abf2 | ||
|
|
75c0004e1e | ||
|
|
be42fd4af7 | ||
|
|
1c05908ff6 | ||
|
|
ea42b75378 | ||
|
|
0330f4b52c | ||
|
|
1d8c659ba2 | ||
|
|
e784254679 | ||
|
|
d5e1edd284 |
@@ -24,15 +24,14 @@ schedules:
|
|||||||
always: true
|
always: true
|
||||||
branches:
|
branches:
|
||||||
include:
|
include:
|
||||||
|
- stable-2
|
||||||
- stable-3
|
- stable-3
|
||||||
- stable-4
|
|
||||||
- cron: 0 11 * * 0
|
- cron: 0 11 * * 0
|
||||||
displayName: Weekly (old stable branches)
|
displayName: Weekly (old stable branches)
|
||||||
always: true
|
always: true
|
||||||
branches:
|
branches:
|
||||||
include:
|
include:
|
||||||
- stable-1
|
- stable-1
|
||||||
- stable-2
|
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
- name: checkoutPath
|
- name: checkoutPath
|
||||||
@@ -69,32 +68,6 @@ stages:
|
|||||||
- test: 3
|
- test: 3
|
||||||
- test: 4
|
- test: 4
|
||||||
- test: extra
|
- test: extra
|
||||||
- stage: Sanity_2_13
|
|
||||||
displayName: Sanity 2.13
|
|
||||||
dependsOn: []
|
|
||||||
jobs:
|
|
||||||
- template: templates/matrix.yml
|
|
||||||
parameters:
|
|
||||||
nameFormat: Test {0}
|
|
||||||
testFormat: 2.13/sanity/{0}
|
|
||||||
targets:
|
|
||||||
- test: 1
|
|
||||||
- test: 2
|
|
||||||
- test: 3
|
|
||||||
- test: 4
|
|
||||||
- stage: Sanity_2_12
|
|
||||||
displayName: Sanity 2.12
|
|
||||||
dependsOn: []
|
|
||||||
jobs:
|
|
||||||
- template: templates/matrix.yml
|
|
||||||
parameters:
|
|
||||||
nameFormat: Test {0}
|
|
||||||
testFormat: 2.12/sanity/{0}
|
|
||||||
targets:
|
|
||||||
- test: 1
|
|
||||||
- test: 2
|
|
||||||
- test: 3
|
|
||||||
- test: 4
|
|
||||||
- stage: Sanity_2_11
|
- stage: Sanity_2_11
|
||||||
displayName: Sanity 2.11
|
displayName: Sanity 2.11
|
||||||
dependsOn: []
|
dependsOn: []
|
||||||
@@ -144,38 +117,13 @@ stages:
|
|||||||
nameFormat: Python {0}
|
nameFormat: Python {0}
|
||||||
testFormat: devel/units/{0}/1
|
testFormat: devel/units/{0}/1
|
||||||
targets:
|
targets:
|
||||||
|
- test: 2.6
|
||||||
- test: 2.7
|
- test: 2.7
|
||||||
- test: 3.5
|
- test: 3.5
|
||||||
- test: 3.6
|
- test: 3.6
|
||||||
- test: 3.7
|
- test: 3.7
|
||||||
- test: 3.8
|
- test: 3.8
|
||||||
- test: 3.9
|
- test: 3.9
|
||||||
- test: '3.10'
|
|
||||||
- stage: Units_2_13
|
|
||||||
displayName: Units 2.13
|
|
||||||
dependsOn: []
|
|
||||||
jobs:
|
|
||||||
- template: templates/matrix.yml
|
|
||||||
parameters:
|
|
||||||
nameFormat: Python {0}
|
|
||||||
testFormat: 2.13/units/{0}/1
|
|
||||||
targets:
|
|
||||||
- test: 2.7
|
|
||||||
- test: 3.6
|
|
||||||
- test: 3.8
|
|
||||||
- test: 3.9
|
|
||||||
- stage: Units_2_12
|
|
||||||
displayName: Units 2.12
|
|
||||||
dependsOn: []
|
|
||||||
jobs:
|
|
||||||
- template: templates/matrix.yml
|
|
||||||
parameters:
|
|
||||||
nameFormat: Python {0}
|
|
||||||
testFormat: 2.12/units/{0}/1
|
|
||||||
targets:
|
|
||||||
- test: 2.6
|
|
||||||
- test: 3.5
|
|
||||||
- test: 3.8
|
|
||||||
- stage: Units_2_11
|
- stage: Units_2_11
|
||||||
displayName: Units 2.11
|
displayName: Units 2.11
|
||||||
dependsOn: []
|
dependsOn: []
|
||||||
@@ -188,6 +136,9 @@ stages:
|
|||||||
- test: 2.6
|
- test: 2.6
|
||||||
- test: 2.7
|
- test: 2.7
|
||||||
- test: 3.5
|
- test: 3.5
|
||||||
|
- test: 3.6
|
||||||
|
- test: 3.7
|
||||||
|
- test: 3.8
|
||||||
- test: 3.9
|
- test: 3.9
|
||||||
- stage: Units_2_10
|
- stage: Units_2_10
|
||||||
displayName: Units 2.10
|
displayName: Units 2.10
|
||||||
@@ -198,8 +149,13 @@ stages:
|
|||||||
nameFormat: Python {0}
|
nameFormat: Python {0}
|
||||||
testFormat: 2.10/units/{0}/1
|
testFormat: 2.10/units/{0}/1
|
||||||
targets:
|
targets:
|
||||||
|
- test: 2.6
|
||||||
- test: 2.7
|
- test: 2.7
|
||||||
|
- test: 3.5
|
||||||
- test: 3.6
|
- test: 3.6
|
||||||
|
- test: 3.7
|
||||||
|
- test: 3.8
|
||||||
|
- test: 3.9
|
||||||
- stage: Units_2_9
|
- stage: Units_2_9
|
||||||
displayName: Units 2.9
|
displayName: Units 2.9
|
||||||
dependsOn: []
|
dependsOn: []
|
||||||
@@ -210,7 +166,11 @@ stages:
|
|||||||
testFormat: 2.9/units/{0}/1
|
testFormat: 2.9/units/{0}/1
|
||||||
targets:
|
targets:
|
||||||
- test: 2.6
|
- test: 2.6
|
||||||
|
- test: 2.7
|
||||||
- test: 3.5
|
- test: 3.5
|
||||||
|
- test: 3.6
|
||||||
|
- test: 3.7
|
||||||
|
- test: 3.8
|
||||||
|
|
||||||
## Remote
|
## Remote
|
||||||
- stage: Remote_devel
|
- stage: Remote_devel
|
||||||
@@ -220,54 +180,21 @@ stages:
|
|||||||
- template: templates/matrix.yml
|
- template: templates/matrix.yml
|
||||||
parameters:
|
parameters:
|
||||||
testFormat: devel/{0}
|
testFormat: devel/{0}
|
||||||
targets:
|
|
||||||
- name: macOS 12.0
|
|
||||||
test: macos/12.0
|
|
||||||
- name: RHEL 7.9
|
|
||||||
test: rhel/7.9
|
|
||||||
- name: RHEL 8.5
|
|
||||||
test: rhel/8.5
|
|
||||||
- name: FreeBSD 12.3
|
|
||||||
test: freebsd/12.3
|
|
||||||
- name: FreeBSD 13.0
|
|
||||||
test: freebsd/13.0
|
|
||||||
groups:
|
|
||||||
- 1
|
|
||||||
- 2
|
|
||||||
- 3
|
|
||||||
- stage: Remote_2_13
|
|
||||||
displayName: Remote 2.13
|
|
||||||
dependsOn: []
|
|
||||||
jobs:
|
|
||||||
- template: templates/matrix.yml
|
|
||||||
parameters:
|
|
||||||
testFormat: 2.13/{0}
|
|
||||||
targets:
|
|
||||||
- name: macOS 12.0
|
|
||||||
test: macos/12.0
|
|
||||||
- name: RHEL 8.5
|
|
||||||
test: rhel/8.5
|
|
||||||
groups:
|
|
||||||
- 1
|
|
||||||
- 2
|
|
||||||
- 3
|
|
||||||
- stage: Remote_2_12
|
|
||||||
displayName: Remote 2.12
|
|
||||||
dependsOn: []
|
|
||||||
jobs:
|
|
||||||
- template: templates/matrix.yml
|
|
||||||
parameters:
|
|
||||||
testFormat: 2.12/{0}
|
|
||||||
targets:
|
targets:
|
||||||
- name: macOS 11.1
|
- name: macOS 11.1
|
||||||
test: macos/11.1
|
test: macos/11.1
|
||||||
- name: RHEL 8.4
|
- name: RHEL 7.9
|
||||||
test: rhel/8.4
|
test: rhel/7.9
|
||||||
|
- name: RHEL 8.3
|
||||||
|
test: rhel/8.3
|
||||||
|
- name: FreeBSD 12.2
|
||||||
|
test: freebsd/12.2
|
||||||
- name: FreeBSD 13.0
|
- name: FreeBSD 13.0
|
||||||
test: freebsd/13.0
|
test: freebsd/13.0
|
||||||
groups:
|
groups:
|
||||||
- 1
|
- 1
|
||||||
- 2
|
- 2
|
||||||
|
- 3
|
||||||
- stage: Remote_2_11
|
- stage: Remote_2_11
|
||||||
displayName: Remote 2.11
|
displayName: Remote 2.11
|
||||||
dependsOn: []
|
dependsOn: []
|
||||||
@@ -276,6 +203,8 @@ stages:
|
|||||||
parameters:
|
parameters:
|
||||||
testFormat: 2.11/{0}
|
testFormat: 2.11/{0}
|
||||||
targets:
|
targets:
|
||||||
|
- name: macOS 11.1
|
||||||
|
test: macos/11.1
|
||||||
- name: RHEL 7.9
|
- name: RHEL 7.9
|
||||||
test: rhel/7.9
|
test: rhel/7.9
|
||||||
- name: RHEL 8.3
|
- name: RHEL 8.3
|
||||||
@@ -297,6 +226,14 @@ stages:
|
|||||||
test: osx/10.11
|
test: osx/10.11
|
||||||
- name: macOS 10.15
|
- name: macOS 10.15
|
||||||
test: macos/10.15
|
test: macos/10.15
|
||||||
|
- name: macOS 11.1
|
||||||
|
test: macos/11.1
|
||||||
|
- name: RHEL 7.8
|
||||||
|
test: rhel/7.8
|
||||||
|
- name: RHEL 8.2
|
||||||
|
test: rhel/8.2
|
||||||
|
- name: FreeBSD 12.1
|
||||||
|
test: freebsd/12.1
|
||||||
groups:
|
groups:
|
||||||
- 1
|
- 1
|
||||||
- 2
|
- 2
|
||||||
@@ -310,8 +247,6 @@ stages:
|
|||||||
targets:
|
targets:
|
||||||
- name: RHEL 8.2
|
- name: RHEL 8.2
|
||||||
test: rhel/8.2
|
test: rhel/8.2
|
||||||
- name: RHEL 7.8
|
|
||||||
test: rhel/7.8
|
|
||||||
- name: FreeBSD 12.0
|
- name: FreeBSD 12.0
|
||||||
test: freebsd/12.0
|
test: freebsd/12.0
|
||||||
groups:
|
groups:
|
||||||
@@ -327,56 +262,24 @@ stages:
|
|||||||
parameters:
|
parameters:
|
||||||
testFormat: devel/linux/{0}
|
testFormat: devel/linux/{0}
|
||||||
targets:
|
targets:
|
||||||
|
- name: CentOS 6
|
||||||
|
test: centos6
|
||||||
- name: CentOS 7
|
- name: CentOS 7
|
||||||
test: centos7
|
test: centos7
|
||||||
|
- name: CentOS 8
|
||||||
|
test: centos8
|
||||||
|
- name: Fedora 33
|
||||||
|
test: fedora33
|
||||||
- name: Fedora 34
|
- name: Fedora 34
|
||||||
test: fedora34
|
test: fedora34
|
||||||
- name: Fedora 35
|
- name: openSUSE 15 py2
|
||||||
test: fedora35
|
test: opensuse15py2
|
||||||
- name: openSUSE 15
|
- name: openSUSE 15 py3
|
||||||
test: opensuse15
|
test: opensuse15
|
||||||
- name: Ubuntu 18.04
|
- name: Ubuntu 18.04
|
||||||
test: ubuntu1804
|
test: ubuntu1804
|
||||||
- name: Ubuntu 20.04
|
- name: Ubuntu 20.04
|
||||||
test: ubuntu2004
|
test: ubuntu2004
|
||||||
- name: Alpine 3
|
|
||||||
test: alpine3
|
|
||||||
groups:
|
|
||||||
- 1
|
|
||||||
- 2
|
|
||||||
- 3
|
|
||||||
- stage: Docker_2_13
|
|
||||||
displayName: Docker 2.13
|
|
||||||
dependsOn: []
|
|
||||||
jobs:
|
|
||||||
- template: templates/matrix.yml
|
|
||||||
parameters:
|
|
||||||
testFormat: 2.13/linux/{0}
|
|
||||||
targets:
|
|
||||||
- name: Fedora 35
|
|
||||||
test: fedora35
|
|
||||||
- name: openSUSE 15 py2
|
|
||||||
test: opensuse15py2
|
|
||||||
- name: Alpine 3
|
|
||||||
test: alpine3
|
|
||||||
groups:
|
|
||||||
- 1
|
|
||||||
- 2
|
|
||||||
- 3
|
|
||||||
- stage: Docker_2_12
|
|
||||||
displayName: Docker 2.12
|
|
||||||
dependsOn: []
|
|
||||||
jobs:
|
|
||||||
- template: templates/matrix.yml
|
|
||||||
parameters:
|
|
||||||
testFormat: 2.12/linux/{0}
|
|
||||||
targets:
|
|
||||||
- name: CentOS 6
|
|
||||||
test: centos6
|
|
||||||
- name: Fedora 34
|
|
||||||
test: fedora34
|
|
||||||
- name: Ubuntu 20.04
|
|
||||||
test: ubuntu2004
|
|
||||||
groups:
|
groups:
|
||||||
- 1
|
- 1
|
||||||
- 2
|
- 2
|
||||||
@@ -389,10 +292,14 @@ stages:
|
|||||||
parameters:
|
parameters:
|
||||||
testFormat: 2.11/linux/{0}
|
testFormat: 2.11/linux/{0}
|
||||||
targets:
|
targets:
|
||||||
|
- name: CentOS 8
|
||||||
|
test: centos8
|
||||||
- name: Fedora 33
|
- name: Fedora 33
|
||||||
test: fedora33
|
test: fedora33
|
||||||
- name: Alpine 3
|
- name: openSUSE 15 py3
|
||||||
test: alpine3
|
test: opensuse15
|
||||||
|
- name: Ubuntu 20.04
|
||||||
|
test: ubuntu2004
|
||||||
groups:
|
groups:
|
||||||
- 2
|
- 2
|
||||||
- 3
|
- 3
|
||||||
@@ -404,8 +311,12 @@ stages:
|
|||||||
parameters:
|
parameters:
|
||||||
testFormat: 2.10/linux/{0}
|
testFormat: 2.10/linux/{0}
|
||||||
targets:
|
targets:
|
||||||
|
- name: CentOS 8
|
||||||
|
test: centos8
|
||||||
- name: Fedora 32
|
- name: Fedora 32
|
||||||
test: fedora32
|
test: fedora32
|
||||||
|
- name: openSUSE 15 py3
|
||||||
|
test: opensuse15
|
||||||
- name: Ubuntu 16.04
|
- name: Ubuntu 16.04
|
||||||
test: ubuntu1604
|
test: ubuntu1604
|
||||||
groups:
|
groups:
|
||||||
@@ -419,32 +330,16 @@ stages:
|
|||||||
parameters:
|
parameters:
|
||||||
testFormat: 2.9/linux/{0}
|
testFormat: 2.9/linux/{0}
|
||||||
targets:
|
targets:
|
||||||
|
- name: CentOS 8
|
||||||
|
test: centos8
|
||||||
- name: Fedora 31
|
- name: Fedora 31
|
||||||
test: fedora31
|
test: fedora31
|
||||||
|
- name: openSUSE 15 py3
|
||||||
|
test: opensuse15
|
||||||
groups:
|
groups:
|
||||||
- 2
|
- 2
|
||||||
- 3
|
- 3
|
||||||
|
|
||||||
### Community Docker
|
|
||||||
- stage: Docker_community_devel
|
|
||||||
displayName: Docker (community images) devel
|
|
||||||
dependsOn: []
|
|
||||||
jobs:
|
|
||||||
- template: templates/matrix.yml
|
|
||||||
parameters:
|
|
||||||
testFormat: devel/linux-community/{0}
|
|
||||||
targets:
|
|
||||||
- name: Debian Bullseye
|
|
||||||
test: debian-bullseye/3.9
|
|
||||||
- name: ArchLinux
|
|
||||||
test: archlinux/3.10
|
|
||||||
- name: CentOS Stream 8
|
|
||||||
test: centos-stream8/3.8
|
|
||||||
groups:
|
|
||||||
- 1
|
|
||||||
- 2
|
|
||||||
- 3
|
|
||||||
|
|
||||||
### Cloud
|
### Cloud
|
||||||
- stage: Cloud_devel
|
- stage: Cloud_devel
|
||||||
displayName: Cloud devel
|
displayName: Cloud devel
|
||||||
@@ -454,27 +349,6 @@ stages:
|
|||||||
parameters:
|
parameters:
|
||||||
nameFormat: Python {0}
|
nameFormat: Python {0}
|
||||||
testFormat: devel/cloud/{0}/1
|
testFormat: devel/cloud/{0}/1
|
||||||
targets:
|
|
||||||
- test: 2.7
|
|
||||||
- test: '3.10'
|
|
||||||
- stage: Cloud_2_13
|
|
||||||
displayName: Cloud 2.13
|
|
||||||
dependsOn: []
|
|
||||||
jobs:
|
|
||||||
- template: templates/matrix.yml
|
|
||||||
parameters:
|
|
||||||
nameFormat: Python {0}
|
|
||||||
testFormat: 2.13/cloud/{0}/1
|
|
||||||
targets:
|
|
||||||
- test: 3.9
|
|
||||||
- stage: Cloud_2_12
|
|
||||||
displayName: Cloud 2.12
|
|
||||||
dependsOn: []
|
|
||||||
jobs:
|
|
||||||
- template: templates/matrix.yml
|
|
||||||
parameters:
|
|
||||||
nameFormat: Python {0}
|
|
||||||
testFormat: 2.12/cloud/{0}/1
|
|
||||||
targets:
|
targets:
|
||||||
- test: 3.8
|
- test: 3.8
|
||||||
- stage: Cloud_2_11
|
- stage: Cloud_2_11
|
||||||
@@ -486,6 +360,7 @@ stages:
|
|||||||
nameFormat: Python {0}
|
nameFormat: Python {0}
|
||||||
testFormat: 2.11/cloud/{0}/1
|
testFormat: 2.11/cloud/{0}/1
|
||||||
targets:
|
targets:
|
||||||
|
- test: 2.7
|
||||||
- test: 3.6
|
- test: 3.6
|
||||||
- stage: Cloud_2_10
|
- stage: Cloud_2_10
|
||||||
displayName: Cloud 2.10
|
displayName: Cloud 2.10
|
||||||
@@ -496,7 +371,7 @@ stages:
|
|||||||
nameFormat: Python {0}
|
nameFormat: Python {0}
|
||||||
testFormat: 2.10/cloud/{0}/1
|
testFormat: 2.10/cloud/{0}/1
|
||||||
targets:
|
targets:
|
||||||
- test: 3.5
|
- test: 3.6
|
||||||
- stage: Cloud_2_9
|
- stage: Cloud_2_9
|
||||||
displayName: Cloud 2.9
|
displayName: Cloud 2.9
|
||||||
dependsOn: []
|
dependsOn: []
|
||||||
@@ -506,7 +381,7 @@ stages:
|
|||||||
nameFormat: Python {0}
|
nameFormat: Python {0}
|
||||||
testFormat: 2.9/cloud/{0}/1
|
testFormat: 2.9/cloud/{0}/1
|
||||||
targets:
|
targets:
|
||||||
- test: 2.7
|
- test: 3.6
|
||||||
- stage: Summary
|
- stage: Summary
|
||||||
condition: succeededOrFailed()
|
condition: succeededOrFailed()
|
||||||
dependsOn:
|
dependsOn:
|
||||||
@@ -514,32 +389,21 @@ stages:
|
|||||||
- Sanity_2_9
|
- Sanity_2_9
|
||||||
- Sanity_2_10
|
- Sanity_2_10
|
||||||
- Sanity_2_11
|
- Sanity_2_11
|
||||||
- Sanity_2_12
|
|
||||||
- Sanity_2_13
|
|
||||||
- Units_devel
|
- Units_devel
|
||||||
- Units_2_9
|
- Units_2_9
|
||||||
- Units_2_10
|
- Units_2_10
|
||||||
- Units_2_11
|
- Units_2_11
|
||||||
- Units_2_12
|
|
||||||
- Units_2_13
|
|
||||||
- Remote_devel
|
- Remote_devel
|
||||||
- Remote_2_9
|
- Remote_2_9
|
||||||
- Remote_2_10
|
- Remote_2_10
|
||||||
- Remote_2_11
|
- Remote_2_11
|
||||||
- Remote_2_12
|
|
||||||
- Remote_2_13
|
|
||||||
- Docker_devel
|
- Docker_devel
|
||||||
- Docker_2_9
|
- Docker_2_9
|
||||||
- Docker_2_10
|
- Docker_2_10
|
||||||
- Docker_2_11
|
- Docker_2_11
|
||||||
- Docker_2_12
|
|
||||||
- Docker_2_13
|
|
||||||
- Docker_community_devel
|
|
||||||
- Cloud_devel
|
- Cloud_devel
|
||||||
- Cloud_2_9
|
- Cloud_2_9
|
||||||
- Cloud_2_10
|
- Cloud_2_10
|
||||||
- Cloud_2_11
|
- Cloud_2_11
|
||||||
- Cloud_2_12
|
|
||||||
- Cloud_2_13
|
|
||||||
jobs:
|
jobs:
|
||||||
- template: templates/coverage.yml
|
- template: templates/coverage.yml
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ mkdir "${agent_temp_directory}/coverage/"
|
|||||||
|
|
||||||
options=(--venv --venv-system-site-packages --color -v)
|
options=(--venv --venv-system-site-packages --color -v)
|
||||||
|
|
||||||
ansible-test coverage combine --group-by command --export "${agent_temp_directory}/coverage/" "${options[@]}"
|
ansible-test coverage combine --export "${agent_temp_directory}/coverage/" "${options[@]}"
|
||||||
|
|
||||||
if ansible-test coverage analyze targets generate --help >/dev/null 2>&1; then
|
if ansible-test coverage analyze targets generate --help >/dev/null 2>&1; then
|
||||||
# Only analyze coverage if the installed version of ansible-test supports it.
|
# Only analyze coverage if the installed version of ansible-test supports it.
|
||||||
|
|||||||
@@ -1,101 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
"""
|
|
||||||
Upload code coverage reports to codecov.io.
|
|
||||||
Multiple coverage files from multiple languages are accepted and aggregated after upload.
|
|
||||||
Python coverage, as well as PowerShell and Python stubs can all be uploaded.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import dataclasses
|
|
||||||
import pathlib
|
|
||||||
import shutil
|
|
||||||
import subprocess
|
|
||||||
import tempfile
|
|
||||||
import typing as t
|
|
||||||
import urllib.request
|
|
||||||
|
|
||||||
|
|
||||||
@dataclasses.dataclass(frozen=True)
|
|
||||||
class CoverageFile:
|
|
||||||
name: str
|
|
||||||
path: pathlib.Path
|
|
||||||
flags: t.List[str]
|
|
||||||
|
|
||||||
|
|
||||||
@dataclasses.dataclass(frozen=True)
|
|
||||||
class Args:
|
|
||||||
dry_run: bool
|
|
||||||
path: pathlib.Path
|
|
||||||
|
|
||||||
|
|
||||||
def parse_args() -> Args:
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument('-n', '--dry-run', action='store_true')
|
|
||||||
parser.add_argument('path', type=pathlib.Path)
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
# Store arguments in a typed dataclass
|
|
||||||
fields = dataclasses.fields(Args)
|
|
||||||
kwargs = {field.name: getattr(args, field.name) for field in fields}
|
|
||||||
|
|
||||||
return Args(**kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def process_files(directory: pathlib.Path) -> t.Tuple[CoverageFile, ...]:
|
|
||||||
processed = []
|
|
||||||
for file in directory.joinpath('reports').glob('coverage*.xml'):
|
|
||||||
name = file.stem.replace('coverage=', '')
|
|
||||||
|
|
||||||
# Get flags from name
|
|
||||||
flags = name.replace('-powershell', '').split('=') # Drop '-powershell' suffix
|
|
||||||
flags = [flag if not flag.startswith('stub') else flag.split('-')[0] for flag in flags] # Remove "-01" from stub files
|
|
||||||
|
|
||||||
processed.append(CoverageFile(name, file, flags))
|
|
||||||
|
|
||||||
return tuple(processed)
|
|
||||||
|
|
||||||
|
|
||||||
def upload_files(codecov_bin: pathlib.Path, files: t.Tuple[CoverageFile, ...], dry_run: bool = False) -> None:
|
|
||||||
for file in files:
|
|
||||||
cmd = [
|
|
||||||
str(codecov_bin),
|
|
||||||
'--name', file.name,
|
|
||||||
'--file', str(file.path),
|
|
||||||
]
|
|
||||||
for flag in file.flags:
|
|
||||||
cmd.extend(['--flags', flag])
|
|
||||||
|
|
||||||
if dry_run:
|
|
||||||
print(f'DRY-RUN: Would run command: {cmd}')
|
|
||||||
continue
|
|
||||||
|
|
||||||
subprocess.run(cmd, check=True)
|
|
||||||
|
|
||||||
|
|
||||||
def download_file(url: str, dest: pathlib.Path, flags: int, dry_run: bool = False) -> None:
|
|
||||||
if dry_run:
|
|
||||||
print(f'DRY-RUN: Would download {url} to {dest} and set mode to {flags:o}')
|
|
||||||
return
|
|
||||||
|
|
||||||
with urllib.request.urlopen(url) as resp:
|
|
||||||
with dest.open('w+b') as f:
|
|
||||||
# Read data in chunks rather than all at once
|
|
||||||
shutil.copyfileobj(resp, f, 64 * 1024)
|
|
||||||
|
|
||||||
dest.chmod(flags)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
args = parse_args()
|
|
||||||
url = 'https://ansible-ci-files.s3.amazonaws.com/codecov/linux/codecov'
|
|
||||||
with tempfile.TemporaryDirectory(prefix='codecov-') as tmpdir:
|
|
||||||
codecov_bin = pathlib.Path(tmpdir) / 'codecov'
|
|
||||||
download_file(url, codecov_bin, 0o755, args.dry_run)
|
|
||||||
|
|
||||||
files = process_files(args.path)
|
|
||||||
upload_files(codecov_bin, files, args.dry_run)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
||||||
27
.azure-pipelines/scripts/publish-codecov.sh
Executable file
27
.azure-pipelines/scripts/publish-codecov.sh
Executable file
@@ -0,0 +1,27 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Upload code coverage reports to codecov.io.
|
||||||
|
# Multiple coverage files from multiple languages are accepted and aggregated after upload.
|
||||||
|
# Python coverage, as well as PowerShell and Python stubs can all be uploaded.
|
||||||
|
|
||||||
|
set -o pipefail -eu
|
||||||
|
|
||||||
|
output_path="$1"
|
||||||
|
|
||||||
|
curl --silent --show-error https://ansible-ci-files.s3.us-east-1.amazonaws.com/codecov/codecov.sh > codecov.sh
|
||||||
|
|
||||||
|
for file in "${output_path}"/reports/coverage*.xml; do
|
||||||
|
name="${file}"
|
||||||
|
name="${name##*/}" # remove path
|
||||||
|
name="${name##coverage=}" # remove 'coverage=' prefix if present
|
||||||
|
name="${name%.xml}" # remove '.xml' suffix
|
||||||
|
|
||||||
|
bash codecov.sh \
|
||||||
|
-f "${file}" \
|
||||||
|
-n "${name}" \
|
||||||
|
-X coveragepy \
|
||||||
|
-X gcov \
|
||||||
|
-X fix \
|
||||||
|
-X search \
|
||||||
|
-X xcode \
|
||||||
|
|| echo "Failed to upload code coverage report to codecov.io: ${file}"
|
||||||
|
done
|
||||||
@@ -12,4 +12,4 @@ if ! ansible-test --help >/dev/null 2>&1; then
|
|||||||
pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check
|
pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ansible-test coverage xml --group-by command --stub --venv --venv-system-site-packages --color -v
|
ansible-test coverage xml --stub --venv --venv-system-site-packages --color -v
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ jobs:
|
|||||||
summaryFileLocation: "$(outputPath)/reports/$(pipelinesCoverage).xml"
|
summaryFileLocation: "$(outputPath)/reports/$(pipelinesCoverage).xml"
|
||||||
displayName: Publish to Azure Pipelines
|
displayName: Publish to Azure Pipelines
|
||||||
condition: gt(variables.coverageFileCount, 0)
|
condition: gt(variables.coverageFileCount, 0)
|
||||||
- bash: .azure-pipelines/scripts/publish-codecov.py "$(outputPath)"
|
- bash: .azure-pipelines/scripts/publish-codecov.sh "$(outputPath)"
|
||||||
displayName: Publish to codecov.io
|
displayName: Publish to codecov.io
|
||||||
condition: gt(variables.coverageFileCount, 0)
|
condition: gt(variables.coverageFileCount, 0)
|
||||||
continueOnError: true
|
continueOnError: true
|
||||||
|
|||||||
442
.github/BOTMETA.yml
vendored
442
.github/BOTMETA.yml
vendored
@@ -1,82 +1,31 @@
|
|||||||
notifications: true
|
|
||||||
automerge: true
|
automerge: true
|
||||||
files:
|
files:
|
||||||
plugins/:
|
plugins/:
|
||||||
supershipit: quidame
|
supershipit: aminvakil russoz
|
||||||
changelogs/: {}
|
|
||||||
changelogs/fragments/:
|
changelogs/fragments/:
|
||||||
support: community
|
support: community
|
||||||
$actions:
|
$actions:
|
||||||
labels: action
|
labels: action
|
||||||
$actions/system/iptables_state.py:
|
$actions/aireos.py:
|
||||||
maintainers: quidame
|
labels: aireos cisco networking
|
||||||
$actions/system/shutdown.py:
|
$actions/ironware.py:
|
||||||
|
maintainers: paulquack
|
||||||
|
labels: ironware networking
|
||||||
|
$actions/shutdown.py:
|
||||||
maintainers: nitzmahone samdoran aminvakil
|
maintainers: nitzmahone samdoran aminvakil
|
||||||
$becomes/:
|
$becomes/:
|
||||||
labels: become
|
labels: become
|
||||||
$becomes/doas.py:
|
|
||||||
maintainers: $team_ansible_core
|
|
||||||
$becomes/dzdo.py:
|
|
||||||
maintainers: $team_ansible_core
|
|
||||||
$becomes/ksu.py:
|
|
||||||
maintainers: $team_ansible_core
|
|
||||||
$becomes/machinectl.py:
|
|
||||||
maintainers: $team_ansible_core
|
|
||||||
$becomes/pbrun.py:
|
|
||||||
maintainers: $team_ansible_core
|
|
||||||
$becomes/pfexec.py:
|
|
||||||
maintainers: $team_ansible_core
|
|
||||||
$becomes/pmrun.py:
|
|
||||||
maintainers: $team_ansible_core
|
|
||||||
$becomes/sesu.py:
|
|
||||||
maintainers: nekonyuu
|
|
||||||
$becomes/sudosu.py:
|
|
||||||
maintainers: dagwieers
|
|
||||||
$caches/:
|
|
||||||
labels: cache
|
|
||||||
$caches/memcached.py: {}
|
|
||||||
$caches/pickle.py:
|
|
||||||
maintainers: bcoca
|
|
||||||
$caches/redis.py: {}
|
|
||||||
$caches/yaml.py:
|
|
||||||
maintainers: bcoca
|
|
||||||
$callbacks/:
|
$callbacks/:
|
||||||
labels: callbacks
|
labels: callbacks
|
||||||
$callbacks/cgroup_memory_recap.py: {}
|
|
||||||
$callbacks/context_demo.py: {}
|
|
||||||
$callbacks/counter_enabled.py: {}
|
|
||||||
$callbacks/dense.py:
|
|
||||||
maintainers: dagwieers
|
|
||||||
$callbacks/diy.py:
|
|
||||||
maintainers: theque5t
|
|
||||||
$callbacks/elastic.py:
|
|
||||||
maintainers: v1v
|
|
||||||
keywords: apm observability
|
|
||||||
$callbacks/hipchat.py: {}
|
|
||||||
$callbacks/jabber.py: {}
|
|
||||||
$callbacks/loganalytics.py:
|
$callbacks/loganalytics.py:
|
||||||
maintainers: zhcli
|
maintainers: zhcli
|
||||||
$callbacks/logdna.py: {}
|
|
||||||
$callbacks/logentries.py: {}
|
|
||||||
$callbacks/log_plays.py: {}
|
|
||||||
$callbacks/logstash.py:
|
$callbacks/logstash.py:
|
||||||
maintainers: ujenmr
|
maintainers: ujenmr
|
||||||
$callbacks/mail.py:
|
|
||||||
maintainers: dagwieers
|
|
||||||
$callbacks/nrdp.py:
|
|
||||||
maintainers: rverchere
|
|
||||||
$callbacks/null.py: {}
|
|
||||||
$callbacks/opentelemetry.py:
|
|
||||||
maintainers: v1v
|
|
||||||
keywords: opentelemetry observability
|
|
||||||
$callbacks/say.py:
|
$callbacks/say.py:
|
||||||
notify: chris-short
|
notify: chris-short
|
||||||
maintainers: $team_macos
|
maintainers: $team_macos
|
||||||
labels: macos say
|
labels: macos say
|
||||||
keywords: brew cask darwin homebrew macosx macports osx
|
keywords: brew cask darwin homebrew macosx macports osx
|
||||||
$callbacks/selective.py: {}
|
|
||||||
$callbacks/slack.py: {}
|
|
||||||
$callbacks/splunk.py: {}
|
|
||||||
$callbacks/sumologic.py:
|
$callbacks/sumologic.py:
|
||||||
maintainers: ryancurrah
|
maintainers: ryancurrah
|
||||||
labels: sumologic
|
labels: sumologic
|
||||||
@@ -85,26 +34,16 @@ files:
|
|||||||
$callbacks/unixy.py:
|
$callbacks/unixy.py:
|
||||||
maintainers: akatch
|
maintainers: akatch
|
||||||
labels: unixy
|
labels: unixy
|
||||||
$callbacks/yaml.py: {}
|
|
||||||
$connections/:
|
$connections/:
|
||||||
labels: connections
|
labels: connections
|
||||||
$connections/chroot.py: {}
|
$connections/kubectl.py:
|
||||||
$connections/funcd.py:
|
maintainers: chouseknecht fabianvf flaper87 maxamillion
|
||||||
maintainers: mscherer
|
labels: k8s kubectl
|
||||||
$connections/iocage.py: {}
|
|
||||||
$connections/jail.py:
|
|
||||||
maintainers: $team_ansible_core
|
|
||||||
$connections/lxc.py: {}
|
|
||||||
$connections/lxd.py:
|
$connections/lxd.py:
|
||||||
maintainers: mattclay
|
maintainers: mattclay
|
||||||
labels: lxd
|
labels: lxd
|
||||||
$connections/qubes.py:
|
|
||||||
maintainers: kushaldas
|
|
||||||
$connections/saltstack.py:
|
$connections/saltstack.py:
|
||||||
maintainers: mscherer
|
|
||||||
labels: saltstack
|
labels: saltstack
|
||||||
$connections/zone.py:
|
|
||||||
maintainers: $team_ansible_core
|
|
||||||
$doc_fragments/:
|
$doc_fragments/:
|
||||||
labels: docs_fragments
|
labels: docs_fragments
|
||||||
$doc_fragments/hpe3par.py:
|
$doc_fragments/hpe3par.py:
|
||||||
@@ -118,120 +57,69 @@ files:
|
|||||||
$doc_fragments/xenserver.py:
|
$doc_fragments/xenserver.py:
|
||||||
maintainers: bvitnik
|
maintainers: bvitnik
|
||||||
labels: xenserver
|
labels: xenserver
|
||||||
$filters/counter.py:
|
|
||||||
maintainers: keilr
|
|
||||||
$filters/dict.py:
|
$filters/dict.py:
|
||||||
maintainers: felixfontein
|
maintainers: felixfontein
|
||||||
$filters/dict_kv.py:
|
$filters/dict_kv.py:
|
||||||
maintainers: giner
|
maintainers: giner
|
||||||
$filters/from_csv.py:
|
$filters/from_csv.py:
|
||||||
maintainers: Ajpantuso
|
maintainers: Ajpantuso
|
||||||
$filters/groupby:
|
|
||||||
maintainers: felixfontein
|
|
||||||
$filters/hashids:
|
$filters/hashids:
|
||||||
maintainers: Ajpantuso
|
maintainers: Ajpantuso
|
||||||
$filters/jc.py:
|
$filters/jc.py:
|
||||||
maintainers: kellyjonbrazil
|
maintainers: kellyjonbrazil
|
||||||
$filters/json_query.py: {}
|
|
||||||
$filters/list.py:
|
$filters/list.py:
|
||||||
maintainers: vbotka
|
maintainers: vbotka
|
||||||
$filters/path_join_shim.py:
|
$filters/path_join_shim.py:
|
||||||
maintainers: felixfontein
|
maintainers: felixfontein
|
||||||
$filters/random_mac.py: {}
|
|
||||||
$filters/time.py:
|
$filters/time.py:
|
||||||
maintainers: resmo
|
maintainers: resmo
|
||||||
$filters/unicode_normalize.py:
|
|
||||||
maintainers: Ajpantuso
|
|
||||||
$filters/version_sort.py:
|
$filters/version_sort.py:
|
||||||
maintainers: ericzolf
|
maintainers: ericzolf
|
||||||
|
$httpapis/:
|
||||||
|
maintainers: $team_networking
|
||||||
|
labels: networking
|
||||||
|
$httpapis/ftd.py:
|
||||||
|
maintainers: $team_networking annikulin
|
||||||
|
labels: cisco ftd networking
|
||||||
|
keywords: firepower ftd
|
||||||
$inventories/:
|
$inventories/:
|
||||||
labels: inventories
|
labels: inventories
|
||||||
$inventories/cobbler.py:
|
|
||||||
maintainers: opoplawski
|
|
||||||
$inventories/gitlab_runners.py:
|
|
||||||
maintainers: morph027
|
|
||||||
$inventories/linode.py:
|
$inventories/linode.py:
|
||||||
maintainers: $team_linode
|
maintainers: $team_linode
|
||||||
labels: cloud linode
|
labels: cloud linode
|
||||||
keywords: linode dynamic inventory script
|
keywords: linode dynamic inventory script
|
||||||
$inventories/lxd.py:
|
$inventories/lxd.py:
|
||||||
maintainers: conloos
|
maintainers: conloos
|
||||||
$inventories/nmap.py: {}
|
|
||||||
$inventories/online.py:
|
|
||||||
maintainers: remyleone
|
|
||||||
$inventories/opennebula.py:
|
|
||||||
maintainers: feldsam
|
|
||||||
labels: cloud opennebula
|
|
||||||
keywords: opennebula dynamic inventory script
|
|
||||||
$inventories/proxmox.py:
|
$inventories/proxmox.py:
|
||||||
maintainers: $team_virt ilijamt
|
maintainers: $team_virt ilijamt
|
||||||
$inventories/xen_orchestra.py:
|
|
||||||
maintainers: ddelnano shinuza
|
|
||||||
$inventories/icinga2.py:
|
|
||||||
maintainers: BongoEADGC6
|
|
||||||
$inventories/scaleway.py:
|
$inventories/scaleway.py:
|
||||||
maintainers: $team_scaleway
|
maintainers: $team_scaleway
|
||||||
labels: cloud scaleway
|
labels: cloud scaleway
|
||||||
$inventories/stackpath_compute.py:
|
|
||||||
maintainers: shayrybak
|
|
||||||
$inventories/virtualbox.py: {}
|
|
||||||
$lookups/:
|
$lookups/:
|
||||||
labels: lookups
|
labels: lookups
|
||||||
$lookups/cartesian.py: {}
|
|
||||||
$lookups/chef_databag.py: {}
|
|
||||||
$lookups/collection_version.py:
|
|
||||||
maintainers: felixfontein
|
|
||||||
$lookups/consul_kv.py: {}
|
|
||||||
$lookups/credstash.py: {}
|
|
||||||
$lookups/cyberarkpassword.py:
|
|
||||||
notify: cyberark-bizdev
|
|
||||||
labels: cyberarkpassword
|
|
||||||
$lookups/dependent.py:
|
|
||||||
maintainers: felixfontein
|
|
||||||
$lookups/dig.py:
|
|
||||||
maintainers: jpmens
|
|
||||||
labels: dig
|
|
||||||
$lookups/dnstxt.py:
|
|
||||||
maintainers: jpmens
|
|
||||||
$lookups/dsv.py:
|
|
||||||
maintainers: amigus endlesstrax
|
|
||||||
$lookups/etcd3.py:
|
|
||||||
maintainers: eric-belhomme
|
|
||||||
$lookups/etcd.py:
|
|
||||||
maintainers: jpmens
|
|
||||||
$lookups/filetree.py:
|
|
||||||
maintainers: dagwieers
|
|
||||||
$lookups/flattened.py: {}
|
|
||||||
$lookups/hiera.py:
|
|
||||||
maintainers: jparrill
|
|
||||||
$lookups/keyring.py: {}
|
|
||||||
$lookups/lastpass.py: {}
|
|
||||||
$lookups/lmdb_kv.py:
|
|
||||||
maintainers: jpmens
|
|
||||||
$lookups/manifold.py:
|
|
||||||
maintainers: galanoff
|
|
||||||
labels: manifold
|
|
||||||
$lookups/onepass:
|
$lookups/onepass:
|
||||||
maintainers: samdoran
|
maintainers: samdoran
|
||||||
labels: onepassword
|
labels: onepassword
|
||||||
$lookups/onepassword.py:
|
$lookups/conjur_variable.py:
|
||||||
maintainers: azenk scottsb
|
notify: cyberark-bizdev
|
||||||
$lookups/onepassword_raw.py:
|
maintainers: $team_cyberark_conjur
|
||||||
maintainers: azenk scottsb
|
labels: conjur_variable
|
||||||
$lookups/passwordstore.py: {}
|
$lookups/cyberarkpassword.py:
|
||||||
$lookups/random_pet.py:
|
notify: cyberark-bizdev
|
||||||
maintainers: Akasurde
|
labels: cyberarkpassword
|
||||||
$lookups/random_string.py:
|
$lookups/dig.py:
|
||||||
maintainers: Akasurde
|
maintainers: jpmens
|
||||||
$lookups/random_words.py:
|
labels: dig
|
||||||
maintainers: konstruktoid
|
|
||||||
$lookups/redis.py:
|
|
||||||
maintainers: $team_ansible_core jpmens
|
|
||||||
$lookups/revbitspss.py:
|
|
||||||
maintainers: RevBits
|
|
||||||
$lookups/shelvefile.py: {}
|
|
||||||
$lookups/tss.py:
|
$lookups/tss.py:
|
||||||
maintainers: amigus endlesstrax
|
maintainers: amigus
|
||||||
|
$lookups/dsv.py:
|
||||||
|
maintainers: amigus
|
||||||
|
$lookups/manifold.py:
|
||||||
|
maintainers: galanoff
|
||||||
|
labels: manifold
|
||||||
|
$lookups/nios:
|
||||||
|
maintainers: $team_networking sganesh-infoblox
|
||||||
|
labels: infoblox networking
|
||||||
$module_utils/:
|
$module_utils/:
|
||||||
labels: module_utils
|
labels: module_utils
|
||||||
$module_utils/gitlab.py:
|
$module_utils/gitlab.py:
|
||||||
@@ -254,12 +142,12 @@ files:
|
|||||||
$module_utils/memset.py:
|
$module_utils/memset.py:
|
||||||
maintainers: glitchcrab
|
maintainers: glitchcrab
|
||||||
labels: cloud memset
|
labels: cloud memset
|
||||||
$module_utils/mh/:
|
|
||||||
maintainers: russoz
|
|
||||||
labels: module_helper
|
|
||||||
$module_utils/module_helper.py:
|
$module_utils/module_helper.py:
|
||||||
maintainers: russoz
|
maintainers: russoz
|
||||||
labels: module_helper
|
labels: module_helper
|
||||||
|
$module_utils/net_tools/nios/api.py:
|
||||||
|
maintainers: $team_networking sganesh-infoblox
|
||||||
|
labels: infoblox networking
|
||||||
$module_utils/oracle/oci_utils.py:
|
$module_utils/oracle/oci_utils.py:
|
||||||
maintainers: $team_oracle
|
maintainers: $team_oracle
|
||||||
labels: cloud
|
labels: cloud
|
||||||
@@ -269,13 +157,11 @@ files:
|
|||||||
$module_utils/redfish_utils.py:
|
$module_utils/redfish_utils.py:
|
||||||
maintainers: $team_redfish
|
maintainers: $team_redfish
|
||||||
labels: redfish_utils
|
labels: redfish_utils
|
||||||
$module_utils/remote_management/lxca/common.py:
|
$module_utils/remote_management/lxca/common.py: navalkp prabhosa
|
||||||
maintainers: navalkp prabhosa
|
|
||||||
$module_utils/scaleway.py:
|
$module_utils/scaleway.py:
|
||||||
maintainers: $team_scaleway
|
maintainers: $team_scaleway
|
||||||
labels: cloud scaleway
|
labels: cloud scaleway
|
||||||
$module_utils/storage/hpe3par/hpe3par.py:
|
$module_utils/storage/hpe3par/hpe3par.py: farhan7500 gautamphegde
|
||||||
maintainers: farhan7500 gautamphegde
|
|
||||||
$module_utils/utm_utils.py:
|
$module_utils/utm_utils.py:
|
||||||
maintainers: $team_e_spirit
|
maintainers: $team_e_spirit
|
||||||
labels: utm_utils
|
labels: utm_utils
|
||||||
@@ -306,31 +192,33 @@ files:
|
|||||||
maintainers: zbal
|
maintainers: zbal
|
||||||
$modules/cloud/lxc/lxc_container.py:
|
$modules/cloud/lxc/lxc_container.py:
|
||||||
maintainers: cloudnull
|
maintainers: cloudnull
|
||||||
|
$modules/cloud/lxc/lxc_profile.py:
|
||||||
|
maintainers: conloos
|
||||||
$modules/cloud/lxd/:
|
$modules/cloud/lxd/:
|
||||||
ignore: hnakamur
|
ignore: hnakamur
|
||||||
$modules/cloud/lxd/lxd_profile.py:
|
|
||||||
maintainers: conloos
|
|
||||||
$modules/cloud/memset/:
|
$modules/cloud/memset/:
|
||||||
maintainers: glitchcrab
|
maintainers: glitchcrab
|
||||||
$modules/cloud/misc/cloud_init_data_facts.py:
|
$modules/cloud/misc/cloud_init_data_facts.py:
|
||||||
maintainers: resmo
|
maintainers: resmo
|
||||||
$modules/cloud/misc/proxmox:
|
$modules/cloud/misc/proxmox.py:
|
||||||
|
maintainers: $team_virt UnderGreen
|
||||||
|
labels: proxmox virt
|
||||||
|
ignore: skvidal
|
||||||
|
keywords: kvm libvirt proxmox qemu
|
||||||
|
$modules/cloud/misc/proxmox_kvm.py:
|
||||||
|
maintainers: $team_virt helldorado
|
||||||
|
labels: proxmox_kvm virt
|
||||||
|
ignore: skvidal
|
||||||
|
keywords: kvm libvirt proxmox qemu
|
||||||
|
$modules/cloud/misc/proxmox_snap.py:
|
||||||
maintainers: $team_virt
|
maintainers: $team_virt
|
||||||
labels: proxmox virt
|
labels: proxmox virt
|
||||||
keywords: kvm libvirt proxmox qemu
|
keywords: kvm libvirt proxmox qemu
|
||||||
$modules/cloud/misc/proxmox.py:
|
|
||||||
maintainers: UnderGreen
|
|
||||||
ignore: skvidal
|
|
||||||
$modules/cloud/misc/proxmox_kvm.py:
|
|
||||||
maintainers: helldorado
|
|
||||||
ignore: skvidal
|
|
||||||
$modules/cloud/misc/proxmox_nic.py:
|
|
||||||
maintainers: Kogelvis
|
|
||||||
$modules/cloud/misc/proxmox_tasks_info:
|
|
||||||
maintainers: paginabianca
|
|
||||||
$modules/cloud/misc/proxmox_template.py:
|
$modules/cloud/misc/proxmox_template.py:
|
||||||
maintainers: UnderGreen
|
maintainers: $team_virt UnderGreen
|
||||||
|
labels: proxmox_template virt
|
||||||
ignore: skvidal
|
ignore: skvidal
|
||||||
|
keywords: kvm libvirt proxmox qemu
|
||||||
$modules/cloud/misc/rhevm.py:
|
$modules/cloud/misc/rhevm.py:
|
||||||
maintainers: $team_virt TimothyVandenbrande
|
maintainers: $team_virt TimothyVandenbrande
|
||||||
labels: rhevm virt
|
labels: rhevm virt
|
||||||
@@ -347,7 +235,7 @@ files:
|
|||||||
$modules/cloud/oneandone/:
|
$modules/cloud/oneandone/:
|
||||||
maintainers: aajdinov edevenport
|
maintainers: aajdinov edevenport
|
||||||
$modules/cloud/online/:
|
$modules/cloud/online/:
|
||||||
maintainers: remyleone
|
maintainers: sieben
|
||||||
$modules/cloud/opennebula/:
|
$modules/cloud/opennebula/:
|
||||||
maintainers: $team_opennebula
|
maintainers: $team_opennebula
|
||||||
$modules/cloud/opennebula/one_host.py:
|
$modules/cloud/opennebula/one_host.py:
|
||||||
@@ -372,40 +260,16 @@ files:
|
|||||||
maintainers: omgjlk sivel
|
maintainers: omgjlk sivel
|
||||||
$modules/cloud/rackspace/:
|
$modules/cloud/rackspace/:
|
||||||
ignore: ryansb sivel
|
ignore: ryansb sivel
|
||||||
$modules/cloud/rackspace/rax_cbs.py:
|
|
||||||
maintainers: claco
|
|
||||||
$modules/cloud/rackspace/rax_cbs_attachments.py:
|
|
||||||
maintainers: claco
|
|
||||||
$modules/cloud/rackspace/rax_cdb.py:
|
|
||||||
maintainers: jails
|
|
||||||
$modules/cloud/rackspace/rax_cdb_user.py:
|
|
||||||
maintainers: jails
|
|
||||||
$modules/cloud/rackspace/rax_cdb_database.py:
|
|
||||||
maintainers: jails
|
|
||||||
$modules/cloud/rackspace/rax_clb.py:
|
$modules/cloud/rackspace/rax_clb.py:
|
||||||
maintainers: claco
|
maintainers: claco
|
||||||
$modules/cloud/rackspace/rax_clb_nodes.py:
|
$modules/cloud/rackspace/rax_clb_nodes.py:
|
||||||
maintainers: neuroid
|
maintainers: neuroid
|
||||||
$modules/cloud/rackspace/rax_clb_ssl.py:
|
$modules/cloud/rackspace/rax_clb_ssl.py:
|
||||||
maintainers: smashwilson
|
maintainers: smashwilson
|
||||||
$modules/cloud/rackspace/rax_files.py:
|
|
||||||
maintainers: angstwad
|
|
||||||
$modules/cloud/rackspace/rax_files_objects.py:
|
|
||||||
maintainers: angstwad
|
|
||||||
$modules/cloud/rackspace/rax_identity.py:
|
$modules/cloud/rackspace/rax_identity.py:
|
||||||
maintainers: claco
|
maintainers: claco
|
||||||
$modules/cloud/rackspace/rax_network.py:
|
$modules/cloud/rackspace/rax_network.py:
|
||||||
maintainers: claco omgjlk
|
maintainers: claco omgjlk
|
||||||
$modules/cloud/rackspace/rax_mon_alarm.py:
|
|
||||||
maintainers: smashwilson
|
|
||||||
$modules/cloud/rackspace/rax_mon_check.py:
|
|
||||||
maintainers: smashwilson
|
|
||||||
$modules/cloud/rackspace/rax_mon_entity.py:
|
|
||||||
maintainers: smashwilson
|
|
||||||
$modules/cloud/rackspace/rax_mon_notification.py:
|
|
||||||
maintainers: smashwilson
|
|
||||||
$modules/cloud/rackspace/rax_mon_notification_plan.py:
|
|
||||||
maintainers: smashwilson
|
|
||||||
$modules/cloud/rackspace/rax_queue.py:
|
$modules/cloud/rackspace/rax_queue.py:
|
||||||
maintainers: claco
|
maintainers: claco
|
||||||
$modules/cloud/scaleway/:
|
$modules/cloud/scaleway/:
|
||||||
@@ -417,19 +281,13 @@ files:
|
|||||||
$modules/cloud/scaleway/scaleway_ip_info.py:
|
$modules/cloud/scaleway/scaleway_ip_info.py:
|
||||||
maintainers: Spredzy
|
maintainers: Spredzy
|
||||||
$modules/cloud/scaleway/scaleway_organization_info.py:
|
$modules/cloud/scaleway/scaleway_organization_info.py:
|
||||||
maintainers: Spredzy
|
maintainers: sieben
|
||||||
$modules/cloud/scaleway/scaleway_private_network.py:
|
|
||||||
maintainers: pastral
|
|
||||||
$modules/cloud/scaleway/scaleway_security_group.py:
|
$modules/cloud/scaleway/scaleway_security_group.py:
|
||||||
maintainers: DenBeke
|
maintainers: DenBeke
|
||||||
$modules/cloud/scaleway/scaleway_security_group_info.py:
|
$modules/cloud/scaleway/scaleway_security_group_info.py:
|
||||||
maintainers: Spredzy
|
maintainers: sieben
|
||||||
$modules/cloud/scaleway/scaleway_security_group_rule.py:
|
$modules/cloud/scaleway/scaleway_security_group_rule.py:
|
||||||
maintainers: DenBeke
|
maintainers: DenBeke
|
||||||
$modules/cloud/scaleway/scaleway_server_info.py:
|
|
||||||
maintainers: Spredzy
|
|
||||||
$modules/cloud/scaleway/scaleway_snapshot_info.py:
|
|
||||||
maintainers: Spredzy
|
|
||||||
$modules/cloud/scaleway/scaleway_volume.py:
|
$modules/cloud/scaleway/scaleway_volume.py:
|
||||||
labels: scaleway_volume
|
labels: scaleway_volume
|
||||||
ignore: hekonsek
|
ignore: hekonsek
|
||||||
@@ -481,24 +339,11 @@ files:
|
|||||||
maintainers: john-westcott-iv
|
maintainers: john-westcott-iv
|
||||||
$modules/database/misc/redis.py:
|
$modules/database/misc/redis.py:
|
||||||
maintainers: slok
|
maintainers: slok
|
||||||
$modules/database/misc/redis_info.py:
|
|
||||||
maintainers: levonet
|
|
||||||
$modules/database/misc/redis_data_info.py:
|
|
||||||
maintainers: paginabianca
|
|
||||||
$modules/database/misc/redis_data.py:
|
|
||||||
maintainers: paginabianca
|
|
||||||
$modules/database/misc/redis_data_incr.py:
|
|
||||||
maintainers: paginabianca
|
|
||||||
$modules/database/misc/riak.py:
|
$modules/database/misc/riak.py:
|
||||||
maintainers: drewkerrigan jsmartin
|
maintainers: drewkerrigan jsmartin
|
||||||
$modules/database/mssql/mssql_db.py:
|
$modules/database/mssql/mssql_db.py:
|
||||||
maintainers: vedit Jmainguy kenichi-ogawa-1988
|
maintainers: vedit Jmainguy kenichi-ogawa-1988
|
||||||
labels: mssql_db
|
labels: mssql_db
|
||||||
$modules/database/mssql/mssql_script.py:
|
|
||||||
maintainers: kbudde
|
|
||||||
labels: mssql_script
|
|
||||||
$modules/database/saphana/hana_query.py:
|
|
||||||
maintainers: rainerleber
|
|
||||||
$modules/database/vertica/:
|
$modules/database/vertica/:
|
||||||
maintainers: dareko
|
maintainers: dareko
|
||||||
$modules/files/archive.py:
|
$modules/files/archive.py:
|
||||||
@@ -507,14 +352,10 @@ files:
|
|||||||
maintainers: quidame
|
maintainers: quidame
|
||||||
$modules/files/ini_file.py:
|
$modules/files/ini_file.py:
|
||||||
maintainers: jpmens noseka1
|
maintainers: jpmens noseka1
|
||||||
$modules/files/iso_create.py:
|
|
||||||
maintainers: Tomorrow9
|
|
||||||
$modules/files/iso_extract.py:
|
$modules/files/iso_extract.py:
|
||||||
maintainers: dagwieers jhoekx ribbons
|
maintainers: dagwieers jhoekx ribbons
|
||||||
$modules/files/read_csv.py:
|
$modules/files/read_csv.py:
|
||||||
maintainers: dagwieers
|
maintainers: dagwieers
|
||||||
$modules/files/sapcar_extract.py:
|
|
||||||
maintainers: RainerLeber
|
|
||||||
$modules/files/xattr.py:
|
$modules/files/xattr.py:
|
||||||
maintainers: bcoca
|
maintainers: bcoca
|
||||||
labels: xattr
|
labels: xattr
|
||||||
@@ -532,30 +373,15 @@ files:
|
|||||||
maintainers: jparrill
|
maintainers: jparrill
|
||||||
$modules/identity/keycloak/:
|
$modules/identity/keycloak/:
|
||||||
maintainers: $team_keycloak
|
maintainers: $team_keycloak
|
||||||
$modules/identity/keycloak/keycloak_authentication.py:
|
|
||||||
maintainers: elfelip Gaetan2907
|
|
||||||
$modules/identity/keycloak/keycloak_clientscope.py:
|
|
||||||
maintainers: Gaetan2907
|
|
||||||
$modules/identity/keycloak/keycloak_client_rolemapping.py:
|
|
||||||
maintainers: Gaetan2907
|
|
||||||
$modules/identity/keycloak/keycloak_group.py:
|
$modules/identity/keycloak/keycloak_group.py:
|
||||||
maintainers: adamgoossens
|
maintainers: adamgoossens
|
||||||
$modules/identity/keycloak/keycloak_identity_provider.py:
|
|
||||||
maintainers: laurpaum
|
|
||||||
$modules/identity/keycloak/keycloak_realm_info.py:
|
|
||||||
maintainers: fynncfchen
|
|
||||||
$modules/identity/keycloak/keycloak_realm.py:
|
$modules/identity/keycloak/keycloak_realm.py:
|
||||||
maintainers: kris2kris
|
maintainers: kris2kris
|
||||||
$modules/identity/keycloak/keycloak_role.py:
|
|
||||||
maintainers: laurpaum
|
|
||||||
$modules/identity/keycloak/keycloak_user_federation.py:
|
|
||||||
maintainers: laurpaum
|
|
||||||
$modules/identity/onepassword_info.py:
|
$modules/identity/onepassword_info.py:
|
||||||
maintainers: Rylon
|
maintainers: Rylon
|
||||||
$modules/identity/opendj/opendj_backendprop.py:
|
$modules/identity/opendj/opendj_backendprop.py:
|
||||||
maintainers: dj-wasabi
|
maintainers: dj-wasabi
|
||||||
$modules/monitoring/airbrake_deployment.py:
|
$modules/monitoring/airbrake_deployment.py:
|
||||||
maintainers: phumpal
|
|
||||||
labels: airbrake_deployment
|
labels: airbrake_deployment
|
||||||
ignore: bpennypacker
|
ignore: bpennypacker
|
||||||
$modules/monitoring/bigpanda.py:
|
$modules/monitoring/bigpanda.py:
|
||||||
@@ -566,8 +392,6 @@ files:
|
|||||||
maintainers: n0ts
|
maintainers: n0ts
|
||||||
labels: datadog_event
|
labels: datadog_event
|
||||||
ignore: arturaz
|
ignore: arturaz
|
||||||
$modules/monitoring/datadog/datadog_downtime.py:
|
|
||||||
maintainers: Datadog
|
|
||||||
$modules/monitoring/datadog/datadog_monitor.py:
|
$modules/monitoring/datadog/datadog_monitor.py:
|
||||||
maintainers: skornehl
|
maintainers: skornehl
|
||||||
$modules/monitoring/honeybadger_deployment.py:
|
$modules/monitoring/honeybadger_deployment.py:
|
||||||
@@ -629,14 +453,12 @@ files:
|
|||||||
labels: cloudflare_dns
|
labels: cloudflare_dns
|
||||||
$modules/net_tools/dnsimple.py:
|
$modules/net_tools/dnsimple.py:
|
||||||
maintainers: drcapulet
|
maintainers: drcapulet
|
||||||
$modules/net_tools/dnsimple_info.py:
|
|
||||||
maintainers: edhilgendorf
|
|
||||||
$modules/net_tools/dnsmadeeasy.py:
|
$modules/net_tools/dnsmadeeasy.py:
|
||||||
maintainers: briceburg
|
maintainers: briceburg
|
||||||
$modules/net_tools/gandi_livedns.py:
|
|
||||||
maintainers: gthiemonge
|
|
||||||
$modules/net_tools/haproxy.py:
|
$modules/net_tools/haproxy.py:
|
||||||
maintainers: ravibhure Normo
|
maintainers: ravibhure Normo
|
||||||
|
$modules/net_tools/:
|
||||||
|
maintainers: nerzhul
|
||||||
$modules/net_tools/infinity/infinity.py:
|
$modules/net_tools/infinity/infinity.py:
|
||||||
maintainers: MeganLiu
|
maintainers: MeganLiu
|
||||||
$modules/net_tools/ip_netns.py:
|
$modules/net_tools/ip_netns.py:
|
||||||
@@ -660,26 +482,37 @@ files:
|
|||||||
ignore: andyhky
|
ignore: andyhky
|
||||||
$modules/net_tools/netcup_dns.py:
|
$modules/net_tools/netcup_dns.py:
|
||||||
maintainers: nbuchwitz
|
maintainers: nbuchwitz
|
||||||
$modules/net_tools/nsupdate.py:
|
|
||||||
maintainers: nerzhul
|
|
||||||
$modules/net_tools/omapi_host.py:
|
$modules/net_tools/omapi_host.py:
|
||||||
maintainers: amasolov nerzhul
|
maintainers: amasolov
|
||||||
$modules/net_tools/pritunl/:
|
$modules/net_tools/nios/:
|
||||||
maintainers: Lowess
|
maintainers: $team_networking
|
||||||
|
labels: infoblox networking
|
||||||
|
$modules/net_tools/nios/nios_fixed_address.py:
|
||||||
|
maintainers: sjaiswal
|
||||||
|
$modules/net_tools/nios/nios_nsgroup.py:
|
||||||
|
maintainers: ebirn sjaiswal
|
||||||
|
$modules/net_tools/nios/nios_ptr_record.py:
|
||||||
|
maintainers: clementtrebuchet
|
||||||
|
$modules/net_tools/nios/nios_srv_record.py:
|
||||||
|
maintainers: brampling
|
||||||
|
$modules/net_tools/nios/nios_txt_record.py:
|
||||||
|
maintainers: coreywan
|
||||||
$modules/net_tools/nmcli.py:
|
$modules/net_tools/nmcli.py:
|
||||||
maintainers: alcamie101
|
maintainers: alcamie101
|
||||||
$modules/net_tools/snmp_facts.py:
|
$modules/net_tools/snmp_facts.py:
|
||||||
maintainers: ogenstad ujwalkomarla
|
maintainers: ogenstad ujwalkomarla
|
||||||
|
$modules/notification/osx_say.py:
|
||||||
|
maintainers: ansible mpdehaan
|
||||||
|
labels: _osx_say
|
||||||
|
deprecated: true
|
||||||
$modules/notification/bearychat.py:
|
$modules/notification/bearychat.py:
|
||||||
maintainers: tonyseek
|
maintainers: tonyseek
|
||||||
$modules/notification/campfire.py:
|
$modules/notification/campfire.py:
|
||||||
maintainers: fabulops
|
maintainers: fabulops
|
||||||
$modules/notification/catapult.py:
|
$modules/notification/catapult.py:
|
||||||
maintainers: Jmainguy
|
maintainers: Jmainguy
|
||||||
$modules/notification/cisco_webex.py:
|
$modules/notification/cisco_spark.py:
|
||||||
maintainers: drew-russell
|
maintainers: drew-russell
|
||||||
$modules/notification/discord.py:
|
|
||||||
maintainers: cwollinger
|
|
||||||
$modules/notification/flowdock.py:
|
$modules/notification/flowdock.py:
|
||||||
maintainers: mcodd
|
maintainers: mcodd
|
||||||
$modules/notification/grove.py:
|
$modules/notification/grove.py:
|
||||||
@@ -707,13 +540,13 @@ files:
|
|||||||
$modules/notification/pushbullet.py:
|
$modules/notification/pushbullet.py:
|
||||||
maintainers: willybarro
|
maintainers: willybarro
|
||||||
$modules/notification/pushover.py:
|
$modules/notification/pushover.py:
|
||||||
maintainers: weaselkeeper wopfel
|
maintainers: weaselkeeper
|
||||||
$modules/notification/rocketchat.py:
|
$modules/notification/rocketchat.py:
|
||||||
maintainers: Deepakkothandan
|
maintainers: Deepakkothandan
|
||||||
labels: rocketchat
|
labels: rocketchat
|
||||||
ignore: ramondelafuente
|
ignore: ramondelafuente
|
||||||
$modules/notification/say.py:
|
$modules/notification/say.py:
|
||||||
maintainers: $team_ansible_core mpdehaan
|
maintainers: ansible mpdehaan
|
||||||
$modules/notification/sendgrid.py:
|
$modules/notification/sendgrid.py:
|
||||||
maintainers: makaimc
|
maintainers: makaimc
|
||||||
$modules/notification/slack.py:
|
$modules/notification/slack.py:
|
||||||
@@ -721,19 +554,15 @@ files:
|
|||||||
$modules/notification/syslogger.py:
|
$modules/notification/syslogger.py:
|
||||||
maintainers: garbled1
|
maintainers: garbled1
|
||||||
$modules/notification/telegram.py:
|
$modules/notification/telegram.py:
|
||||||
maintainers: tyouxa loms lomserman
|
maintainers: tyouxa loms
|
||||||
$modules/notification/twilio.py:
|
$modules/notification/twilio.py:
|
||||||
maintainers: makaimc
|
maintainers: makaimc
|
||||||
$modules/notification/typetalk.py:
|
$modules/notification/typetalk.py:
|
||||||
maintainers: tksmd
|
maintainers: tksmd
|
||||||
$modules/packaging/language/ansible_galaxy_install.py:
|
|
||||||
maintainers: russoz
|
|
||||||
$modules/packaging/language/bower.py:
|
$modules/packaging/language/bower.py:
|
||||||
maintainers: mwarkentin
|
maintainers: mwarkentin
|
||||||
$modules/packaging/language/bundler.py:
|
$modules/packaging/language/bundler.py:
|
||||||
maintainers: thoiberg
|
maintainers: thoiberg
|
||||||
$modules/packaging/language/cargo.py:
|
|
||||||
maintainers: radek-sprta
|
|
||||||
$modules/packaging/language/composer.py:
|
$modules/packaging/language/composer.py:
|
||||||
maintainers: dmtrs
|
maintainers: dmtrs
|
||||||
ignore: resmo
|
ignore: resmo
|
||||||
@@ -742,7 +571,7 @@ files:
|
|||||||
$modules/packaging/language/easy_install.py:
|
$modules/packaging/language/easy_install.py:
|
||||||
maintainers: mattupstate
|
maintainers: mattupstate
|
||||||
$modules/packaging/language/gem.py:
|
$modules/packaging/language/gem.py:
|
||||||
maintainers: $team_ansible_core johanwiren
|
maintainers: ansible johanwiren
|
||||||
labels: gem
|
labels: gem
|
||||||
$modules/packaging/language/maven_artifact.py:
|
$modules/packaging/language/maven_artifact.py:
|
||||||
maintainers: tumbl3w33d turb
|
maintainers: tumbl3w33d turb
|
||||||
@@ -757,22 +586,16 @@ files:
|
|||||||
ignore: jle64
|
ignore: jle64
|
||||||
$modules/packaging/language/pip_package_info.py:
|
$modules/packaging/language/pip_package_info.py:
|
||||||
maintainers: bcoca matburt maxamillion
|
maintainers: bcoca matburt maxamillion
|
||||||
$modules/packaging/language/pipx.py:
|
|
||||||
maintainers: russoz
|
|
||||||
$modules/packaging/language/yarn.py:
|
$modules/packaging/language/yarn.py:
|
||||||
maintainers: chrishoffman verkaufer
|
maintainers: chrishoffman verkaufer
|
||||||
$modules/packaging/os/apk.py:
|
$modules/packaging/os/apk.py:
|
||||||
maintainers: tdtrask
|
maintainers: tdtrask
|
||||||
labels: apk
|
labels: apk
|
||||||
ignore: kbrebanov
|
ignore: kbrebanov
|
||||||
$modules/packaging/os/apt_repo.py:
|
|
||||||
maintainers: obirvalger
|
|
||||||
$modules/packaging/os/apt_rpm.py:
|
$modules/packaging/os/apt_rpm.py:
|
||||||
maintainers: evgkrsk
|
maintainers: evgkrsk
|
||||||
$modules/packaging/os/copr.py:
|
$modules/packaging/os/copr.py:
|
||||||
maintainers: schlupov
|
maintainers: schlupov
|
||||||
$modules/packaging/os/dnf_versionlock.py:
|
|
||||||
maintainers: moreda
|
|
||||||
$modules/packaging/os/flatpak.py:
|
$modules/packaging/os/flatpak.py:
|
||||||
maintainers: $team_flatpak
|
maintainers: $team_flatpak
|
||||||
$modules/packaging/os/flatpak_remote.py:
|
$modules/packaging/os/flatpak_remote.py:
|
||||||
@@ -821,12 +644,9 @@ files:
|
|||||||
$modules/packaging/os/opkg.py:
|
$modules/packaging/os/opkg.py:
|
||||||
maintainers: skinp
|
maintainers: skinp
|
||||||
$modules/packaging/os/pacman.py:
|
$modules/packaging/os/pacman.py:
|
||||||
maintainers: elasticdog indrajitr tchernomax jraby
|
maintainers: elasticdog indrajitr tchernomax
|
||||||
labels: pacman
|
labels: pacman
|
||||||
ignore: elasticdog
|
ignore: elasticdog
|
||||||
$modules/packaging/os/pacman_key.py:
|
|
||||||
maintainers: grawlinson
|
|
||||||
labels: pacman
|
|
||||||
$modules/packaging/os/pkgin.py:
|
$modules/packaging/os/pkgin.py:
|
||||||
maintainers: $team_solaris L2G jasperla szinck martinm82
|
maintainers: $team_solaris L2G jasperla szinck martinm82
|
||||||
labels: pkgin solaris
|
labels: pkgin solaris
|
||||||
@@ -869,9 +689,6 @@ files:
|
|||||||
$modules/packaging/os/snap.py:
|
$modules/packaging/os/snap.py:
|
||||||
maintainers: angristan vcarceler
|
maintainers: angristan vcarceler
|
||||||
labels: snap
|
labels: snap
|
||||||
$modules/packaging/os/snap_alias.py:
|
|
||||||
maintainers: russoz
|
|
||||||
labels: snap
|
|
||||||
$modules/packaging/os/sorcery.py:
|
$modules/packaging/os/sorcery.py:
|
||||||
maintainers: vaygr
|
maintainers: vaygr
|
||||||
$modules/packaging/os/svr4pkg.py:
|
$modules/packaging/os/svr4pkg.py:
|
||||||
@@ -895,9 +712,8 @@ files:
|
|||||||
labels: zypper
|
labels: zypper
|
||||||
ignore: dirtyharrycallahan robinro
|
ignore: dirtyharrycallahan robinro
|
||||||
$modules/packaging/os/zypper_repository.py:
|
$modules/packaging/os/zypper_repository.py:
|
||||||
maintainers: $team_suse
|
maintainers: $team_suse matze
|
||||||
labels: zypper
|
labels: zypper
|
||||||
ignore: matze
|
|
||||||
$modules/remote_management/cobbler/:
|
$modules/remote_management/cobbler/:
|
||||||
maintainers: dagwieers
|
maintainers: dagwieers
|
||||||
$modules/remote_management/hpilo/:
|
$modules/remote_management/hpilo/:
|
||||||
@@ -915,10 +731,6 @@ files:
|
|||||||
$modules/remote_management/manageiq/:
|
$modules/remote_management/manageiq/:
|
||||||
labels: manageiq
|
labels: manageiq
|
||||||
maintainers: $team_manageiq
|
maintainers: $team_manageiq
|
||||||
$modules/remote_management/manageiq/manageiq_alert_profiles.py:
|
|
||||||
maintainers: elad661
|
|
||||||
$modules/remote_management/manageiq/manageiq_alerts.py:
|
|
||||||
maintainers: elad661
|
|
||||||
$modules/remote_management/manageiq/manageiq_group.py:
|
$modules/remote_management/manageiq/manageiq_group.py:
|
||||||
maintainers: evertmulder
|
maintainers: evertmulder
|
||||||
$modules/remote_management/manageiq/manageiq_tenant.py:
|
$modules/remote_management/manageiq/manageiq_tenant.py:
|
||||||
@@ -967,10 +779,6 @@ files:
|
|||||||
maintainers: markuman
|
maintainers: markuman
|
||||||
$modules/source_control/gitlab/gitlab_runner.py:
|
$modules/source_control/gitlab/gitlab_runner.py:
|
||||||
maintainers: SamyCoenen
|
maintainers: SamyCoenen
|
||||||
$modules/source_control/gitlab/gitlab_user.py:
|
|
||||||
maintainers: LennertMertens stgrace
|
|
||||||
$modules/source_control/gitlab/gitlab_branch.py:
|
|
||||||
maintainers: paytroff
|
|
||||||
$modules/source_control/hg.py:
|
$modules/source_control/hg.py:
|
||||||
maintainers: yeukhon
|
maintainers: yeukhon
|
||||||
$modules/storage/emc/emc_vnx_sg_member.py:
|
$modules/storage/emc/emc_vnx_sg_member.py:
|
||||||
@@ -979,8 +787,13 @@ files:
|
|||||||
maintainers: farhan7500 gautamphegde
|
maintainers: farhan7500 gautamphegde
|
||||||
$modules/storage/ibm/:
|
$modules/storage/ibm/:
|
||||||
maintainers: tzure
|
maintainers: tzure
|
||||||
$modules/storage/pmem/pmem.py:
|
$modules/storage/infinidat/:
|
||||||
maintainers: mizumm
|
maintainers: vmalloc GR360RY
|
||||||
|
$modules/storage/netapp/:
|
||||||
|
maintainers: $team_netapp
|
||||||
|
$modules/storage/purestorage/:
|
||||||
|
maintainers: $team_purestorage
|
||||||
|
labels: pure_storage
|
||||||
$modules/storage/vexata/:
|
$modules/storage/vexata/:
|
||||||
maintainers: vexata
|
maintainers: vexata
|
||||||
$modules/storage/zfs/:
|
$modules/storage/zfs/:
|
||||||
@@ -999,8 +812,6 @@ files:
|
|||||||
maintainers: mulby
|
maintainers: mulby
|
||||||
labels: alternatives
|
labels: alternatives
|
||||||
ignore: DavidWittman
|
ignore: DavidWittman
|
||||||
$modules/system/aix_lvol.py:
|
|
||||||
maintainers: adejoux
|
|
||||||
$modules/system/awall.py:
|
$modules/system/awall.py:
|
||||||
maintainers: tdtrask
|
maintainers: tdtrask
|
||||||
$modules/system/beadm.py:
|
$modules/system/beadm.py:
|
||||||
@@ -1018,7 +829,7 @@ files:
|
|||||||
$modules/system/dpkg_divert.py:
|
$modules/system/dpkg_divert.py:
|
||||||
maintainers: quidame
|
maintainers: quidame
|
||||||
$modules/system/facter.py:
|
$modules/system/facter.py:
|
||||||
maintainers: $team_ansible_core gamethis
|
maintainers: ansible gamethis
|
||||||
labels: facter
|
labels: facter
|
||||||
$modules/system/filesystem.py:
|
$modules/system/filesystem.py:
|
||||||
maintainers: pilou- abulimov quidame
|
maintainers: pilou- abulimov quidame
|
||||||
@@ -1026,19 +837,15 @@ files:
|
|||||||
$modules/system/gconftool2.py:
|
$modules/system/gconftool2.py:
|
||||||
maintainers: Akasurde kevensen
|
maintainers: Akasurde kevensen
|
||||||
labels: gconftool2
|
labels: gconftool2
|
||||||
$modules/system/homectl.py:
|
|
||||||
maintainers: jameslivulpi
|
|
||||||
$modules/system/interfaces_file.py:
|
$modules/system/interfaces_file.py:
|
||||||
maintainers: obourdon hryamzik
|
maintainers: obourdon hryamzik
|
||||||
labels: interfaces_file
|
labels: interfaces_file
|
||||||
$modules/system/iptables_state.py:
|
$modules/system/iptables_state.py:
|
||||||
maintainers: quidame
|
maintainers: quidame
|
||||||
$modules/system/shutdown.py:
|
|
||||||
maintainers: nitzmahone samdoran aminvakil
|
|
||||||
$modules/system/java_cert.py:
|
$modules/system/java_cert.py:
|
||||||
maintainers: haad absynth76
|
maintainers: haad absynth76
|
||||||
$modules/system/java_keystore.py:
|
$modules/system/java_keystore.py:
|
||||||
maintainers: Mogztter quidame
|
maintainers: Mogztter
|
||||||
$modules/system/kernel_blacklist.py:
|
$modules/system/kernel_blacklist.py:
|
||||||
maintainers: matze
|
maintainers: matze
|
||||||
$modules/system/launchd.py:
|
$modules/system/launchd.py:
|
||||||
@@ -1052,7 +859,7 @@ files:
|
|||||||
$modules/system/lvg.py:
|
$modules/system/lvg.py:
|
||||||
maintainers: abulimov
|
maintainers: abulimov
|
||||||
$modules/system/lvol.py:
|
$modules/system/lvol.py:
|
||||||
maintainers: abulimov jhoekx zigaSRC unkaputtbar112
|
maintainers: abulimov jhoekx
|
||||||
$modules/system/make.py:
|
$modules/system/make.py:
|
||||||
maintainers: LinusU
|
maintainers: LinusU
|
||||||
$modules/system/mksysb.py:
|
$modules/system/mksysb.py:
|
||||||
@@ -1065,7 +872,7 @@ files:
|
|||||||
$modules/system/nosh.py:
|
$modules/system/nosh.py:
|
||||||
maintainers: tacatac
|
maintainers: tacatac
|
||||||
$modules/system/ohai.py:
|
$modules/system/ohai.py:
|
||||||
maintainers: $team_ansible_core mpdehaan
|
maintainers: ansible mpdehaan
|
||||||
labels: ohai
|
labels: ohai
|
||||||
$modules/system/open_iscsi.py:
|
$modules/system/open_iscsi.py:
|
||||||
maintainers: srvg
|
maintainers: srvg
|
||||||
@@ -1094,8 +901,6 @@ files:
|
|||||||
ignore: ryansb
|
ignore: ryansb
|
||||||
$modules/system/runit.py:
|
$modules/system/runit.py:
|
||||||
maintainers: jsumners
|
maintainers: jsumners
|
||||||
$modules/system/sap_task_list_execute:
|
|
||||||
maintainers: rainerleber
|
|
||||||
$modules/system/sefcontext.py:
|
$modules/system/sefcontext.py:
|
||||||
maintainers: dagwieers
|
maintainers: dagwieers
|
||||||
$modules/system/selinux_permissive.py:
|
$modules/system/selinux_permissive.py:
|
||||||
@@ -1108,10 +913,6 @@ files:
|
|||||||
maintainers: $team_solaris pmarkham
|
maintainers: $team_solaris pmarkham
|
||||||
labels: solaris
|
labels: solaris
|
||||||
keywords: beadm dladm illumos ipadm nexenta omnios openindiana pfexec smartos solaris sunos zfs zpool
|
keywords: beadm dladm illumos ipadm nexenta omnios openindiana pfexec smartos solaris sunos zfs zpool
|
||||||
$modules/system/ssh_config.py:
|
|
||||||
maintainers: gaqzi Akasurde
|
|
||||||
$modules/system/sudoers.py:
|
|
||||||
maintainers: JonEllis
|
|
||||||
$modules/system/svc.py:
|
$modules/system/svc.py:
|
||||||
maintainers: bcoca
|
maintainers: bcoca
|
||||||
$modules/system/syspatch.py:
|
$modules/system/syspatch.py:
|
||||||
@@ -1127,38 +928,31 @@ files:
|
|||||||
maintainers: ahtik ovcharenko pyykkis
|
maintainers: ahtik ovcharenko pyykkis
|
||||||
labels: ufw
|
labels: ufw
|
||||||
$modules/system/vdo.py:
|
$modules/system/vdo.py:
|
||||||
maintainers: rhawalsh bgurney-rh
|
maintainers: rhawalsh
|
||||||
$modules/system/xfconf.py:
|
$modules/system/xfconf.py:
|
||||||
maintainers: russoz jbenden
|
maintainers: russoz jbenden
|
||||||
labels: xfconf
|
labels: xfconf
|
||||||
$modules/system/xfconf_info.py:
|
|
||||||
maintainers: russoz
|
|
||||||
labels: xfconf
|
|
||||||
$modules/system/xfs_quota.py:
|
$modules/system/xfs_quota.py:
|
||||||
maintainers: bushvin
|
maintainers: bushvin
|
||||||
$modules/web_infrastructure/apache2_mod_proxy.py:
|
$modules/web_infrastructure/apache2_mod_proxy.py:
|
||||||
maintainers: oboukili
|
maintainers: oboukili
|
||||||
$modules/web_infrastructure/apache2_module.py:
|
$modules/web_infrastructure/apache2_module.py:
|
||||||
maintainers: berendt n0trax
|
maintainers: berendt n0trax robinro
|
||||||
ignore: robinro
|
|
||||||
$modules/web_infrastructure/deploy_helper.py:
|
$modules/web_infrastructure/deploy_helper.py:
|
||||||
maintainers: ramondelafuente
|
maintainers: ramondelafuente
|
||||||
$modules/web_infrastructure/django_manage.py:
|
$modules/web_infrastructure/django_manage.py:
|
||||||
maintainers: russoz
|
maintainers: scottanderson42 russoz tastychutney
|
||||||
ignore: scottanderson42 tastychutney
|
|
||||||
labels: django_manage
|
labels: django_manage
|
||||||
$modules/web_infrastructure/ejabberd_user.py:
|
$modules/web_infrastructure/ejabberd_user.py:
|
||||||
maintainers: privateip
|
maintainers: privateip
|
||||||
$modules/web_infrastructure/gunicorn.py:
|
$modules/web_infrastructure/gunicorn.py:
|
||||||
maintainers: agmezr
|
maintainers: agmezr
|
||||||
$modules/web_infrastructure/htpasswd.py:
|
$modules/web_infrastructure/htpasswd.py:
|
||||||
maintainers: $team_ansible_core
|
maintainers: ansible
|
||||||
labels: htpasswd
|
labels: htpasswd
|
||||||
$modules/web_infrastructure/jboss.py:
|
$modules/web_infrastructure/jboss.py:
|
||||||
maintainers: $team_jboss jhoekx
|
maintainers: $team_jboss jhoekx
|
||||||
labels: jboss
|
labels: jboss
|
||||||
$modules/web_infrastructure/jenkins_build.py:
|
|
||||||
maintainers: brettmilford unnecessary-username
|
|
||||||
$modules/web_infrastructure/jenkins_job.py:
|
$modules/web_infrastructure/jenkins_job.py:
|
||||||
maintainers: sermilrod
|
maintainers: sermilrod
|
||||||
$modules/web_infrastructure/jenkins_job_info.py:
|
$modules/web_infrastructure/jenkins_job_info.py:
|
||||||
@@ -1168,19 +962,12 @@ files:
|
|||||||
$modules/web_infrastructure/jenkins_script.py:
|
$modules/web_infrastructure/jenkins_script.py:
|
||||||
maintainers: hogarthj
|
maintainers: hogarthj
|
||||||
$modules/web_infrastructure/jira.py:
|
$modules/web_infrastructure/jira.py:
|
||||||
maintainers: Slezhuk tarka pertoft
|
maintainers: Slezhuk tarka
|
||||||
ignore: DWSR
|
|
||||||
labels: jira
|
labels: jira
|
||||||
$modules/web_infrastructure/nginx_status_info.py:
|
$modules/web_infrastructure/nginx_status_info.py:
|
||||||
maintainers: resmo
|
maintainers: resmo
|
||||||
$modules/web_infrastructure/rundeck_acl_policy.py:
|
$modules/web_infrastructure/:
|
||||||
maintainers: nerzhul
|
maintainers: nerzhul
|
||||||
$modules/web_infrastructure/rundeck_project.py:
|
|
||||||
maintainers: nerzhul
|
|
||||||
$modules/web_infrastructure/rundeck_job_run.py:
|
|
||||||
maintainers: phsmith
|
|
||||||
$modules/web_infrastructure/rundeck_job_executions_info.py:
|
|
||||||
maintainers: phsmith
|
|
||||||
$modules/web_infrastructure/sophos_utm/:
|
$modules/web_infrastructure/sophos_utm/:
|
||||||
maintainers: $team_e_spirit
|
maintainers: $team_e_spirit
|
||||||
keywords: sophos utm
|
keywords: sophos utm
|
||||||
@@ -1190,20 +977,10 @@ files:
|
|||||||
$modules/web_infrastructure/sophos_utm/utm_proxy_exception.py:
|
$modules/web_infrastructure/sophos_utm/utm_proxy_exception.py:
|
||||||
maintainers: $team_e_spirit RickS-C137
|
maintainers: $team_e_spirit RickS-C137
|
||||||
keywords: sophos utm
|
keywords: sophos utm
|
||||||
$modules/web_infrastructure/sophos_utm/utm_ca_host_key_cert.py:
|
|
||||||
maintainers: stearz
|
|
||||||
$modules/web_infrastructure/sophos_utm/utm_ca_host_key_cert_info.py:
|
|
||||||
maintainers: stearz
|
|
||||||
$modules/web_infrastructure/sophos_utm/utm_network_interface_address.py:
|
|
||||||
maintainers: steamx
|
|
||||||
$modules/web_infrastructure/sophos_utm/utm_network_interface_address_info.py:
|
|
||||||
maintainers: steamx
|
|
||||||
$modules/web_infrastructure/supervisorctl.py:
|
$modules/web_infrastructure/supervisorctl.py:
|
||||||
maintainers: inetfuture mattupstate
|
maintainers: inetfuture mattupstate
|
||||||
$modules/web_infrastructure/taiga_issue.py:
|
$modules/web_infrastructure/taiga_issue.py:
|
||||||
maintainers: lekum
|
maintainers: lekum
|
||||||
$tests/a_module.py:
|
|
||||||
maintainers: felixfontein
|
|
||||||
#########################
|
#########################
|
||||||
tests/:
|
tests/:
|
||||||
labels: tests
|
labels: tests
|
||||||
@@ -1219,26 +996,24 @@ files:
|
|||||||
macros:
|
macros:
|
||||||
actions: plugins/action
|
actions: plugins/action
|
||||||
becomes: plugins/become
|
becomes: plugins/become
|
||||||
caches: plugins/cache
|
|
||||||
callbacks: plugins/callback
|
callbacks: plugins/callback
|
||||||
cliconfs: plugins/cliconf
|
cliconfs: plugins/cliconf
|
||||||
connections: plugins/connection
|
connections: plugins/connection
|
||||||
doc_fragments: plugins/doc_fragments
|
doc_fragments: plugins/doc_fragments
|
||||||
filters: plugins/filter
|
filters: plugins/filter
|
||||||
|
httpapis: plugins/httpapi
|
||||||
inventories: plugins/inventory
|
inventories: plugins/inventory
|
||||||
lookups: plugins/lookup
|
lookups: plugins/lookup
|
||||||
module_utils: plugins/module_utils
|
module_utils: plugins/module_utils
|
||||||
modules: plugins/modules
|
modules: plugins/modules
|
||||||
terminals: plugins/terminal
|
terminals: plugins/terminal
|
||||||
tests: plugins/test
|
|
||||||
team_ansible_core:
|
|
||||||
team_aix: MorrisA bcoca d-little flynn1973 gforster kairoaraujo marvin-sinister mator molekuul ramooncamacho wtcross
|
team_aix: MorrisA bcoca d-little flynn1973 gforster kairoaraujo marvin-sinister mator molekuul ramooncamacho wtcross
|
||||||
team_bsd: JoergFiedler MacLemon bcoca dch jasperla mekanix opoplawski overhacked tuxillo
|
team_bsd: JoergFiedler MacLemon bcoca dch jasperla mekanix opoplawski overhacked tuxillo
|
||||||
team_consul: sgargan
|
team_consul: sgargan
|
||||||
team_cyberark_conjur: jvanderhoof ryanprior
|
team_cyberark_conjur: jvanderhoof ryanprior
|
||||||
team_e_spirit: MatrixCrawler getjack
|
team_e_spirit: MatrixCrawler getjack
|
||||||
team_flatpak: JayKayy oolongbrothers
|
team_flatpak: JayKayy oolongbrothers
|
||||||
team_gitlab: Lunik Shaps dj-wasabi marwatk waheedi zanssa scodeman metanovii sh0shin nejch lgatellier suukit
|
team_gitlab: Lunik Shaps dj-wasabi marwatk waheedi zanssa scodeman metanovii
|
||||||
team_hpux: bcoca davx8342
|
team_hpux: bcoca davx8342
|
||||||
team_huawei: QijunPan TommyLike edisonxiang freesky-edward hwDCN niuzhenguo xuxiaowei0512 yanzhangi zengchen1024 zhongjun2
|
team_huawei: QijunPan TommyLike edisonxiang freesky-edward hwDCN niuzhenguo xuxiaowei0512 yanzhangi zengchen1024 zhongjun2
|
||||||
team_ipa: Akasurde Nosmoht fxfitz justchris1
|
team_ipa: Akasurde Nosmoht fxfitz justchris1
|
||||||
@@ -1247,13 +1022,14 @@ macros:
|
|||||||
team_linode: InTheCloudDan decentral1se displague rmcintosh Charliekenney23 LBGarber
|
team_linode: InTheCloudDan decentral1se displague rmcintosh Charliekenney23 LBGarber
|
||||||
team_macos: Akasurde kyleabenson martinm82 danieljaouen indrajitr
|
team_macos: Akasurde kyleabenson martinm82 danieljaouen indrajitr
|
||||||
team_manageiq: abellotti cben gtanzillo yaacov zgalor dkorn evertmulder
|
team_manageiq: abellotti cben gtanzillo yaacov zgalor dkorn evertmulder
|
||||||
|
team_netapp: amit0701 carchi8py hulquest lmprice lonico ndswartz schmots1
|
||||||
team_networking: NilashishC Qalthos danielmellado ganeshrn justjais trishnaguha sganesh-infoblox privateip
|
team_networking: NilashishC Qalthos danielmellado ganeshrn justjais trishnaguha sganesh-infoblox privateip
|
||||||
team_opennebula: ilicmilan meerkampdvv rsmontero xorel nilsding
|
team_opennebula: ilicmilan meerkampdvv rsmontero xorel nilsding
|
||||||
team_oracle: manojmeda mross22 nalsaber
|
team_oracle: manojmeda mross22 nalsaber
|
||||||
team_purestorage: bannaych dnix101 genegr lionmax opslounge raekins sdodsley sile16
|
team_purestorage: bannaych dnix101 genegr lionmax opslounge raekins sdodsley sile16
|
||||||
team_redfish: mraineri tomasg2012 xmadsen renxulei rajeevkallur bhavya06
|
team_redfish: mraineri tomasg2012 xmadsen renxulei
|
||||||
team_rhn: FlossWare alikins barnabycourt vritant
|
team_rhn: FlossWare alikins barnabycourt vritant
|
||||||
team_scaleway: remyleone abarbare
|
team_scaleway: QuentinBrosse abarbare jerome-quere kindermoumoute remyleone sieben
|
||||||
team_solaris: bcoca fishman jasperla jpdasma mator scathatheworm troy2914 xen0l
|
team_solaris: bcoca fishman jasperla jpdasma mator scathatheworm troy2914 xen0l
|
||||||
team_suse: commel dcermak evrardjp lrupp toabctl AnderEnder alxgu andytom sealor
|
team_suse: commel dcermak evrardjp lrupp toabctl AnderEnder alxgu andytom sealor
|
||||||
team_virt: joshainglis karmab tleguern Thulium-Drake Ajpantuso
|
team_virt: joshainglis karmab tleguern Thulium-Drake Ajpantuso
|
||||||
|
|||||||
14
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
14
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -62,20 +62,6 @@ body:
|
|||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Community.general Version
|
|
||||||
description: >-
|
|
||||||
Paste verbatim output from "ansible-galaxy collection list community.general"
|
|
||||||
between tripple backticks.
|
|
||||||
value: |
|
|
||||||
```console (paste below)
|
|
||||||
$ ansible-galaxy collection list community.general
|
|
||||||
|
|
||||||
```
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: Configuration
|
label: Configuration
|
||||||
|
|||||||
14
.github/ISSUE_TEMPLATE/documentation_report.yml
vendored
14
.github/ISSUE_TEMPLATE/documentation_report.yml
vendored
@@ -62,20 +62,6 @@ body:
|
|||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Community.general Version
|
|
||||||
description: >-
|
|
||||||
Paste verbatim output from "ansible-galaxy collection list community.general"
|
|
||||||
between tripple backticks.
|
|
||||||
value: |
|
|
||||||
```console (paste below)
|
|
||||||
$ ansible-galaxy collection list community.general
|
|
||||||
|
|
||||||
```
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: Configuration
|
label: Configuration
|
||||||
|
|||||||
2
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
2
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@@ -21,7 +21,7 @@ body:
|
|||||||
placeholder: >-
|
placeholder: >-
|
||||||
I am trying to do X with the collection from the main branch on GitHub and
|
I am trying to do X with the collection from the main branch on GitHub and
|
||||||
I think that implementing a feature Y would be very helpful for me and
|
I think that implementing a feature Y would be very helpful for me and
|
||||||
every other user of community.general because of Z.
|
every other user of ansible-core because of Z.
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
|
|||||||
6
.github/dependabot.yml
vendored
6
.github/dependabot.yml
vendored
@@ -1,6 +0,0 @@
|
|||||||
version: 2
|
|
||||||
updates:
|
|
||||||
- package-ecosystem: "github-actions"
|
|
||||||
directory: "/"
|
|
||||||
interval:
|
|
||||||
schedule: "weekly"
|
|
||||||
81
.gitignore
vendored
81
.gitignore
vendored
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
# Created by https://www.toptal.com/developers/gitignore/api/git,linux,pydev,python,windows,pycharm+all,jupyternotebook,vim,webstorm,emacs,dotenv
|
# Created by https://www.gitignore.io/api/git,linux,pydev,python,windows,pycharm+all,jupyternotebook,vim,webstorm,emacs,dotenv
|
||||||
# Edit at https://www.toptal.com/developers/gitignore?templates=git,linux,pydev,python,windows,pycharm+all,jupyternotebook,vim,webstorm,emacs,dotenv
|
# Edit at https://www.gitignore.io/?templates=git,linux,pydev,python,windows,pycharm+all,jupyternotebook,vim,webstorm,emacs,dotenv
|
||||||
|
|
||||||
### dotenv ###
|
### dotenv ###
|
||||||
.env
|
.env
|
||||||
@@ -88,7 +88,7 @@ flycheck_*.el
|
|||||||
.nfs*
|
.nfs*
|
||||||
|
|
||||||
### PyCharm+all ###
|
### PyCharm+all ###
|
||||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
|
||||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
# User-specific stuff
|
# User-specific stuff
|
||||||
@@ -98,9 +98,6 @@ flycheck_*.el
|
|||||||
.idea/**/dictionaries
|
.idea/**/dictionaries
|
||||||
.idea/**/shelf
|
.idea/**/shelf
|
||||||
|
|
||||||
# AWS User-specific
|
|
||||||
.idea/**/aws.xml
|
|
||||||
|
|
||||||
# Generated files
|
# Generated files
|
||||||
.idea/**/contentModel.xml
|
.idea/**/contentModel.xml
|
||||||
|
|
||||||
@@ -121,9 +118,6 @@ flycheck_*.el
|
|||||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||||
# since they will be recreated, and may cause churn. Uncomment if using
|
# since they will be recreated, and may cause churn. Uncomment if using
|
||||||
# auto-import.
|
# auto-import.
|
||||||
# .idea/artifacts
|
|
||||||
# .idea/compiler.xml
|
|
||||||
# .idea/jarRepositories.xml
|
|
||||||
# .idea/modules.xml
|
# .idea/modules.xml
|
||||||
# .idea/*.iml
|
# .idea/*.iml
|
||||||
# .idea/modules
|
# .idea/modules
|
||||||
@@ -204,6 +198,7 @@ parts/
|
|||||||
sdist/
|
sdist/
|
||||||
var/
|
var/
|
||||||
wheels/
|
wheels/
|
||||||
|
pip-wheel-metadata/
|
||||||
share/python-wheels/
|
share/python-wheels/
|
||||||
*.egg-info/
|
*.egg-info/
|
||||||
.installed.cfg
|
.installed.cfg
|
||||||
@@ -230,25 +225,13 @@ htmlcov/
|
|||||||
nosetests.xml
|
nosetests.xml
|
||||||
coverage.xml
|
coverage.xml
|
||||||
*.cover
|
*.cover
|
||||||
*.py,cover
|
|
||||||
.hypothesis/
|
.hypothesis/
|
||||||
.pytest_cache/
|
.pytest_cache/
|
||||||
cover/
|
|
||||||
|
|
||||||
# Translations
|
# Translations
|
||||||
*.mo
|
*.mo
|
||||||
*.pot
|
*.pot
|
||||||
|
|
||||||
# Django stuff:
|
|
||||||
*.log
|
|
||||||
local_settings.py
|
|
||||||
db.sqlite3
|
|
||||||
db.sqlite3-journal
|
|
||||||
|
|
||||||
# Flask stuff:
|
|
||||||
instance/
|
|
||||||
.webassets-cache
|
|
||||||
|
|
||||||
# Scrapy stuff:
|
# Scrapy stuff:
|
||||||
.scrapy
|
.scrapy
|
||||||
|
|
||||||
@@ -256,19 +239,9 @@ instance/
|
|||||||
docs/_build/
|
docs/_build/
|
||||||
|
|
||||||
# PyBuilder
|
# PyBuilder
|
||||||
.pybuilder/
|
|
||||||
target/
|
target/
|
||||||
|
|
||||||
# Jupyter Notebook
|
|
||||||
.ipynb_checkpoints
|
|
||||||
|
|
||||||
# IPython
|
|
||||||
profile_default/
|
|
||||||
ipython_config.py
|
|
||||||
|
|
||||||
# pyenv
|
# pyenv
|
||||||
# For a library or package, you might want to ignore these files since the code is
|
|
||||||
# intended to run in multiple environments; otherwise, check them in:
|
|
||||||
.python-version
|
.python-version
|
||||||
|
|
||||||
# pipenv
|
# pipenv
|
||||||
@@ -278,24 +251,12 @@ ipython_config.py
|
|||||||
# install all needed dependencies.
|
# install all needed dependencies.
|
||||||
#Pipfile.lock
|
#Pipfile.lock
|
||||||
|
|
||||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
# celery beat schedule file
|
||||||
__pypackages__/
|
|
||||||
|
|
||||||
# Celery stuff
|
|
||||||
celerybeat-schedule
|
celerybeat-schedule
|
||||||
celerybeat.pid
|
|
||||||
|
|
||||||
# SageMath parsed files
|
# SageMath parsed files
|
||||||
*.sage.py
|
*.sage.py
|
||||||
|
|
||||||
# Environments
|
|
||||||
.venv
|
|
||||||
env/
|
|
||||||
venv/
|
|
||||||
ENV/
|
|
||||||
env.bak/
|
|
||||||
venv.bak/
|
|
||||||
|
|
||||||
# Spyder project settings
|
# Spyder project settings
|
||||||
.spyderproject
|
.spyderproject
|
||||||
.spyproject
|
.spyproject
|
||||||
@@ -303,6 +264,10 @@ venv.bak/
|
|||||||
# Rope project settings
|
# Rope project settings
|
||||||
.ropeproject
|
.ropeproject
|
||||||
|
|
||||||
|
# Mr Developer
|
||||||
|
.mr.developer.cfg
|
||||||
|
.project
|
||||||
|
|
||||||
# mkdocs documentation
|
# mkdocs documentation
|
||||||
/site
|
/site
|
||||||
|
|
||||||
@@ -314,16 +279,9 @@ dmypy.json
|
|||||||
# Pyre type checker
|
# Pyre type checker
|
||||||
.pyre/
|
.pyre/
|
||||||
|
|
||||||
# pytype static type analyzer
|
|
||||||
.pytype/
|
|
||||||
|
|
||||||
# Cython debug symbols
|
|
||||||
cython_debug/
|
|
||||||
|
|
||||||
### Vim ###
|
### Vim ###
|
||||||
# Swap
|
# Swap
|
||||||
[._]*.s[a-v][a-z]
|
[._]*.s[a-v][a-z]
|
||||||
!*.svg # comment out if you don't need vector files
|
|
||||||
[._]*.sw[a-p]
|
[._]*.sw[a-p]
|
||||||
[._]s[a-rt-v][a-z]
|
[._]s[a-rt-v][a-z]
|
||||||
[._]ss[a-gi-z]
|
[._]ss[a-gi-z]
|
||||||
@@ -341,13 +299,11 @@ tags
|
|||||||
[._]*.un~
|
[._]*.un~
|
||||||
|
|
||||||
### WebStorm ###
|
### WebStorm ###
|
||||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
|
||||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
# User-specific stuff
|
# User-specific stuff
|
||||||
|
|
||||||
# AWS User-specific
|
|
||||||
|
|
||||||
# Generated files
|
# Generated files
|
||||||
|
|
||||||
# Sensitive or high-churn files
|
# Sensitive or high-churn files
|
||||||
@@ -358,9 +314,6 @@ tags
|
|||||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||||
# since they will be recreated, and may cause churn. Uncomment if using
|
# since they will be recreated, and may cause churn. Uncomment if using
|
||||||
# auto-import.
|
# auto-import.
|
||||||
# .idea/artifacts
|
|
||||||
# .idea/compiler.xml
|
|
||||||
# .idea/jarRepositories.xml
|
|
||||||
# .idea/modules.xml
|
# .idea/modules.xml
|
||||||
# .idea/*.iml
|
# .idea/*.iml
|
||||||
# .idea/modules
|
# .idea/modules
|
||||||
@@ -396,27 +349,15 @@ tags
|
|||||||
# *.ipr
|
# *.ipr
|
||||||
|
|
||||||
# Sonarlint plugin
|
# Sonarlint plugin
|
||||||
# https://plugins.jetbrains.com/plugin/7973-sonarlint
|
|
||||||
.idea/**/sonarlint/
|
.idea/**/sonarlint/
|
||||||
|
|
||||||
# SonarQube Plugin
|
# SonarQube Plugin
|
||||||
# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
|
|
||||||
.idea/**/sonarIssues.xml
|
.idea/**/sonarIssues.xml
|
||||||
|
|
||||||
# Markdown Navigator plugin
|
# Markdown Navigator plugin
|
||||||
# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
|
|
||||||
.idea/**/markdown-navigator.xml
|
.idea/**/markdown-navigator.xml
|
||||||
.idea/**/markdown-navigator-enh.xml
|
|
||||||
.idea/**/markdown-navigator/
|
.idea/**/markdown-navigator/
|
||||||
|
|
||||||
# Cache file creation bug
|
|
||||||
# See https://youtrack.jetbrains.com/issue/JBR-2257
|
|
||||||
.idea/$CACHE_FILE$
|
|
||||||
|
|
||||||
# CodeStream plugin
|
|
||||||
# https://plugins.jetbrains.com/plugin/12206-codestream
|
|
||||||
.idea/codestream.xml
|
|
||||||
|
|
||||||
### Windows ###
|
### Windows ###
|
||||||
# Windows thumbnail cache files
|
# Windows thumbnail cache files
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
@@ -443,4 +384,4 @@ $RECYCLE.BIN/
|
|||||||
# Windows shortcuts
|
# Windows shortcuts
|
||||||
*.lnk
|
*.lnk
|
||||||
|
|
||||||
# End of https://www.toptal.com/developers/gitignore/api/git,linux,pydev,python,windows,pycharm+all,jupyternotebook,vim,webstorm,emacs,dotenv
|
# End of https://www.gitignore.io/api/git,linux,pydev,python,windows,pycharm+all,jupyternotebook,vim,webstorm,emacs,dotenv
|
||||||
|
|||||||
1342
CHANGELOG.rst
1342
CHANGELOG.rst
File diff suppressed because it is too large
Load Diff
121
CONTRIBUTING.md
121
CONTRIBUTING.md
@@ -1,121 +0,0 @@
|
|||||||
# Contributing
|
|
||||||
|
|
||||||
We follow [Ansible Code of Conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html) in all our contributions and interactions within this repository.
|
|
||||||
|
|
||||||
If you are a committer, also refer to the [collection's committer guidelines](https://github.com/ansible-collections/community.general/blob/main/commit-rights.md).
|
|
||||||
|
|
||||||
## Issue tracker
|
|
||||||
|
|
||||||
Whether you are looking for an opportunity to contribute or you found a bug and already know how to solve it, please go to the [issue tracker](https://github.com/ansible-collections/community.general/issues).
|
|
||||||
There you can find feature ideas to implement, reports about bugs to solve, or submit an issue to discuss your idea before implementing it which can help choose a right direction at the beginning of your work and potentially save a lot of time and effort.
|
|
||||||
Also somebody may already have started discussing or working on implementing the same or a similar idea,
|
|
||||||
so you can cooperate to create a better solution together.
|
|
||||||
|
|
||||||
* If you are interested in starting with an easy issue, look for [issues with an `easyfix` label](https://github.com/ansible-collections/community.general/labels/easyfix).
|
|
||||||
* Often issues that are waiting for contributors to pick up have [the `waiting_on_contributor` label](https://github.com/ansible-collections/community.general/labels/waiting_on_contributor).
|
|
||||||
|
|
||||||
## Open pull requests
|
|
||||||
|
|
||||||
Look through currently [open pull requests](https://github.com/ansible-collections/community.general/pulls).
|
|
||||||
You can help by reviewing them. Reviews help move pull requests to merge state. Some good pull requests cannot be merged only due to a lack of reviews. And it is always worth saying that good reviews are often more valuable than pull requests themselves.
|
|
||||||
Note that reviewing does not only mean code review, but also offering comments on new interfaces added to existing plugins/modules, interfaces of new plugins/modules, improving language (not everyone is a native english speaker), or testing bugfixes and new features!
|
|
||||||
|
|
||||||
Also, consider taking up a valuable, reviewed, but abandoned pull request which you could politely ask the original authors to complete yourself.
|
|
||||||
|
|
||||||
* Try committing your changes with an informative but short commit message.
|
|
||||||
* Do not squash your commits and force-push to your branch if not needed. Reviews of your pull request are much easier with individual commits to comprehend the pull request history. All commits of your pull request branch will be squashed into one commit by GitHub upon merge.
|
|
||||||
* Do not add merge commits to your PR. The bot will complain and you will have to rebase ([instructions for rebasing](https://docs.ansible.com/ansible/latest/dev_guide/developing_rebasing.html)) to remove them before your PR can be merged. To avoid that git automatically does merges during pulls, you can configure it to do rebases instead by running `git config pull.rebase true` inside the repository checkout.
|
|
||||||
* Make sure your PR includes a [changelog fragment](https://docs.ansible.com/ansible/devel/community/development_process.html#changelogs-how-to). (You must not include a fragment for new modules or new plugins, except for test and filter plugins. Also you shouldn't include one for docs-only changes. If you're not sure, simply don't include one, we'll tell you whether one is needed or not :) )
|
|
||||||
* Avoid reformatting unrelated parts of the codebase in your PR. These types of changes will likely be requested for reversion, create additional work for reviewers, and may cause approval to be delayed.
|
|
||||||
|
|
||||||
You can also read [our Quick-start development guide](https://github.com/ansible/community-docs/blob/main/create_pr_quick_start_guide.rst).
|
|
||||||
|
|
||||||
## Test pull requests
|
|
||||||
|
|
||||||
If you want to test a PR locally, refer to [our testing guide](https://github.com/ansible/community-docs/blob/main/test_pr_locally_guide.rst) for instructions on how do it quickly.
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
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:
|
|
||||||
|
|
||||||
```.bash
|
|
||||||
mkdir -p ~/dev/ansible_collections/community
|
|
||||||
git clone https://github.com/ansible-collections/community.general.git ~/dev/ansible_collections/community/general
|
|
||||||
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+.
|
|
||||||
|
|
||||||
The following commands show how to run sanity tests:
|
|
||||||
|
|
||||||
```.bash
|
|
||||||
# Run sanity tests for all files in the collection:
|
|
||||||
ansible-test sanity --docker -v
|
|
||||||
|
|
||||||
# Run sanity tests for the given files and directories:
|
|
||||||
ansible-test sanity --docker -v plugins/modules/system/pids.py tests/integration/targets/pids/
|
|
||||||
```
|
|
||||||
|
|
||||||
The following commands show how to run unit tests:
|
|
||||||
|
|
||||||
```.bash
|
|
||||||
# Run all unit tests:
|
|
||||||
ansible-test units --docker -v
|
|
||||||
|
|
||||||
# Run all unit tests for one Python version (a lot faster):
|
|
||||||
ansible-test units --docker -v --python 3.8
|
|
||||||
|
|
||||||
# Run a specific unit test (for the nmcli module) for one Python version:
|
|
||||||
ansible-test units --docker -v --python 3.8 tests/unit/plugins/modules/net_tools/test_nmcli.py
|
|
||||||
```
|
|
||||||
|
|
||||||
The following commands show how to run integration tests:
|
|
||||||
|
|
||||||
```.bash
|
|
||||||
# Run integration tests for the interfaces_files module in a Docker container using the
|
|
||||||
# fedora35 operating system image (the supported images depend on your ansible-core version):
|
|
||||||
ansible-test integration --docker fedora35 -v interfaces_file
|
|
||||||
|
|
||||||
# Run integration tests for the flattened lookup **without any isolation**:
|
|
||||||
ansible-test integration -v lookup_flattened
|
|
||||||
```
|
|
||||||
|
|
||||||
If you are unsure about the integration test target name for a module or plugin, you can take a look in `tests/integration/targets/`. Tests for plugins have the plugin type prepended.
|
|
||||||
|
|
||||||
## Creating new modules or plugins
|
|
||||||
|
|
||||||
Creating new modules and plugins requires a bit more work than other Pull Requests.
|
|
||||||
|
|
||||||
1. Please make sure that your new module or plugin is of interest to a larger audience. Very specialized modules or plugins that
|
|
||||||
can only be used by very few people should better be added to more specialized collections.
|
|
||||||
|
|
||||||
2. Please do not add more than one plugin/module in one PR, especially if it is the first plugin/module you are contributing.
|
|
||||||
That makes it easier for reviewers, and increases the chance that your PR will get merged. If you plan to contribute a group
|
|
||||||
of plugins/modules (say, more than a module and a corresponding ``_info`` module), please mention that in the first PR. In
|
|
||||||
such cases, you also have to think whether it is better to publish the group of plugins/modules in a new collection.
|
|
||||||
|
|
||||||
3. When creating a new module or plugin, please make sure that you follow various guidelines:
|
|
||||||
|
|
||||||
- Follow [development conventions](https://docs.ansible.com/ansible/devel/dev_guide/developing_modules_best_practices.html);
|
|
||||||
- Follow [documentation standards](https://docs.ansible.com/ansible/devel/dev_guide/developing_modules_documenting.html) and
|
|
||||||
the [Ansible style guide](https://docs.ansible.com/ansible/devel/dev_guide/style_guide/index.html#style-guide);
|
|
||||||
- Make sure your modules and plugins are [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0-standalone.html) licensed
|
|
||||||
(new module_utils can also be [BSD-2-clause](https://opensource.org/licenses/BSD-2-Clause) licensed);
|
|
||||||
- Make sure that new plugins and modules have tests (unit tests, integration tests, or both); it is preferable to have some tests
|
|
||||||
which run in CI.
|
|
||||||
|
|
||||||
4. For modules and action plugins, make sure to create your module/plugin in the correct subdirectory, and create a symbolic link
|
|
||||||
from `plugins/modules/` respectively `plugins/action/` to the actual module/plugin code. (Other plugin types should not use
|
|
||||||
subdirectories.)
|
|
||||||
|
|
||||||
- Action plugins need to be accompanied by a module, even if the module file only contains documentation
|
|
||||||
(`DOCUMENTATION`, `EXAMPLES` and `RETURN`). The module must have the same name and directory path in `plugins/modules/`
|
|
||||||
than the action plugin has in `plugins/action/`.
|
|
||||||
|
|
||||||
5. Make sure to add a BOTMETA entry for your new module/plugin in `.github/BOTMETA.yml`. Search for other plugins/modules in the
|
|
||||||
same directory to see how entries could look. You should list all authors either as `maintainers` or under `ignore`. People
|
|
||||||
listed as `maintainers` will be pinged for new issues and PRs that modify the module/plugin or its tests.
|
|
||||||
|
|
||||||
When you add a new plugin/module, we expect that you perform maintainer duty for at least some time after contributing it.
|
|
||||||
86
README.md
86
README.md
@@ -1,23 +1,17 @@
|
|||||||
# Community General Collection
|
# Community General Collection
|
||||||
|
|
||||||
[](https://dev.azure.com/ansible/community.general/_build?definitionId=31)
|
[](https://dev.azure.com/ansible/community.general/_build?definitionId=31)
|
||||||
[](https://codecov.io/gh/ansible-collections/community.general)
|
[](https://codecov.io/gh/ansible-collections/community.general)
|
||||||
|
|
||||||
This repository contains the `community.general` Ansible Collection. The collection is a part of the Ansible package and includes many modules and plugins supported by Ansible community which are not part of more specialized community collections.
|
This repo contains the `community.general` Ansible Collection. The collection includes many modules and plugins supported by Ansible community which are not part of more specialized community collections.
|
||||||
|
|
||||||
You can find [documentation for this collection on the Ansible docs site](https://docs.ansible.com/ansible/latest/collections/community/general/).
|
You can find [documentation for this collection on the Ansible docs site](https://docs.ansible.com/ansible/latest/collections/community/general/).
|
||||||
|
|
||||||
Please note that this collection does **not** support Windows targets. Only connection plugins included in this collection might support Windows targets, and will explicitly mention that in their documentation if they do so.
|
Please note that this collection does **not** support Windows targets. Only connection plugins included in this collection might support Windows targets, and will explicitly mention that in their documentation if they do so.
|
||||||
|
|
||||||
## Code of Conduct
|
|
||||||
|
|
||||||
We follow [Ansible Code of Conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html) in all our interactions within this project.
|
|
||||||
|
|
||||||
If you encounter abusive behavior violating the [Ansible Code of Conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html), please refer to the [policy violations](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html#policy-violations) section of the Code of Conduct for information on how to raise a complaint.
|
|
||||||
|
|
||||||
## Tested with Ansible
|
## Tested with Ansible
|
||||||
|
|
||||||
Tested with the current Ansible 2.9, ansible-base 2.10, ansible-core 2.11, ansible-core 2.12, ansible-core 2.13 releases and the current development version of ansible-core. Ansible versions before 2.9.10 are not supported.
|
Tested with the current Ansible 2.9, ansible-base 2.10 and ansible-core 2.11 releases and the current development version of ansible-core. Ansible versions before 2.9.10 are not supported.
|
||||||
|
|
||||||
## External requirements
|
## External requirements
|
||||||
|
|
||||||
@@ -29,9 +23,7 @@ Please check the included content on the [Ansible Galaxy page for this collectio
|
|||||||
|
|
||||||
## Using this collection
|
## Using this collection
|
||||||
|
|
||||||
This collection is shipped with the Ansible package. So if you have it installed, no more action is required.
|
Before using the General community collection, you need to install the collection with the `ansible-galaxy` CLI:
|
||||||
|
|
||||||
If you have a minimal installation (only Ansible Core installed) or you want to use the latest version of the collection along with the whole Ansible package, you need to install the collection from [Ansible Galaxy](https://galaxy.ansible.com/community/general) manually with the `ansible-galaxy` command-line tool:
|
|
||||||
|
|
||||||
ansible-galaxy collection install community.general
|
ansible-galaxy collection install community.general
|
||||||
|
|
||||||
@@ -42,79 +34,57 @@ collections:
|
|||||||
- name: community.general
|
- name: community.general
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that if you install the collection manually, it will not be upgraded automatically when you upgrade the Ansible package. To upgrade the collection to the latest available version, run the following command:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ansible-galaxy collection install community.general --upgrade
|
|
||||||
```
|
|
||||||
|
|
||||||
You can also install a specific version of the collection, for example, if you need to downgrade when something is broken in the latest version (please report an issue in this repository). Use the following syntax where `X.Y.Z` can be any [available version](https://galaxy.ansible.com/community/general):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ansible-galaxy collection install community.general:==X.Y.Z
|
|
||||||
```
|
|
||||||
|
|
||||||
See [Ansible Using collections](https://docs.ansible.com/ansible/latest/user_guide/collections_using.html) for more details.
|
See [Ansible Using collections](https://docs.ansible.com/ansible/latest/user_guide/collections_using.html) for more details.
|
||||||
|
|
||||||
## Contributing to this collection
|
## Contributing to this collection
|
||||||
|
|
||||||
The content of this collection is made by good people just like you, a community of individuals collaborating on making the world better through developing automation software.
|
If you want to develop new content for this collection or improve what is already here, the easiest way to work on the collection is to clone it into one of the configured [`COLLECTIONS_PATH`](https://docs.ansible.com/ansible/latest/reference_appendices/config.html#collections-paths), and work on it there.
|
||||||
|
|
||||||
We are actively accepting new contributors.
|
For example, if you are working in the `~/dev` directory:
|
||||||
|
|
||||||
All types of contributions are very welcome.
|
```
|
||||||
|
cd ~/dev
|
||||||
You don't know how to start? Refer to our [contribution guide](https://github.com/ansible-collections/community.general/blob/stable-4/CONTRIBUTING.md)!
|
git clone git@github.com:ansible-collections/community.general.git collections/ansible_collections/community/general
|
||||||
|
export COLLECTIONS_PATH=$(pwd)/collections:$COLLECTIONS_PATH
|
||||||
The current maintainers are listed in the [commit-rights.md](https://github.com/ansible-collections/community.general/blob/stable-4/commit-rights.md#people) file. If you have questions or need help, feel free to mention them in the proposals.
|
```
|
||||||
|
|
||||||
You can find more information in the [developer guide for collections](https://docs.ansible.com/ansible/devel/dev_guide/developing_collections.html#contributing-to-collections), and in the [Ansible Community Guide](https://docs.ansible.com/ansible/latest/community/index.html).
|
You can find more information in the [developer guide for collections](https://docs.ansible.com/ansible/devel/dev_guide/developing_collections.html#contributing-to-collections), and in the [Ansible Community Guide](https://docs.ansible.com/ansible/latest/community/index.html).
|
||||||
|
|
||||||
Also for some notes specific to this collection see [our CONTRIBUTING documentation](https://github.com/ansible-collections/community.general/blob/stable-4/CONTRIBUTING.md).
|
|
||||||
|
|
||||||
### Running tests
|
### Running tests
|
||||||
|
|
||||||
See [here](https://docs.ansible.com/ansible/devel/dev_guide/developing_collections.html#testing-collections).
|
See [here](https://docs.ansible.com/ansible/devel/dev_guide/developing_collections.html#testing-collections).
|
||||||
|
|
||||||
## Collection maintenance
|
### Communication
|
||||||
|
|
||||||
To learn how to maintain / become a maintainer of this collection, refer to:
|
We have a dedicated Working Group for Ansible development.
|
||||||
|
|
||||||
* [Committer guidelines](https://github.com/ansible-collections/community.general/blob/stable-4/commit-rights.md).
|
You can find other people interested on the following Freenode IRC channels -
|
||||||
* [Maintainer guidelines](https://github.com/ansible/community-docs/blob/main/maintaining.rst).
|
- `#ansible` - For general use questions and support.
|
||||||
|
- `#ansible-devel` - For discussions on developer topics and code related to features or bugs.
|
||||||
It is necessary for maintainers of this collection to be subscribed to:
|
- `#ansible-community` - For discussions on community topics and community meetings.
|
||||||
|
|
||||||
* The collection itself (the `Watch` button → `All Activity` in the upper right corner of the repository's homepage).
|
|
||||||
* The "Changes Impacting Collection Contributors and Maintainers" [issue](https://github.com/ansible-collections/overview/issues/45).
|
|
||||||
|
|
||||||
They also should be subscribed to Ansible's [The Bullhorn newsletter](https://docs.ansible.com/ansible/devel/community/communication.html#the-bullhorn).
|
|
||||||
|
|
||||||
## Communication
|
|
||||||
|
|
||||||
We announce important development changes and releases through Ansible's [The Bullhorn newsletter](https://eepurl.com/gZmiEP). If you are a collection developer, be sure you are subscribed.
|
|
||||||
|
|
||||||
Join us in the `#ansible` (general use questions and support), `#ansible-community` (community and collection development questions), and other [IRC channels](https://docs.ansible.com/ansible/devel/community/communication.html#irc-channels) on [Libera.chat](https://libera.chat).
|
|
||||||
|
|
||||||
We take part in the global quarterly [Ansible Contributor Summit](https://github.com/ansible/community/wiki/Contributor-Summit) virtually or in-person. Track [The Bullhorn newsletter](https://eepurl.com/gZmiEP) and join us.
|
|
||||||
|
|
||||||
For more information about communities, meetings and agendas see [Community Wiki](https://github.com/ansible/community/wiki/Community).
|
For more information about communities, meetings and agendas see [Community Wiki](https://github.com/ansible/community/wiki/Community).
|
||||||
|
|
||||||
For more information about communication, refer to Ansible's the [Communication guide](https://docs.ansible.com/ansible/devel/community/communication.html).
|
For more information about [communication](https://docs.ansible.com/ansible/latest/community/communication.html)
|
||||||
|
|
||||||
## Publishing New Version
|
### Publishing New Version
|
||||||
|
|
||||||
See the [Releasing guidelines](https://github.com/ansible/community-docs/blob/main/releasing_collections.rst) to learn how to release this collection.
|
Basic instructions without release branches:
|
||||||
|
|
||||||
|
1. Create `changelogs/fragments/<version>.yml` with `release_summary:` section (which must be a string, not a list).
|
||||||
|
2. Run `antsibull-changelog release --collection-flatmap yes`
|
||||||
|
3. Make sure `CHANGELOG.rst` and `changelogs/changelog.yaml` are added to git, and the deleted fragments have been removed.
|
||||||
|
4. Tag the commit with `<version>`. Push changes and tag to the main repository.
|
||||||
|
|
||||||
## Release notes
|
## Release notes
|
||||||
|
|
||||||
See the [changelog](https://github.com/ansible-collections/community.general/blob/stable-4/CHANGELOG.rst).
|
See the [changelog](https://github.com/ansible-collections/community.general/blob/stable-3/CHANGELOG.rst).
|
||||||
|
|
||||||
## Roadmap
|
## Roadmap
|
||||||
|
|
||||||
In general, we plan to release a major version every six months, and minor versions every two months. Major versions can contain breaking changes, while minor versions only contain new features and bugfixes.
|
See [this issue](https://github.com/ansible-collections/community.general/issues/582) for information on releasing, versioning and deprecation.
|
||||||
|
|
||||||
See [this issue](https://github.com/ansible-collections/community.general/issues/582) for information on releasing, versioning, and deprecation.
|
In general, we plan to release a major version every six months, and minor versions every two months. Major versions can contain breaking changes, while minor versions only contain new features and bugfixes.
|
||||||
|
|
||||||
## More information
|
## More information
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -67,8 +67,6 @@ Individuals who have been asked to become a part of this group have generally be
|
|||||||
|
|
||||||
| Name | GitHub ID | IRC Nick | Other |
|
| Name | GitHub ID | IRC Nick | Other |
|
||||||
| ------------------- | -------------------- | ------------------ | -------------------- |
|
| ------------------- | -------------------- | ------------------ | -------------------- |
|
||||||
| Alexei Znamensky | russoz | russoz | |
|
|
||||||
| Andrew Klychkov | andersson007 | andersson007_ | |
|
| Andrew Klychkov | andersson007 | andersson007_ | |
|
||||||
| Andrew Pantuso | Ajpantuso | ajpantuso | |
|
|
||||||
| Felix Fontein | felixfontein | felixfontein | |
|
| Felix Fontein | felixfontein | felixfontein | |
|
||||||
| John R Barker | gundalow | gundalow | |
|
| John R Barker | gundalow | gundalow | |
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
---
|
|
||||||
sections:
|
|
||||||
- title: Guides
|
|
||||||
toctree:
|
|
||||||
- filter_guide
|
|
||||||
- test_guide
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
list1:
|
|
||||||
- name: foo
|
|
||||||
extra: true
|
|
||||||
- name: bar
|
|
||||||
extra: false
|
|
||||||
- name: meh
|
|
||||||
extra: true
|
|
||||||
|
|
||||||
list2:
|
|
||||||
- name: foo
|
|
||||||
path: /foo
|
|
||||||
- name: baz
|
|
||||||
path: /baz
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
list1:
|
|
||||||
- name: myname01
|
|
||||||
param01:
|
|
||||||
x: default_value
|
|
||||||
y: default_value
|
|
||||||
list:
|
|
||||||
- default_value
|
|
||||||
- name: myname02
|
|
||||||
param01: [1, 1, 2, 3]
|
|
||||||
|
|
||||||
list2:
|
|
||||||
- name: myname01
|
|
||||||
param01:
|
|
||||||
y: patch_value
|
|
||||||
z: patch_value
|
|
||||||
list:
|
|
||||||
- patch_value
|
|
||||||
- name: myname02
|
|
||||||
param01: [3, 4, 4, {key: value}]
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
---
|
|
||||||
- name: 1. Merge two lists by common attribute 'name'
|
|
||||||
include_vars:
|
|
||||||
dir: example-001_vars
|
|
||||||
- debug:
|
|
||||||
var: list3
|
|
||||||
when: debug|d(false)|bool
|
|
||||||
- template:
|
|
||||||
src: list3.out.j2
|
|
||||||
dest: example-001.out
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../default-common.yml
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
list3: "{{ list1|
|
|
||||||
community.general.lists_mergeby(list2, 'name') }}"
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
---
|
|
||||||
- name: 2. Merge two lists by common attribute 'name'
|
|
||||||
include_vars:
|
|
||||||
dir: example-002_vars
|
|
||||||
- debug:
|
|
||||||
var: list3
|
|
||||||
when: debug|d(false)|bool
|
|
||||||
- template:
|
|
||||||
src: list3.out.j2
|
|
||||||
dest: example-002.out
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../default-common.yml
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
list3: "{{ [list1, list2]|
|
|
||||||
community.general.lists_mergeby('name') }}"
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
---
|
|
||||||
- name: 3. Merge recursive by 'name', replace lists (default)
|
|
||||||
include_vars:
|
|
||||||
dir: example-003_vars
|
|
||||||
- debug:
|
|
||||||
var: list3
|
|
||||||
when: debug|d(false)|bool
|
|
||||||
- template:
|
|
||||||
src: list3.out.j2
|
|
||||||
dest: example-003.out
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../default-recursive-true.yml
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
list3: "{{ [list1, list2]|
|
|
||||||
community.general.lists_mergeby('name',
|
|
||||||
recursive=true) }}"
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
---
|
|
||||||
- name: 4. Merge recursive by 'name', keep lists
|
|
||||||
include_vars:
|
|
||||||
dir: example-004_vars
|
|
||||||
- debug:
|
|
||||||
var: list3
|
|
||||||
when: debug|d(false)|bool
|
|
||||||
- template:
|
|
||||||
src: list3.out.j2
|
|
||||||
dest: example-004.out
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../default-recursive-true.yml
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
list3: "{{ [list1, list2]|
|
|
||||||
community.general.lists_mergeby('name',
|
|
||||||
recursive=true,
|
|
||||||
list_merge='keep') }}"
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
---
|
|
||||||
- name: 5. Merge recursive by 'name', append lists
|
|
||||||
include_vars:
|
|
||||||
dir: example-005_vars
|
|
||||||
- debug:
|
|
||||||
var: list3
|
|
||||||
when: debug|d(false)|bool
|
|
||||||
- template:
|
|
||||||
src: list3.out.j2
|
|
||||||
dest: example-005.out
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../default-recursive-true.yml
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
list3: "{{ [list1, list2]|
|
|
||||||
community.general.lists_mergeby('name',
|
|
||||||
recursive=true,
|
|
||||||
list_merge='append') }}"
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
---
|
|
||||||
- name: 6. Merge recursive by 'name', prepend lists
|
|
||||||
include_vars:
|
|
||||||
dir: example-006_vars
|
|
||||||
- debug:
|
|
||||||
var: list3
|
|
||||||
when: debug|d(false)|bool
|
|
||||||
- template:
|
|
||||||
src: list3.out.j2
|
|
||||||
dest: example-006.out
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../default-recursive-true.yml
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
list3: "{{ [list1, list2]|
|
|
||||||
community.general.lists_mergeby('name',
|
|
||||||
recursive=true,
|
|
||||||
list_merge='prepend') }}"
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
---
|
|
||||||
- name: 7. Merge recursive by 'name', append lists 'remove present'
|
|
||||||
include_vars:
|
|
||||||
dir: example-007_vars
|
|
||||||
- debug:
|
|
||||||
var: list3
|
|
||||||
when: debug|d(false)|bool
|
|
||||||
- template:
|
|
||||||
src: list3.out.j2
|
|
||||||
dest: example-007.out
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../default-recursive-true.yml
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
list3: "{{ [list1, list2]|
|
|
||||||
community.general.lists_mergeby('name',
|
|
||||||
recursive=true,
|
|
||||||
list_merge='append_rp') }}"
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
---
|
|
||||||
- name: 8. Merge recursive by 'name', prepend lists 'remove present'
|
|
||||||
include_vars:
|
|
||||||
dir: example-008_vars
|
|
||||||
- debug:
|
|
||||||
var: list3
|
|
||||||
when: debug|d(false)|bool
|
|
||||||
- template:
|
|
||||||
src: list3.out.j2
|
|
||||||
dest: example-008.out
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../default-recursive-true.yml
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
list3: "{{ [list1, list2]|
|
|
||||||
community.general.lists_mergeby('name',
|
|
||||||
recursive=true,
|
|
||||||
list_merge='prepend_rp') }}"
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
---
|
|
||||||
examples:
|
|
||||||
- label: 'In the example below the lists are merged by the attribute ``name``:'
|
|
||||||
file: example-001_vars/list3.yml
|
|
||||||
lang: 'yaml+jinja'
|
|
||||||
- label: 'This produces:'
|
|
||||||
file: example-001.out
|
|
||||||
lang: 'yaml'
|
|
||||||
- label: 'It is possible to use a list of lists as an input of the filter:'
|
|
||||||
file: example-002_vars/list3.yml
|
|
||||||
lang: 'yaml+jinja'
|
|
||||||
- label: 'This produces the same result as in the previous example:'
|
|
||||||
file: example-002.out
|
|
||||||
lang: 'yaml'
|
|
||||||
- label: 'Example ``list_merge=replace`` (default):'
|
|
||||||
file: example-003_vars/list3.yml
|
|
||||||
lang: 'yaml+jinja'
|
|
||||||
- label: 'This produces:'
|
|
||||||
file: example-003.out
|
|
||||||
lang: 'yaml'
|
|
||||||
- label: 'Example ``list_merge=keep``:'
|
|
||||||
file: example-004_vars/list3.yml
|
|
||||||
lang: 'yaml+jinja'
|
|
||||||
- label: 'This produces:'
|
|
||||||
file: example-004.out
|
|
||||||
lang: 'yaml'
|
|
||||||
- label: 'Example ``list_merge=append``:'
|
|
||||||
file: example-005_vars/list3.yml
|
|
||||||
lang: 'yaml+jinja'
|
|
||||||
- label: 'This produces:'
|
|
||||||
file: example-005.out
|
|
||||||
lang: 'yaml'
|
|
||||||
- label: 'Example ``list_merge=prepend``:'
|
|
||||||
file: example-006_vars/list3.yml
|
|
||||||
lang: 'yaml+jinja'
|
|
||||||
- label: 'This produces:'
|
|
||||||
file: example-006.out
|
|
||||||
lang: 'yaml'
|
|
||||||
- label: 'Example ``list_merge=append_rp``:'
|
|
||||||
file: example-007_vars/list3.yml
|
|
||||||
lang: 'yaml+jinja'
|
|
||||||
- label: 'This produces:'
|
|
||||||
file: example-007.out
|
|
||||||
lang: 'yaml'
|
|
||||||
- label: 'Example ``list_merge=prepend_rp``:'
|
|
||||||
file: example-008_vars/list3.yml
|
|
||||||
lang: 'yaml+jinja'
|
|
||||||
- label: 'This produces:'
|
|
||||||
file: example-008.out
|
|
||||||
lang: 'yaml'
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
{% for i in examples %}
|
|
||||||
{{ i.label }}
|
|
||||||
|
|
||||||
.. code-block:: {{ i.lang }}
|
|
||||||
|
|
||||||
{{ lookup('file', i.file)|indent(2) }}
|
|
||||||
|
|
||||||
{% endfor %}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
Merging lists of dictionaries
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
If you have two or more lists of dictionaries and want to combine them into a list of merged dictionaries, where the dictionaries are merged by an attribute, you can use the ``lists_mergeby`` filter.
|
|
||||||
|
|
||||||
.. note:: The output of the examples in this section use the YAML callback plugin. Quoting: "Ansible output that can be quite a bit easier to read than the default JSON formatting." See :ref:`the documentation for the community.general.yaml callback plugin <ansible_collections.community.general.yaml_callback>`.
|
|
||||||
|
|
||||||
Let us use the lists below in the following examples:
|
|
||||||
|
|
||||||
.. code-block:: yaml
|
|
||||||
|
|
||||||
{{ lookup('file', 'default-common.yml')|indent(2) }}
|
|
||||||
|
|
||||||
{% for i in examples[0:2] %}
|
|
||||||
{{ i.label }}
|
|
||||||
|
|
||||||
.. code-block:: {{ i.lang }}
|
|
||||||
|
|
||||||
{{ lookup('file', i.file)|indent(2) }}
|
|
||||||
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
.. versionadded:: 2.0.0
|
|
||||||
|
|
||||||
{% for i in examples[2:4] %}
|
|
||||||
{{ i.label }}
|
|
||||||
|
|
||||||
.. code-block:: {{ i.lang }}
|
|
||||||
|
|
||||||
{{ lookup('file', i.file)|indent(2) }}
|
|
||||||
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
The filter also accepts two optional parameters: ``recursive`` and ``list_merge``. These parameters are only supported when used with ansible-base 2.10 or ansible-core, but not with Ansible 2.9. This is available since community.general 4.4.0.
|
|
||||||
|
|
||||||
**recursive**
|
|
||||||
Is a boolean, default to ``False``. Should the ``community.general.lists_mergeby`` recursively merge nested hashes. Note: It does not depend on the value of the ``hash_behaviour`` setting in ``ansible.cfg``.
|
|
||||||
|
|
||||||
**list_merge**
|
|
||||||
Is a string, its possible values are ``replace`` (default), ``keep``, ``append``, ``prepend``, ``append_rp`` or ``prepend_rp``. It modifies the behaviour of ``community.general.lists_mergeby`` when the hashes to merge contain arrays/lists.
|
|
||||||
|
|
||||||
The examples below set ``recursive=true`` and display the differences among all six options of ``list_merge``. Functionality of the parameters is exactly the same as in the filter ``combine``. See :ref:`Combining hashes/dictionaries <combine_filter>` to learn details about these options.
|
|
||||||
|
|
||||||
Let us use the lists below in the following examples
|
|
||||||
|
|
||||||
.. code-block:: yaml
|
|
||||||
|
|
||||||
{{ lookup('file', 'default-recursive-true.yml')|indent(2) }}
|
|
||||||
|
|
||||||
{% for i in examples[4:16] %}
|
|
||||||
{{ i.label }}
|
|
||||||
|
|
||||||
.. code-block:: {{ i.lang }}
|
|
||||||
|
|
||||||
{{ lookup('file', i.file)|indent(2) }}
|
|
||||||
|
|
||||||
{% endfor %}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
list3:
|
|
||||||
{{ list3|to_nice_yaml(indent=0) }}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
---
|
|
||||||
|
|
||||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
# 1) Run all examples and create example-XXX.out
|
|
||||||
# shell> ansible-playbook playbook.yml -e examples=true
|
|
||||||
#
|
|
||||||
# 2) Optionally, for testing, create examples_all.rst
|
|
||||||
# shell> ansible-playbook playbook.yml -e examples_all=true
|
|
||||||
#
|
|
||||||
# 3) Create docs REST files
|
|
||||||
# shell> ansible-playbook playbook.yml -e merging_lists_of_dictionaries=true
|
|
||||||
#
|
|
||||||
# Notes:
|
|
||||||
# * Use YAML callback, e.g. set ANSIBLE_STDOUT_CALLBACK=community.general.yaml
|
|
||||||
# * Use sphinx-view to render and review the REST files
|
|
||||||
# shell> sphinx-view <path_to_helper>/examples_all.rst
|
|
||||||
# * Proofread and copy completed docs *.rst files into the directory rst.
|
|
||||||
# * Then delete the *.rst and *.out files from this directory. Do not
|
|
||||||
# add *.rst and *.out in this directory to the version control.
|
|
||||||
#
|
|
||||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
# community.general/docs/docsite/helper/lists_mergeby/playbook.yml
|
|
||||||
|
|
||||||
- hosts: localhost
|
|
||||||
gather_facts: false
|
|
||||||
tasks:
|
|
||||||
|
|
||||||
- block:
|
|
||||||
- import_tasks: example-001.yml
|
|
||||||
tags: t001
|
|
||||||
- import_tasks: example-002.yml
|
|
||||||
tags: t002
|
|
||||||
- import_tasks: example-003.yml
|
|
||||||
tags: t003
|
|
||||||
- import_tasks: example-004.yml
|
|
||||||
tags: t004
|
|
||||||
- import_tasks: example-005.yml
|
|
||||||
tags: t005
|
|
||||||
- import_tasks: example-006.yml
|
|
||||||
tags: t006
|
|
||||||
- import_tasks: example-007.yml
|
|
||||||
tags: t007
|
|
||||||
- import_tasks: example-008.yml
|
|
||||||
tags: t008
|
|
||||||
when: examples|d(false)|bool
|
|
||||||
|
|
||||||
- block:
|
|
||||||
- include_vars: examples.yml
|
|
||||||
- template:
|
|
||||||
src: examples_all.rst.j2
|
|
||||||
dest: examples_all.rst
|
|
||||||
when: examples_all|d(false)|bool
|
|
||||||
|
|
||||||
- block:
|
|
||||||
- include_vars: examples.yml
|
|
||||||
- template:
|
|
||||||
src: filter_guide_abstract_informations_merging_lists_of_dictionaries.rst.j2
|
|
||||||
dest: filter_guide_abstract_informations_merging_lists_of_dictionaries.rst
|
|
||||||
when: merging_lists_of_dictionaries|d(false)|bool
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
---
|
|
||||||
edit_on_github:
|
|
||||||
repository: ansible-collections/community.general
|
|
||||||
branch: main
|
|
||||||
path_prefix: ''
|
|
||||||
|
|
||||||
extra_links:
|
|
||||||
- description: Submit a bug report
|
|
||||||
url: https://github.com/ansible-collections/community.general/issues/new?assignees=&labels=&template=bug_report.yml
|
|
||||||
- description: Request a feature
|
|
||||||
url: https://github.com/ansible-collections/community.general/issues/new?assignees=&labels=&template=feature_request.yml
|
|
||||||
|
|
||||||
communication:
|
|
||||||
matrix_rooms:
|
|
||||||
- topic: General usage and support questions
|
|
||||||
room: '#users:ansible.im'
|
|
||||||
irc_channels:
|
|
||||||
- topic: General usage and support questions
|
|
||||||
network: Libera
|
|
||||||
channel: '#ansible'
|
|
||||||
mailing_lists:
|
|
||||||
- topic: Ansible Project List
|
|
||||||
url: https://groups.google.com/g/ansible-project
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
|
|
||||||
.. _ansible_collections.community.general.docsite.filter_guide:
|
|
||||||
|
|
||||||
community.general Filter Guide
|
|
||||||
==============================
|
|
||||||
|
|
||||||
The :ref:`community.general collection <plugins_in_community.general>` offers several useful filter plugins.
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 2
|
|
||||||
|
|
||||||
filter_guide_paths
|
|
||||||
filter_guide_abstract_informations
|
|
||||||
filter_guide_working_with_times
|
|
||||||
filter_guide_working_with_versions
|
|
||||||
filter_guide_creating_identifiers
|
|
||||||
filter_guide_conversions
|
|
||||||
filter_guide_selecting_json_data
|
|
||||||
filter_guide_working_with_unicode
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
Abstract transformations
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 1
|
|
||||||
|
|
||||||
filter_guide_abstract_informations_dictionaries
|
|
||||||
filter_guide_abstract_informations_grouping
|
|
||||||
filter_guide_abstract_informations_merging_lists_of_dictionaries
|
|
||||||
filter_guide_abstract_informations_counting_elements_in_sequence
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
Counting elements in a sequence
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
The ``community.general.counter`` filter plugin allows you to count (hashable) elements in a sequence. Elements are returned as dictionary keys and their counts are stored as dictionary values.
|
|
||||||
|
|
||||||
.. code-block:: yaml+jinja
|
|
||||||
|
|
||||||
- name: Count character occurrences in a string
|
|
||||||
debug:
|
|
||||||
msg: "{{ 'abccbaabca' | community.general.counter }}"
|
|
||||||
|
|
||||||
- name: Count items in a list
|
|
||||||
debug:
|
|
||||||
msg: "{{ ['car', 'car', 'bike', 'plane', 'bike'] | community.general.counter }}"
|
|
||||||
|
|
||||||
This produces:
|
|
||||||
|
|
||||||
.. code-block:: ansible-output
|
|
||||||
|
|
||||||
TASK [Count character occurrences in a string] ********************************************
|
|
||||||
ok: [localhost] => {
|
|
||||||
"msg": {
|
|
||||||
"a": 4,
|
|
||||||
"b": 3,
|
|
||||||
"c": 3
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TASK [Count items in a list] **************************************************************
|
|
||||||
ok: [localhost] => {
|
|
||||||
"msg": {
|
|
||||||
"bike": 2,
|
|
||||||
"car": 2,
|
|
||||||
"plane": 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
This plugin is useful for selecting resources based on current allocation:
|
|
||||||
|
|
||||||
.. code-block:: yaml+jinja
|
|
||||||
|
|
||||||
- name: Get ID of SCSI controller(s) with less than 4 disks attached and choose the one with the least disks
|
|
||||||
debug:
|
|
||||||
msg: >-
|
|
||||||
{{
|
|
||||||
( disks | dict2items | map(attribute='value.adapter') | list
|
|
||||||
| community.general.counter | dict2items
|
|
||||||
| rejectattr('value', '>=', 4) | sort(attribute='value') | first
|
|
||||||
).key
|
|
||||||
}}
|
|
||||||
vars:
|
|
||||||
disks:
|
|
||||||
sda:
|
|
||||||
adapter: scsi_1
|
|
||||||
sdb:
|
|
||||||
adapter: scsi_1
|
|
||||||
sdc:
|
|
||||||
adapter: scsi_1
|
|
||||||
sdd:
|
|
||||||
adapter: scsi_1
|
|
||||||
sde:
|
|
||||||
adapter: scsi_2
|
|
||||||
sdf:
|
|
||||||
adapter: scsi_3
|
|
||||||
sdg:
|
|
||||||
adapter: scsi_3
|
|
||||||
|
|
||||||
This produces:
|
|
||||||
|
|
||||||
.. code-block:: ansible-output
|
|
||||||
|
|
||||||
TASK [Get ID of SCSI controller(s) with less than 4 disks attached and choose the one with the least disks]
|
|
||||||
ok: [localhost] => {
|
|
||||||
"msg": "scsi_2"
|
|
||||||
}
|
|
||||||
|
|
||||||
.. versionadded:: 4.3.0
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
Dictionaries
|
|
||||||
^^^^^^^^^^^^
|
|
||||||
|
|
||||||
You can use the ``dict_kv`` filter to create a single-entry dictionary with ``value | community.general.dict_kv(key)``:
|
|
||||||
|
|
||||||
.. code-block:: yaml+jinja
|
|
||||||
|
|
||||||
- name: Create a single-entry dictionary
|
|
||||||
debug:
|
|
||||||
msg: "{{ myvar | community.general.dict_kv('thatsmyvar') }}"
|
|
||||||
vars:
|
|
||||||
myvar: myvalue
|
|
||||||
|
|
||||||
- name: Create a list of dictionaries where the 'server' field is taken from a list
|
|
||||||
debug:
|
|
||||||
msg: >-
|
|
||||||
{{ myservers | map('community.general.dict_kv', 'server')
|
|
||||||
| map('combine', common_config) }}
|
|
||||||
vars:
|
|
||||||
common_config:
|
|
||||||
type: host
|
|
||||||
database: all
|
|
||||||
myservers:
|
|
||||||
- server1
|
|
||||||
- server2
|
|
||||||
|
|
||||||
This produces:
|
|
||||||
|
|
||||||
.. code-block:: ansible-output
|
|
||||||
|
|
||||||
TASK [Create a single-entry dictionary] **************************************************
|
|
||||||
ok: [localhost] => {
|
|
||||||
"msg": {
|
|
||||||
"thatsmyvar": "myvalue"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TASK [Create a list of dictionaries where the 'server' field is taken from a list] *******
|
|
||||||
ok: [localhost] => {
|
|
||||||
"msg": [
|
|
||||||
{
|
|
||||||
"database": "all",
|
|
||||||
"server": "server1",
|
|
||||||
"type": "host"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"database": "all",
|
|
||||||
"server": "server2",
|
|
||||||
"type": "host"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
.. versionadded:: 2.0.0
|
|
||||||
|
|
||||||
If you need to convert a list of key-value pairs to a dictionary, you can use the ``dict`` function. Unfortunately, this function cannot be used with ``map``. For this, the ``community.general.dict`` filter can be used:
|
|
||||||
|
|
||||||
.. code-block:: yaml+jinja
|
|
||||||
|
|
||||||
- name: Create a dictionary with the dict function
|
|
||||||
debug:
|
|
||||||
msg: "{{ dict([[1, 2], ['a', 'b']]) }}"
|
|
||||||
|
|
||||||
- name: Create a dictionary with the community.general.dict filter
|
|
||||||
debug:
|
|
||||||
msg: "{{ [[1, 2], ['a', 'b']] | community.general.dict }}"
|
|
||||||
|
|
||||||
- name: Create a list of dictionaries with map and the community.general.dict filter
|
|
||||||
debug:
|
|
||||||
msg: >-
|
|
||||||
{{ values | map('zip', ['k1', 'k2', 'k3'])
|
|
||||||
| map('map', 'reverse')
|
|
||||||
| map('community.general.dict') }}
|
|
||||||
vars:
|
|
||||||
values:
|
|
||||||
- - foo
|
|
||||||
- 23
|
|
||||||
- a
|
|
||||||
- - bar
|
|
||||||
- 42
|
|
||||||
- b
|
|
||||||
|
|
||||||
This produces:
|
|
||||||
|
|
||||||
.. code-block:: ansible-output
|
|
||||||
|
|
||||||
TASK [Create a dictionary with the dict function] ****************************************
|
|
||||||
ok: [localhost] => {
|
|
||||||
"msg": {
|
|
||||||
"1": 2,
|
|
||||||
"a": "b"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TASK [Create a dictionary with the community.general.dict filter] ************************
|
|
||||||
ok: [localhost] => {
|
|
||||||
"msg": {
|
|
||||||
"1": 2,
|
|
||||||
"a": "b"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TASK [Create a list of dictionaries with map and the community.general.dict filter] ******
|
|
||||||
ok: [localhost] => {
|
|
||||||
"msg": [
|
|
||||||
{
|
|
||||||
"k1": "foo",
|
|
||||||
"k2": 23,
|
|
||||||
"k3": "a"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"k1": "bar",
|
|
||||||
"k2": 42,
|
|
||||||
"k3": "b"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
.. versionadded:: 3.0.0
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
Grouping
|
|
||||||
^^^^^^^^
|
|
||||||
|
|
||||||
If you have a list of dictionaries, the Jinja2 ``groupby`` filter allows to group the list by an attribute. This results in a list of ``(grouper, list)`` namedtuples, where ``list`` contains all dictionaries where the selected attribute equals ``grouper``. If you know that for every ``grouper``, there will be a most one entry in that list, you can use the ``community.general.groupby_as_dict`` filter to convert the original list into a dictionary which maps ``grouper`` to the corresponding dictionary.
|
|
||||||
|
|
||||||
One example is ``ansible_facts.mounts``, which is a list of dictionaries where each has one ``device`` element to indicate the device which is mounted. Therefore, ``ansible_facts.mounts | community.general.groupby_as_dict('device')`` is a dictionary mapping a device to the mount information:
|
|
||||||
|
|
||||||
.. code-block:: yaml+jinja
|
|
||||||
|
|
||||||
- name: Output mount facts grouped by device name
|
|
||||||
debug:
|
|
||||||
var: ansible_facts.mounts | community.general.groupby_as_dict('device')
|
|
||||||
|
|
||||||
- name: Output mount facts grouped by mount point
|
|
||||||
debug:
|
|
||||||
var: ansible_facts.mounts | community.general.groupby_as_dict('mount')
|
|
||||||
|
|
||||||
This produces:
|
|
||||||
|
|
||||||
.. code-block:: ansible-output
|
|
||||||
|
|
||||||
TASK [Output mount facts grouped by device name] ******************************************
|
|
||||||
ok: [localhost] => {
|
|
||||||
"ansible_facts.mounts | community.general.groupby_as_dict('device')": {
|
|
||||||
"/dev/sda1": {
|
|
||||||
"block_available": 2000,
|
|
||||||
"block_size": 4096,
|
|
||||||
"block_total": 2345,
|
|
||||||
"block_used": 345,
|
|
||||||
"device": "/dev/sda1",
|
|
||||||
"fstype": "ext4",
|
|
||||||
"inode_available": 500,
|
|
||||||
"inode_total": 512,
|
|
||||||
"inode_used": 12,
|
|
||||||
"mount": "/boot",
|
|
||||||
"options": "rw,relatime,data=ordered",
|
|
||||||
"size_available": 56821,
|
|
||||||
"size_total": 543210,
|
|
||||||
"uuid": "ab31cade-d9c1-484d-8482-8a4cbee5241a"
|
|
||||||
},
|
|
||||||
"/dev/sda2": {
|
|
||||||
"block_available": 1234,
|
|
||||||
"block_size": 4096,
|
|
||||||
"block_total": 12345,
|
|
||||||
"block_used": 11111,
|
|
||||||
"device": "/dev/sda2",
|
|
||||||
"fstype": "ext4",
|
|
||||||
"inode_available": 1111,
|
|
||||||
"inode_total": 1234,
|
|
||||||
"inode_used": 123,
|
|
||||||
"mount": "/",
|
|
||||||
"options": "rw,relatime",
|
|
||||||
"size_available": 42143,
|
|
||||||
"size_total": 543210,
|
|
||||||
"uuid": "abcdef01-2345-6789-0abc-def012345678"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TASK [Output mount facts grouped by mount point] ******************************************
|
|
||||||
ok: [localhost] => {
|
|
||||||
"ansible_facts.mounts | community.general.groupby_as_dict('mount')": {
|
|
||||||
"/": {
|
|
||||||
"block_available": 1234,
|
|
||||||
"block_size": 4096,
|
|
||||||
"block_total": 12345,
|
|
||||||
"block_used": 11111,
|
|
||||||
"device": "/dev/sda2",
|
|
||||||
"fstype": "ext4",
|
|
||||||
"inode_available": 1111,
|
|
||||||
"inode_total": 1234,
|
|
||||||
"inode_used": 123,
|
|
||||||
"mount": "/",
|
|
||||||
"options": "rw,relatime",
|
|
||||||
"size_available": 42143,
|
|
||||||
"size_total": 543210,
|
|
||||||
"uuid": "bdf50b7d-4859-40af-8665-c637ee7a7808"
|
|
||||||
},
|
|
||||||
"/boot": {
|
|
||||||
"block_available": 2000,
|
|
||||||
"block_size": 4096,
|
|
||||||
"block_total": 2345,
|
|
||||||
"block_used": 345,
|
|
||||||
"device": "/dev/sda1",
|
|
||||||
"fstype": "ext4",
|
|
||||||
"inode_available": 500,
|
|
||||||
"inode_total": 512,
|
|
||||||
"inode_used": 12,
|
|
||||||
"mount": "/boot",
|
|
||||||
"options": "rw,relatime,data=ordered",
|
|
||||||
"size_available": 56821,
|
|
||||||
"size_total": 543210,
|
|
||||||
"uuid": "ab31cade-d9c1-484d-8482-8a4cbee5241a"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.. versionadded: 3.0.0
|
|
||||||
@@ -1,292 +0,0 @@
|
|||||||
Merging lists of dictionaries
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
If you have two or more lists of dictionaries and want to combine them into a list of merged dictionaries, where the dictionaries are merged by an attribute, you can use the ``lists_mergeby`` filter.
|
|
||||||
|
|
||||||
.. note:: The output of the examples in this section use the YAML callback plugin. Quoting: "Ansible output that can be quite a bit easier to read than the default JSON formatting." See :ref:`the documentation for the community.general.yaml callback plugin <ansible_collections.community.general.yaml_callback>`.
|
|
||||||
|
|
||||||
Let us use the lists below in the following examples:
|
|
||||||
|
|
||||||
.. code-block:: yaml
|
|
||||||
|
|
||||||
list1:
|
|
||||||
- name: foo
|
|
||||||
extra: true
|
|
||||||
- name: bar
|
|
||||||
extra: false
|
|
||||||
- name: meh
|
|
||||||
extra: true
|
|
||||||
|
|
||||||
list2:
|
|
||||||
- name: foo
|
|
||||||
path: /foo
|
|
||||||
- name: baz
|
|
||||||
path: /baz
|
|
||||||
|
|
||||||
In the example below the lists are merged by the attribute ``name``:
|
|
||||||
|
|
||||||
.. code-block:: yaml+jinja
|
|
||||||
|
|
||||||
list3: "{{ list1|
|
|
||||||
community.general.lists_mergeby(list2, 'name') }}"
|
|
||||||
|
|
||||||
This produces:
|
|
||||||
|
|
||||||
.. code-block:: yaml
|
|
||||||
|
|
||||||
list3:
|
|
||||||
- extra: false
|
|
||||||
name: bar
|
|
||||||
- name: baz
|
|
||||||
path: /baz
|
|
||||||
- extra: true
|
|
||||||
name: foo
|
|
||||||
path: /foo
|
|
||||||
- extra: true
|
|
||||||
name: meh
|
|
||||||
|
|
||||||
|
|
||||||
.. versionadded:: 2.0.0
|
|
||||||
|
|
||||||
It is possible to use a list of lists as an input of the filter:
|
|
||||||
|
|
||||||
.. code-block:: yaml+jinja
|
|
||||||
|
|
||||||
list3: "{{ [list1, list2]|
|
|
||||||
community.general.lists_mergeby('name') }}"
|
|
||||||
|
|
||||||
This produces the same result as in the previous example:
|
|
||||||
|
|
||||||
.. code-block:: yaml
|
|
||||||
|
|
||||||
list3:
|
|
||||||
- extra: false
|
|
||||||
name: bar
|
|
||||||
- name: baz
|
|
||||||
path: /baz
|
|
||||||
- extra: true
|
|
||||||
name: foo
|
|
||||||
path: /foo
|
|
||||||
- extra: true
|
|
||||||
name: meh
|
|
||||||
|
|
||||||
|
|
||||||
The filter also accepts two optional parameters: ``recursive`` and ``list_merge``. These parameters are only supported when used with ansible-base 2.10 or ansible-core, but not with Ansible 2.9. This is available since community.general 4.4.0.
|
|
||||||
|
|
||||||
**recursive**
|
|
||||||
Is a boolean, default to ``False``. Should the ``community.general.lists_mergeby`` recursively merge nested hashes. Note: It does not depend on the value of the ``hash_behaviour`` setting in ``ansible.cfg``.
|
|
||||||
|
|
||||||
**list_merge**
|
|
||||||
Is a string, its possible values are ``replace`` (default), ``keep``, ``append``, ``prepend``, ``append_rp`` or ``prepend_rp``. It modifies the behaviour of ``community.general.lists_mergeby`` when the hashes to merge contain arrays/lists.
|
|
||||||
|
|
||||||
The examples below set ``recursive=true`` and display the differences among all six options of ``list_merge``. Functionality of the parameters is exactly the same as in the filter ``combine``. See :ref:`Combining hashes/dictionaries <combine_filter>` to learn details about these options.
|
|
||||||
|
|
||||||
Let us use the lists below in the following examples
|
|
||||||
|
|
||||||
.. code-block:: yaml
|
|
||||||
|
|
||||||
list1:
|
|
||||||
- name: myname01
|
|
||||||
param01:
|
|
||||||
x: default_value
|
|
||||||
y: default_value
|
|
||||||
list:
|
|
||||||
- default_value
|
|
||||||
- name: myname02
|
|
||||||
param01: [1, 1, 2, 3]
|
|
||||||
|
|
||||||
list2:
|
|
||||||
- name: myname01
|
|
||||||
param01:
|
|
||||||
y: patch_value
|
|
||||||
z: patch_value
|
|
||||||
list:
|
|
||||||
- patch_value
|
|
||||||
- name: myname02
|
|
||||||
param01: [3, 4, 4, {key: value}]
|
|
||||||
|
|
||||||
Example ``list_merge=replace`` (default):
|
|
||||||
|
|
||||||
.. code-block:: yaml+jinja
|
|
||||||
|
|
||||||
list3: "{{ [list1, list2]|
|
|
||||||
community.general.lists_mergeby('name',
|
|
||||||
recursive=true) }}"
|
|
||||||
|
|
||||||
This produces:
|
|
||||||
|
|
||||||
.. code-block:: yaml
|
|
||||||
|
|
||||||
list3:
|
|
||||||
- name: myname01
|
|
||||||
param01:
|
|
||||||
list:
|
|
||||||
- patch_value
|
|
||||||
x: default_value
|
|
||||||
y: patch_value
|
|
||||||
z: patch_value
|
|
||||||
- name: myname02
|
|
||||||
param01:
|
|
||||||
- 3
|
|
||||||
- 4
|
|
||||||
- 4
|
|
||||||
- key: value
|
|
||||||
|
|
||||||
Example ``list_merge=keep``:
|
|
||||||
|
|
||||||
.. code-block:: yaml+jinja
|
|
||||||
|
|
||||||
list3: "{{ [list1, list2]|
|
|
||||||
community.general.lists_mergeby('name',
|
|
||||||
recursive=true,
|
|
||||||
list_merge='keep') }}"
|
|
||||||
|
|
||||||
This produces:
|
|
||||||
|
|
||||||
.. code-block:: yaml
|
|
||||||
|
|
||||||
list3:
|
|
||||||
- name: myname01
|
|
||||||
param01:
|
|
||||||
list:
|
|
||||||
- default_value
|
|
||||||
x: default_value
|
|
||||||
y: patch_value
|
|
||||||
z: patch_value
|
|
||||||
- name: myname02
|
|
||||||
param01:
|
|
||||||
- 1
|
|
||||||
- 1
|
|
||||||
- 2
|
|
||||||
- 3
|
|
||||||
|
|
||||||
Example ``list_merge=append``:
|
|
||||||
|
|
||||||
.. code-block:: yaml+jinja
|
|
||||||
|
|
||||||
list3: "{{ [list1, list2]|
|
|
||||||
community.general.lists_mergeby('name',
|
|
||||||
recursive=true,
|
|
||||||
list_merge='append') }}"
|
|
||||||
|
|
||||||
This produces:
|
|
||||||
|
|
||||||
.. code-block:: yaml
|
|
||||||
|
|
||||||
list3:
|
|
||||||
- name: myname01
|
|
||||||
param01:
|
|
||||||
list:
|
|
||||||
- default_value
|
|
||||||
- patch_value
|
|
||||||
x: default_value
|
|
||||||
y: patch_value
|
|
||||||
z: patch_value
|
|
||||||
- name: myname02
|
|
||||||
param01:
|
|
||||||
- 1
|
|
||||||
- 1
|
|
||||||
- 2
|
|
||||||
- 3
|
|
||||||
- 3
|
|
||||||
- 4
|
|
||||||
- 4
|
|
||||||
- key: value
|
|
||||||
|
|
||||||
Example ``list_merge=prepend``:
|
|
||||||
|
|
||||||
.. code-block:: yaml+jinja
|
|
||||||
|
|
||||||
list3: "{{ [list1, list2]|
|
|
||||||
community.general.lists_mergeby('name',
|
|
||||||
recursive=true,
|
|
||||||
list_merge='prepend') }}"
|
|
||||||
|
|
||||||
This produces:
|
|
||||||
|
|
||||||
.. code-block:: yaml
|
|
||||||
|
|
||||||
list3:
|
|
||||||
- name: myname01
|
|
||||||
param01:
|
|
||||||
list:
|
|
||||||
- patch_value
|
|
||||||
- default_value
|
|
||||||
x: default_value
|
|
||||||
y: patch_value
|
|
||||||
z: patch_value
|
|
||||||
- name: myname02
|
|
||||||
param01:
|
|
||||||
- 3
|
|
||||||
- 4
|
|
||||||
- 4
|
|
||||||
- key: value
|
|
||||||
- 1
|
|
||||||
- 1
|
|
||||||
- 2
|
|
||||||
- 3
|
|
||||||
|
|
||||||
Example ``list_merge=append_rp``:
|
|
||||||
|
|
||||||
.. code-block:: yaml+jinja
|
|
||||||
|
|
||||||
list3: "{{ [list1, list2]|
|
|
||||||
community.general.lists_mergeby('name',
|
|
||||||
recursive=true,
|
|
||||||
list_merge='append_rp') }}"
|
|
||||||
|
|
||||||
This produces:
|
|
||||||
|
|
||||||
.. code-block:: yaml
|
|
||||||
|
|
||||||
list3:
|
|
||||||
- name: myname01
|
|
||||||
param01:
|
|
||||||
list:
|
|
||||||
- default_value
|
|
||||||
- patch_value
|
|
||||||
x: default_value
|
|
||||||
y: patch_value
|
|
||||||
z: patch_value
|
|
||||||
- name: myname02
|
|
||||||
param01:
|
|
||||||
- 1
|
|
||||||
- 1
|
|
||||||
- 2
|
|
||||||
- 3
|
|
||||||
- 4
|
|
||||||
- 4
|
|
||||||
- key: value
|
|
||||||
|
|
||||||
Example ``list_merge=prepend_rp``:
|
|
||||||
|
|
||||||
.. code-block:: yaml+jinja
|
|
||||||
|
|
||||||
list3: "{{ [list1, list2]|
|
|
||||||
community.general.lists_mergeby('name',
|
|
||||||
recursive=true,
|
|
||||||
list_merge='prepend_rp') }}"
|
|
||||||
|
|
||||||
This produces:
|
|
||||||
|
|
||||||
.. code-block:: yaml
|
|
||||||
|
|
||||||
list3:
|
|
||||||
- name: myname01
|
|
||||||
param01:
|
|
||||||
list:
|
|
||||||
- patch_value
|
|
||||||
- default_value
|
|
||||||
x: default_value
|
|
||||||
y: patch_value
|
|
||||||
z: patch_value
|
|
||||||
- name: myname02
|
|
||||||
param01:
|
|
||||||
- 3
|
|
||||||
- 4
|
|
||||||
- 4
|
|
||||||
- key: value
|
|
||||||
- 1
|
|
||||||
- 1
|
|
||||||
- 2
|
|
||||||
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
Conversions
|
|
||||||
-----------
|
|
||||||
|
|
||||||
Parsing CSV files
|
|
||||||
^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
Ansible offers the :ref:`community.general.read_csv module <ansible_collections.community.general.read_csv_module>` to read CSV files. Sometimes you need to convert strings to CSV files instead. For this, the ``from_csv`` filter exists.
|
|
||||||
|
|
||||||
.. code-block:: yaml+jinja
|
|
||||||
|
|
||||||
- name: "Parse CSV from string"
|
|
||||||
debug:
|
|
||||||
msg: "{{ csv_string | community.general.from_csv }}"
|
|
||||||
vars:
|
|
||||||
csv_string: |
|
|
||||||
foo,bar,baz
|
|
||||||
1,2,3
|
|
||||||
you,this,then
|
|
||||||
|
|
||||||
This produces:
|
|
||||||
|
|
||||||
.. code-block:: ansible-output
|
|
||||||
|
|
||||||
TASK [Parse CSV from string] **************************************************************
|
|
||||||
ok: [localhost] => {
|
|
||||||
"msg": [
|
|
||||||
{
|
|
||||||
"bar": "2",
|
|
||||||
"baz": "3",
|
|
||||||
"foo": "1"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"bar": "this",
|
|
||||||
"baz": "then",
|
|
||||||
"foo": "you"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
The ``from_csv`` filter has several keyword arguments to control its behavior:
|
|
||||||
|
|
||||||
:dialect: Dialect of the CSV file. Default is ``excel``. Other possible choices are ``excel-tab`` and ``unix``. If one of ``delimiter``, ``skipinitialspace`` or ``strict`` is specified, ``dialect`` is ignored.
|
|
||||||
:fieldnames: A set of column names to use. If not provided, the first line of the CSV is assumed to contain the column names.
|
|
||||||
:delimiter: Sets the delimiter to use. Default depends on the dialect used.
|
|
||||||
:skipinitialspace: Set to ``true`` to ignore space directly after the delimiter. Default depends on the dialect used (usually ``false``).
|
|
||||||
:strict: Set to ``true`` to error out on invalid CSV input.
|
|
||||||
|
|
||||||
.. versionadded: 3.0.0
|
|
||||||
|
|
||||||
Converting to JSON
|
|
||||||
^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
`JC <https://pypi.org/project/jc/>`_ is a CLI tool and Python library which allows to interpret output of various CLI programs as JSON. It is also available as a filter in community.general. This filter needs the `jc Python library <https://pypi.org/project/jc/>`_ installed on the controller.
|
|
||||||
|
|
||||||
.. code-block:: yaml+jinja
|
|
||||||
|
|
||||||
- name: Run 'ls' to list files in /
|
|
||||||
command: ls /
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- name: Parse the ls output
|
|
||||||
debug:
|
|
||||||
msg: "{{ result.stdout | community.general.jc('ls') }}"
|
|
||||||
|
|
||||||
This produces:
|
|
||||||
|
|
||||||
.. code-block:: ansible-output
|
|
||||||
|
|
||||||
TASK [Run 'ls' to list files in /] ********************************************************
|
|
||||||
changed: [localhost]
|
|
||||||
|
|
||||||
TASK [Parse the ls output] ****************************************************************
|
|
||||||
ok: [localhost] => {
|
|
||||||
"msg": [
|
|
||||||
{
|
|
||||||
"filename": "bin"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "boot"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "dev"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "etc"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "home"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "lib"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "proc"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "root"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "run"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "tmp"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
.. versionadded: 2.0.0
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
Creating identifiers
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
The following filters allow to create identifiers.
|
|
||||||
|
|
||||||
Hashids
|
|
||||||
^^^^^^^
|
|
||||||
|
|
||||||
`Hashids <https://hashids.org/>`_ allow to convert sequences of integers to short unique string identifiers. This filter needs the `hashids Python library <https://pypi.org/project/hashids/>`_ installed on the controller.
|
|
||||||
|
|
||||||
.. code-block:: yaml+jinja
|
|
||||||
|
|
||||||
- name: "Create hashid"
|
|
||||||
debug:
|
|
||||||
msg: "{{ [1234, 5, 6] | community.general.hashids_encode }}"
|
|
||||||
|
|
||||||
- name: "Decode hashid"
|
|
||||||
debug:
|
|
||||||
msg: "{{ 'jm2Cytn' | community.general.hashids_decode }}"
|
|
||||||
|
|
||||||
This produces:
|
|
||||||
|
|
||||||
.. code-block:: ansible-output
|
|
||||||
|
|
||||||
TASK [Create hashid] **********************************************************************
|
|
||||||
ok: [localhost] => {
|
|
||||||
"msg": "jm2Cytn"
|
|
||||||
}
|
|
||||||
|
|
||||||
TASK [Decode hashid] **********************************************************************
|
|
||||||
ok: [localhost] => {
|
|
||||||
"msg": [
|
|
||||||
1234,
|
|
||||||
5,
|
|
||||||
6
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
The hashids filters accept keyword arguments to allow fine-tuning the hashids generated:
|
|
||||||
|
|
||||||
:salt: String to use as salt when hashing.
|
|
||||||
:alphabet: String of 16 or more unique characters to produce a hash.
|
|
||||||
:min_length: Minimum length of hash produced.
|
|
||||||
|
|
||||||
.. versionadded: 3.0.0
|
|
||||||
|
|
||||||
Random MACs
|
|
||||||
^^^^^^^^^^^
|
|
||||||
|
|
||||||
You can use the ``random_mac`` filter to complete a partial `MAC address <https://en.wikipedia.org/wiki/MAC_address>`_ to a random 6-byte MAC address.
|
|
||||||
|
|
||||||
.. code-block:: yaml+jinja
|
|
||||||
|
|
||||||
- name: "Create a random MAC starting with ff:"
|
|
||||||
debug:
|
|
||||||
msg: "{{ 'FF' | community.general.random_mac }}"
|
|
||||||
|
|
||||||
- name: "Create a random MAC starting with 00:11:22:"
|
|
||||||
debug:
|
|
||||||
msg: "{{ '00:11:22' | community.general.random_mac }}"
|
|
||||||
|
|
||||||
This produces:
|
|
||||||
|
|
||||||
.. code-block:: ansible-output
|
|
||||||
|
|
||||||
TASK [Create a random MAC starting with ff:] **********************************************
|
|
||||||
ok: [localhost] => {
|
|
||||||
"msg": "ff:69:d3:78:7f:b4"
|
|
||||||
}
|
|
||||||
|
|
||||||
TASK [Create a random MAC starting with 00:11:22:] ****************************************
|
|
||||||
ok: [localhost] => {
|
|
||||||
"msg": "00:11:22:71:5d:3b"
|
|
||||||
}
|
|
||||||
|
|
||||||
You can also initialize the random number generator from a seed to create random-but-idempotent MAC addresses:
|
|
||||||
|
|
||||||
.. code-block:: yaml+jinja
|
|
||||||
|
|
||||||
"{{ '52:54:00' | community.general.random_mac(seed=inventory_hostname) }}"
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
Paths
|
|
||||||
-----
|
|
||||||
|
|
||||||
The ``path_join`` filter has been added in ansible-base 2.10. If you want to use this filter, but also need to support Ansible 2.9, you can use ``community.general``'s ``path_join`` shim, ``community.general.path_join``. This filter redirects to ``path_join`` for ansible-base 2.10 and ansible-core 2.11 or newer, and re-implements the filter for Ansible 2.9.
|
|
||||||
|
|
||||||
.. code-block:: yaml+jinja
|
|
||||||
|
|
||||||
# ansible-base 2.10 or newer:
|
|
||||||
path: {{ ('/etc', path, 'subdir', file) | path_join }}
|
|
||||||
|
|
||||||
# Also works with Ansible 2.9:
|
|
||||||
path: {{ ('/etc', path, 'subdir', file) | community.general.path_join }}
|
|
||||||
|
|
||||||
.. versionadded:: 3.0.0
|
|
||||||
@@ -1,144 +0,0 @@
|
|||||||
.. _ansible_collections.community.general.docsite.json_query_filter:
|
|
||||||
|
|
||||||
Selecting JSON data: JSON queries
|
|
||||||
---------------------------------
|
|
||||||
|
|
||||||
To select a single element or a data subset from a complex data structure in JSON format (for example, Ansible facts), use the ``json_query`` filter. The ``json_query`` filter lets you query a complex JSON structure and iterate over it using a loop structure.
|
|
||||||
|
|
||||||
.. note:: You must manually install the **jmespath** dependency on the Ansible controller before using this filter. This filter is built upon **jmespath**, and you can use the same syntax. For examples, see `jmespath examples <http://jmespath.org/examples.html>`_.
|
|
||||||
|
|
||||||
Consider this data structure:
|
|
||||||
|
|
||||||
.. code-block:: yaml+jinja
|
|
||||||
|
|
||||||
{
|
|
||||||
"domain_definition": {
|
|
||||||
"domain": {
|
|
||||||
"cluster": [
|
|
||||||
{
|
|
||||||
"name": "cluster1"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "cluster2"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"server": [
|
|
||||||
{
|
|
||||||
"name": "server11",
|
|
||||||
"cluster": "cluster1",
|
|
||||||
"port": "8080"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "server12",
|
|
||||||
"cluster": "cluster1",
|
|
||||||
"port": "8090"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "server21",
|
|
||||||
"cluster": "cluster2",
|
|
||||||
"port": "9080"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "server22",
|
|
||||||
"cluster": "cluster2",
|
|
||||||
"port": "9090"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"library": [
|
|
||||||
{
|
|
||||||
"name": "lib1",
|
|
||||||
"target": "cluster1"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "lib2",
|
|
||||||
"target": "cluster2"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
To extract all clusters from this structure, you can use the following query:
|
|
||||||
|
|
||||||
.. code-block:: yaml+jinja
|
|
||||||
|
|
||||||
- name: Display all cluster names
|
|
||||||
ansible.builtin.debug:
|
|
||||||
var: item
|
|
||||||
loop: "{{ domain_definition | community.general.json_query('domain.cluster[*].name') }}"
|
|
||||||
|
|
||||||
To extract all server names:
|
|
||||||
|
|
||||||
.. code-block:: yaml+jinja
|
|
||||||
|
|
||||||
- name: Display all server names
|
|
||||||
ansible.builtin.debug:
|
|
||||||
var: item
|
|
||||||
loop: "{{ domain_definition | community.general.json_query('domain.server[*].name') }}"
|
|
||||||
|
|
||||||
To extract ports from cluster1:
|
|
||||||
|
|
||||||
.. code-block:: yaml+jinja
|
|
||||||
|
|
||||||
- name: Display all ports from cluster1
|
|
||||||
ansible.builtin.debug:
|
|
||||||
var: item
|
|
||||||
loop: "{{ domain_definition | community.general.json_query(server_name_cluster1_query) }}"
|
|
||||||
vars:
|
|
||||||
server_name_cluster1_query: "domain.server[?cluster=='cluster1'].port"
|
|
||||||
|
|
||||||
.. note:: You can use a variable to make the query more readable.
|
|
||||||
|
|
||||||
To print out the ports from cluster1 in a comma separated string:
|
|
||||||
|
|
||||||
.. code-block:: yaml+jinja
|
|
||||||
|
|
||||||
- name: Display all ports from cluster1 as a string
|
|
||||||
ansible.builtin.debug:
|
|
||||||
msg: "{{ domain_definition | community.general.json_query('domain.server[?cluster==`cluster1`].port') | join(', ') }}"
|
|
||||||
|
|
||||||
.. note:: In the example above, quoting literals using backticks avoids escaping quotes and maintains readability.
|
|
||||||
|
|
||||||
You can use YAML `single quote escaping <https://yaml.org/spec/current.html#id2534365>`_:
|
|
||||||
|
|
||||||
.. code-block:: yaml+jinja
|
|
||||||
|
|
||||||
- name: Display all ports from cluster1
|
|
||||||
ansible.builtin.debug:
|
|
||||||
var: item
|
|
||||||
loop: "{{ domain_definition | community.general.json_query('domain.server[?cluster==''cluster1''].port') }}"
|
|
||||||
|
|
||||||
.. note:: Escaping single quotes within single quotes in YAML is done by doubling the single quote.
|
|
||||||
|
|
||||||
To get a hash map with all ports and names of a cluster:
|
|
||||||
|
|
||||||
.. code-block:: yaml+jinja
|
|
||||||
|
|
||||||
- name: Display all server ports and names from cluster1
|
|
||||||
ansible.builtin.debug:
|
|
||||||
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}"
|
|
||||||
|
|
||||||
To extract ports from all clusters with name starting with 'server1':
|
|
||||||
|
|
||||||
.. code-block:: yaml+jinja
|
|
||||||
|
|
||||||
- name: Display all ports from cluster1
|
|
||||||
ansible.builtin.debug:
|
|
||||||
msg: "{{ domain_definition | to_json | from_json | community.general.json_query(server_name_query) }}"
|
|
||||||
vars:
|
|
||||||
server_name_query: "domain.server[?starts_with(name,'server1')].port"
|
|
||||||
|
|
||||||
To extract ports from all clusters with name containing 'server1':
|
|
||||||
|
|
||||||
.. code-block:: yaml+jinja
|
|
||||||
|
|
||||||
- name: Display all ports from cluster1
|
|
||||||
ansible.builtin.debug:
|
|
||||||
msg: "{{ domain_definition | to_json | from_json | community.general.json_query(server_name_query) }}"
|
|
||||||
vars:
|
|
||||||
server_name_query: "domain.server[?contains(name,'server1')].port"
|
|
||||||
|
|
||||||
.. note:: while using ``starts_with`` and ``contains``, you have to use `` to_json | from_json `` filter for correct parsing of data structure.
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
Working with times
|
|
||||||
------------------
|
|
||||||
|
|
||||||
The ``to_time_unit`` filter allows to convert times from a human-readable string to a unit. For example, ``'4h 30min 12second' | community.general.to_time_unit('hour')`` gives the number of hours that correspond to 4 hours, 30 minutes and 12 seconds.
|
|
||||||
|
|
||||||
There are shorthands to directly convert to various units, like ``to_hours``, ``to_minutes``, ``to_seconds``, and so on. The following table lists all units that can be used:
|
|
||||||
|
|
||||||
.. list-table:: Units
|
|
||||||
:widths: 25 25 25 25
|
|
||||||
:header-rows: 1
|
|
||||||
|
|
||||||
* - Unit name
|
|
||||||
- Unit value in seconds
|
|
||||||
- Unit strings for filter
|
|
||||||
- Shorthand filter
|
|
||||||
* - Millisecond
|
|
||||||
- 1/1000 second
|
|
||||||
- ``ms``, ``millisecond``, ``milliseconds``, ``msec``, ``msecs``, ``msecond``, ``mseconds``
|
|
||||||
- ``to_milliseconds``
|
|
||||||
* - Second
|
|
||||||
- 1 second
|
|
||||||
- ``s``, ``sec``, ``secs``, ``second``, ``seconds``
|
|
||||||
- ``to_seconds``
|
|
||||||
* - Minute
|
|
||||||
- 60 seconds
|
|
||||||
- ``m``, ``min``, ``mins``, ``minute``, ``minutes``
|
|
||||||
- ``to_minutes``
|
|
||||||
* - Hour
|
|
||||||
- 60*60 seconds
|
|
||||||
- ``h``, ``hour``, ``hours``
|
|
||||||
- ``to_hours``
|
|
||||||
* - Day
|
|
||||||
- 24*60*60 seconds
|
|
||||||
- ``d``, ``day``, ``days``
|
|
||||||
- ``to_days``
|
|
||||||
* - Week
|
|
||||||
- 7*24*60*60 seconds
|
|
||||||
- ``w``, ``week``, ``weeks``
|
|
||||||
- ``to_weeks``
|
|
||||||
* - Month
|
|
||||||
- 30*24*60*60 seconds
|
|
||||||
- ``mo``, ``month``, ``months``
|
|
||||||
- ``to_months``
|
|
||||||
* - Year
|
|
||||||
- 365*24*60*60 seconds
|
|
||||||
- ``y``, ``year``, ``years``
|
|
||||||
- ``to_years``
|
|
||||||
|
|
||||||
Note that months and years are using a simplified representation: a month is 30 days, and a year is 365 days. If you need different definitions of months or years, you can pass them as keyword arguments. For example, if you want a year to be 365.25 days, and a month to be 30.5 days, you can write ``'11months 4' | community.general.to_years(year=365.25, month=30.5)``. These keyword arguments can be specified to ``to_time_unit`` and to all shorthand filters.
|
|
||||||
|
|
||||||
.. code-block:: yaml+jinja
|
|
||||||
|
|
||||||
- name: Convert string to seconds
|
|
||||||
debug:
|
|
||||||
msg: "{{ '30h 20m 10s 123ms' | community.general.to_time_unit('seconds') }}"
|
|
||||||
|
|
||||||
- name: Convert string to hours
|
|
||||||
debug:
|
|
||||||
msg: "{{ '30h 20m 10s 123ms' | community.general.to_hours }}"
|
|
||||||
|
|
||||||
- name: Convert string to years (using 365.25 days == 1 year)
|
|
||||||
debug:
|
|
||||||
msg: "{{ '400d 15h' | community.general.to_years(year=365.25) }}"
|
|
||||||
|
|
||||||
This produces:
|
|
||||||
|
|
||||||
.. code-block:: ansible-output
|
|
||||||
|
|
||||||
TASK [Convert string to seconds] **********************************************************
|
|
||||||
ok: [localhost] => {
|
|
||||||
"msg": "109210.123"
|
|
||||||
}
|
|
||||||
|
|
||||||
TASK [Convert string to hours] ************************************************************
|
|
||||||
ok: [localhost] => {
|
|
||||||
"msg": "30.336145277778"
|
|
||||||
}
|
|
||||||
|
|
||||||
TASK [Convert string to years (using 365.25 days == 1 year)] ******************************
|
|
||||||
ok: [localhost] => {
|
|
||||||
"msg": "1.096851471595"
|
|
||||||
}
|
|
||||||
|
|
||||||
.. versionadded: 0.2.0
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
Working with Unicode
|
|
||||||
---------------------
|
|
||||||
|
|
||||||
`Unicode <https://unicode.org/main.html>`_ makes it possible to produce two strings which may be visually equivalent, but are comprised of distinctly different characters/character sequences. To address this ``Unicode`` defines `normalization forms <https://unicode.org/reports/tr15/>`_ which avoid these distinctions by choosing a unique character sequence for a given visual representation.
|
|
||||||
|
|
||||||
You can use the ``community.general.unicode_normalize`` filter to normalize ``Unicode`` strings within your playbooks.
|
|
||||||
|
|
||||||
.. code-block:: yaml+jinja
|
|
||||||
|
|
||||||
- name: Compare Unicode representations
|
|
||||||
debug:
|
|
||||||
msg: "{{ with_combining_character | community.general.unicode_normalize == without_combining_character }}"
|
|
||||||
vars:
|
|
||||||
with_combining_character: "{{ 'Mayagu\u0308ez' }}"
|
|
||||||
without_combining_character: Mayagüez
|
|
||||||
|
|
||||||
This produces:
|
|
||||||
|
|
||||||
.. code-block:: ansible-output
|
|
||||||
|
|
||||||
TASK [Compare Unicode representations] ********************************************************
|
|
||||||
ok: [localhost] => {
|
|
||||||
"msg": true
|
|
||||||
}
|
|
||||||
|
|
||||||
The ``community.general.unicode_normalize`` filter accepts a keyword argument to select the ``Unicode`` form used to normalize the input string.
|
|
||||||
|
|
||||||
:form: One of ``'NFC'`` (default), ``'NFD'``, ``'NFKC'``, or ``'NFKD'``. See the `Unicode reference <https://unicode.org/reports/tr15/>`_ for more information.
|
|
||||||
|
|
||||||
.. versionadded:: 3.7.0
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
Working with versions
|
|
||||||
---------------------
|
|
||||||
|
|
||||||
If you need to sort a list of version numbers, the Jinja ``sort`` filter is problematic. Since it sorts lexicographically, ``2.10`` will come before ``2.9``. To treat version numbers correctly, you can use the ``version_sort`` filter:
|
|
||||||
|
|
||||||
.. code-block:: yaml+jinja
|
|
||||||
|
|
||||||
- name: Sort list by version number
|
|
||||||
debug:
|
|
||||||
var: ansible_versions | community.general.version_sort
|
|
||||||
vars:
|
|
||||||
ansible_versions:
|
|
||||||
- '2.8.0'
|
|
||||||
- '2.11.0'
|
|
||||||
- '2.7.0'
|
|
||||||
- '2.10.0'
|
|
||||||
- '2.9.0'
|
|
||||||
|
|
||||||
This produces:
|
|
||||||
|
|
||||||
.. code-block:: ansible-output
|
|
||||||
|
|
||||||
TASK [Sort list by version number] ********************************************************
|
|
||||||
ok: [localhost] => {
|
|
||||||
"ansible_versions | community.general.version_sort": [
|
|
||||||
"2.7.0",
|
|
||||||
"2.8.0",
|
|
||||||
"2.9.0",
|
|
||||||
"2.10.0",
|
|
||||||
"2.11.0"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
.. versionadded: 2.2.0
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
.. _ansible_collections.community.general.docsite.test_guide:
|
|
||||||
|
|
||||||
community.general Test (Plugin) Guide
|
|
||||||
=====================================
|
|
||||||
|
|
||||||
The :ref:`community.general collection <plugins_in_community.general>` offers currently one test plugin.
|
|
||||||
|
|
||||||
.. contents:: Topics
|
|
||||||
|
|
||||||
Feature Tests
|
|
||||||
-------------
|
|
||||||
|
|
||||||
The ``a_module`` test allows to check whether a given string refers to an existing module or action plugin. This can be useful in roles, which can use this to ensure that required modules are present ahead of time.
|
|
||||||
|
|
||||||
.. code-block:: yaml+jinja
|
|
||||||
|
|
||||||
- name: Make sure that community.aws.route53 is available
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- >
|
|
||||||
'community.aws.route53' is community.general.a_module
|
|
||||||
|
|
||||||
- name: Make sure that community.general.does_not_exist is not a module or action plugin
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- "'community.general.does_not_exist' is not community.general.a_module"
|
|
||||||
|
|
||||||
.. versionadded:: 4.0.0
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
namespace: community
|
namespace: community
|
||||||
name: general
|
name: general
|
||||||
version: 4.7.0
|
version: 3.0.2
|
||||||
readme: README.md
|
readme: README.md
|
||||||
authors:
|
authors:
|
||||||
- Ansible (https://github.com/ansible)
|
- Ansible (https://github.com/ansible)
|
||||||
|
|||||||
131
meta/runtime.yml
131
meta/runtime.yml
@@ -1,5 +1,31 @@
|
|||||||
---
|
---
|
||||||
requires_ansible: '>=2.9.10'
|
requires_ansible: '>=2.9.10'
|
||||||
|
action_groups:
|
||||||
|
ovirt:
|
||||||
|
- ovirt_affinity_label_facts
|
||||||
|
- ovirt_api_facts
|
||||||
|
- ovirt_cluster_facts
|
||||||
|
- ovirt_datacenter_facts
|
||||||
|
- ovirt_disk_facts
|
||||||
|
- ovirt_event_facts
|
||||||
|
- ovirt_external_provider_facts
|
||||||
|
- ovirt_group_facts
|
||||||
|
- ovirt_host_facts
|
||||||
|
- ovirt_host_storage_facts
|
||||||
|
- ovirt_network_facts
|
||||||
|
- ovirt_nic_facts
|
||||||
|
- ovirt_permission_facts
|
||||||
|
- ovirt_quota_facts
|
||||||
|
- ovirt_scheduling_policy_facts
|
||||||
|
- ovirt_snapshot_facts
|
||||||
|
- ovirt_storage_domain_facts
|
||||||
|
- ovirt_storage_template_facts
|
||||||
|
- ovirt_storage_vm_facts
|
||||||
|
- ovirt_tag_facts
|
||||||
|
- ovirt_template_facts
|
||||||
|
- ovirt_user_facts
|
||||||
|
- ovirt_vm_facts
|
||||||
|
- ovirt_vmpool_facts
|
||||||
plugin_routing:
|
plugin_routing:
|
||||||
connection:
|
connection:
|
||||||
docker:
|
docker:
|
||||||
@@ -11,12 +37,6 @@ plugin_routing:
|
|||||||
redirect: community.google.gcp_storage_file
|
redirect: community.google.gcp_storage_file
|
||||||
hashi_vault:
|
hashi_vault:
|
||||||
redirect: community.hashi_vault.hashi_vault
|
redirect: community.hashi_vault.hashi_vault
|
||||||
nios:
|
|
||||||
redirect: infoblox.nios_modules.nios_lookup
|
|
||||||
nios_next_ip:
|
|
||||||
redirect: infoblox.nios_modules.nios_next_ip
|
|
||||||
nios_next_network:
|
|
||||||
redirect: infoblox.nios_modules.nios_next_network
|
|
||||||
modules:
|
modules:
|
||||||
ali_instance_facts:
|
ali_instance_facts:
|
||||||
tombstone:
|
tombstone:
|
||||||
@@ -121,13 +141,11 @@ plugin_routing:
|
|||||||
gcp_forwarding_rule:
|
gcp_forwarding_rule:
|
||||||
tombstone:
|
tombstone:
|
||||||
removal_version: 2.0.0
|
removal_version: 2.0.0
|
||||||
warning_text: Use google.cloud.gcp_compute_forwarding_rule or google.cloud.gcp_compute_global_forwarding_rule
|
warning_text: Use google.cloud.gcp_compute_forwarding_rule or google.cloud.gcp_compute_global_forwarding_rule instead.
|
||||||
instead.
|
|
||||||
gcp_healthcheck:
|
gcp_healthcheck:
|
||||||
tombstone:
|
tombstone:
|
||||||
removal_version: 2.0.0
|
removal_version: 2.0.0
|
||||||
warning_text: Use google.cloud.gcp_compute_health_check, google.cloud.gcp_compute_http_health_check
|
warning_text: Use google.cloud.gcp_compute_health_check, google.cloud.gcp_compute_http_health_check or google.cloud.gcp_compute_https_health_check instead.
|
||||||
or google.cloud.gcp_compute_https_health_check instead.
|
|
||||||
gcp_target_proxy:
|
gcp_target_proxy:
|
||||||
tombstone:
|
tombstone:
|
||||||
removal_version: 2.0.0
|
removal_version: 2.0.0
|
||||||
@@ -138,22 +156,37 @@ plugin_routing:
|
|||||||
warning_text: Use google.cloud.gcp_compute_url_map instead.
|
warning_text: Use google.cloud.gcp_compute_url_map instead.
|
||||||
gcpubsub:
|
gcpubsub:
|
||||||
redirect: community.google.gcpubsub
|
redirect: community.google.gcpubsub
|
||||||
|
gcpubsub_info:
|
||||||
|
redirect: community.google.gcpubsub_info
|
||||||
gcpubsub_facts:
|
gcpubsub_facts:
|
||||||
tombstone:
|
tombstone:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.google.gcpubsub_info instead.
|
warning_text: Use community.google.gcpubsub_info instead.
|
||||||
gcpubsub_info:
|
|
||||||
redirect: community.google.gcpubsub_info
|
|
||||||
gcspanner:
|
gcspanner:
|
||||||
tombstone:
|
tombstone:
|
||||||
removal_version: 2.0.0
|
removal_version: 2.0.0
|
||||||
warning_text: Use google.cloud.gcp_spanner_database and/or google.cloud.gcp_spanner_instance
|
warning_text: Use google.cloud.gcp_spanner_database and/or google.cloud.gcp_spanner_instance instead.
|
||||||
instead.
|
|
||||||
github_hooks:
|
github_hooks:
|
||||||
tombstone:
|
tombstone:
|
||||||
removal_version: 2.0.0
|
removal_version: 2.0.0
|
||||||
warning_text: Use community.general.github_webhook and community.general.github_webhook_info
|
warning_text: Use community.general.github_webhook and community.general.github_webhook_info instead.
|
||||||
instead.
|
# Adding tombstones burns the old name, so we simply remove the entries:
|
||||||
|
# gluster_heal_info:
|
||||||
|
# tombstone:
|
||||||
|
# removal_version: 3.0.0
|
||||||
|
# warning_text: The gluster modules have migrated to the gluster.gluster collection. Use gluster.gluster.gluster_heal_info instead.
|
||||||
|
# gluster_peer:
|
||||||
|
# tombstone:
|
||||||
|
# removal_version: 3.0.0
|
||||||
|
# warning_text: The gluster modules have migrated to the gluster.gluster collection. Use gluster.gluster.gluster_peer instead.
|
||||||
|
# gluster_volume:
|
||||||
|
# tombstone:
|
||||||
|
# removal_version: 3.0.0
|
||||||
|
# warning_text: The gluster modules have migrated to the gluster.gluster collection. Use gluster.gluster.gluster_volume instead.
|
||||||
|
# helm:
|
||||||
|
# tombstone:
|
||||||
|
# removal_version: 3.0.0
|
||||||
|
# warning_text: Use community.kubernetes.helm instead.
|
||||||
hetzner_failover_ip:
|
hetzner_failover_ip:
|
||||||
redirect: community.hrobot.failover_ip
|
redirect: community.hrobot.failover_ip
|
||||||
hetzner_failover_ip_info:
|
hetzner_failover_ip_info:
|
||||||
@@ -201,13 +234,11 @@ plugin_routing:
|
|||||||
logicmonitor:
|
logicmonitor:
|
||||||
tombstone:
|
tombstone:
|
||||||
removal_version: 1.0.0
|
removal_version: 1.0.0
|
||||||
warning_text: The logicmonitor_facts module is no longer maintained and the
|
warning_text: The logicmonitor_facts module is no longer maintained and the API used has been disabled in 2017.
|
||||||
API used has been disabled in 2017.
|
|
||||||
logicmonitor_facts:
|
logicmonitor_facts:
|
||||||
tombstone:
|
tombstone:
|
||||||
removal_version: 1.0.0
|
removal_version: 1.0.0
|
||||||
warning_text: The logicmonitor_facts module is no longer maintained and the
|
warning_text: The logicmonitor_facts module is no longer maintained and the API used has been disabled in 2017.
|
||||||
API used has been disabled in 2017.
|
|
||||||
memset_memstore_facts:
|
memset_memstore_facts:
|
||||||
tombstone:
|
tombstone:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
@@ -256,38 +287,6 @@ plugin_routing:
|
|||||||
tombstone:
|
tombstone:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.general.nginx_status_info instead.
|
warning_text: Use community.general.nginx_status_info instead.
|
||||||
nios_a_record:
|
|
||||||
redirect: infoblox.nios_modules.nios_a_record
|
|
||||||
nios_aaaa_record:
|
|
||||||
redirect: infoblox.nios_modules.nios_aaaa_record
|
|
||||||
nios_cname_record:
|
|
||||||
redirect: infoblox.nios_modules.nios_cname_record
|
|
||||||
nios_dns_view:
|
|
||||||
redirect: infoblox.nios_modules.nios_dns_view
|
|
||||||
nios_fixed_address:
|
|
||||||
redirect: infoblox.nios_modules.nios_fixed_address
|
|
||||||
nios_host_record:
|
|
||||||
redirect: infoblox.nios_modules.nios_host_record
|
|
||||||
nios_member:
|
|
||||||
redirect: infoblox.nios_modules.nios_member
|
|
||||||
nios_mx_record:
|
|
||||||
redirect: infoblox.nios_modules.nios_mx_record
|
|
||||||
nios_naptr_record:
|
|
||||||
redirect: infoblox.nios_modules.nios_naptr_record
|
|
||||||
nios_network:
|
|
||||||
redirect: infoblox.nios_modules.nios_network
|
|
||||||
nios_network_view:
|
|
||||||
redirect: infoblox.nios_modules.nios_network_view
|
|
||||||
nios_nsgroup:
|
|
||||||
redirect: infoblox.nios_modules.nios_nsgroup
|
|
||||||
nios_ptr_record:
|
|
||||||
redirect: infoblox.nios_modules.nios_ptr_record
|
|
||||||
nios_srv_record:
|
|
||||||
redirect: infoblox.nios_modules.nios_srv_record
|
|
||||||
nios_txt_record:
|
|
||||||
redirect: infoblox.nios_modules.nios_txt_record
|
|
||||||
nios_zone:
|
|
||||||
redirect: infoblox.nios_modules.nios_zone
|
|
||||||
ome_device_info:
|
ome_device_info:
|
||||||
redirect: dellemc.openmanage.ome_device_info
|
redirect: dellemc.openmanage.ome_device_info
|
||||||
one_image_facts:
|
one_image_facts:
|
||||||
@@ -321,8 +320,7 @@ plugin_routing:
|
|||||||
oneview_logical_interconnect_group_facts:
|
oneview_logical_interconnect_group_facts:
|
||||||
tombstone:
|
tombstone:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.general.oneview_logical_interconnect_group_info
|
warning_text: Use community.general.oneview_logical_interconnect_group_info instead.
|
||||||
instead.
|
|
||||||
oneview_network_set_facts:
|
oneview_network_set_facts:
|
||||||
tombstone:
|
tombstone:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
@@ -479,10 +477,10 @@ plugin_routing:
|
|||||||
redirect: community.postgresql.postgresql_table
|
redirect: community.postgresql.postgresql_table
|
||||||
postgresql_tablespace:
|
postgresql_tablespace:
|
||||||
redirect: community.postgresql.postgresql_tablespace
|
redirect: community.postgresql.postgresql_tablespace
|
||||||
postgresql_user:
|
|
||||||
redirect: community.postgresql.postgresql_user
|
|
||||||
postgresql_user_obj_stat_info:
|
postgresql_user_obj_stat_info:
|
||||||
redirect: community.postgresql.postgresql_user_obj_stat_info
|
redirect: community.postgresql.postgresql_user_obj_stat_info
|
||||||
|
postgresql_user:
|
||||||
|
redirect: community.postgresql.postgresql_user
|
||||||
purefa_facts:
|
purefa_facts:
|
||||||
tombstone:
|
tombstone:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
@@ -570,11 +568,11 @@ plugin_routing:
|
|||||||
redirect: community.kubevirt.kubevirt_common_options
|
redirect: community.kubevirt.kubevirt_common_options
|
||||||
kubevirt_vm_options:
|
kubevirt_vm_options:
|
||||||
redirect: community.kubevirt.kubevirt_vm_options
|
redirect: community.kubevirt.kubevirt_vm_options
|
||||||
nios:
|
|
||||||
redirect: infoblox.nios_modules.nios
|
|
||||||
postgresql:
|
postgresql:
|
||||||
redirect: community.postgresql.postgresql
|
redirect: community.postgresql.postgresql
|
||||||
module_utils:
|
module_utils:
|
||||||
|
remote_management.dellemc.dellemc_idrac:
|
||||||
|
redirect: dellemc.openmanage.dellemc_idrac
|
||||||
docker.common:
|
docker.common:
|
||||||
redirect: community.docker.common
|
redirect: community.docker.common
|
||||||
docker.swarm:
|
docker.swarm:
|
||||||
@@ -589,30 +587,23 @@ plugin_routing:
|
|||||||
redirect: community.hrobot.robot
|
redirect: community.hrobot.robot
|
||||||
kubevirt:
|
kubevirt:
|
||||||
redirect: community.kubevirt.kubevirt
|
redirect: community.kubevirt.kubevirt
|
||||||
net_tools.nios.api:
|
|
||||||
redirect: infoblox.nios_modules.api
|
|
||||||
postgresql:
|
|
||||||
redirect: community.postgresql.postgresql
|
|
||||||
remote_management.dellemc.dellemc_idrac:
|
|
||||||
redirect: dellemc.openmanage.dellemc_idrac
|
|
||||||
remote_management.dellemc.ome:
|
remote_management.dellemc.ome:
|
||||||
redirect: dellemc.openmanage.ome
|
redirect: dellemc.openmanage.ome
|
||||||
|
postgresql:
|
||||||
|
redirect: community.postgresql.postgresql
|
||||||
callback:
|
callback:
|
||||||
actionable:
|
actionable:
|
||||||
tombstone:
|
tombstone:
|
||||||
removal_version: 2.0.0
|
removal_version: 2.0.0
|
||||||
warning_text: Use the 'default' callback plugin with 'display_skipped_hosts
|
warning_text: Use the 'default' callback plugin with 'display_skipped_hosts = no' and 'display_ok_hosts = no' options.
|
||||||
= no' and 'display_ok_hosts = no' options.
|
|
||||||
full_skip:
|
full_skip:
|
||||||
tombstone:
|
tombstone:
|
||||||
removal_version: 2.0.0
|
removal_version: 2.0.0
|
||||||
warning_text: Use the 'default' callback plugin with 'display_skipped_hosts
|
warning_text: Use the 'default' callback plugin with 'display_skipped_hosts = no' option.
|
||||||
= no' option.
|
|
||||||
stderr:
|
stderr:
|
||||||
tombstone:
|
tombstone:
|
||||||
removal_version: 2.0.0
|
removal_version: 2.0.0
|
||||||
warning_text: Use the 'default' callback plugin with 'display_failed_stderr
|
warning_text: Use the 'default' callback plugin with 'display_failed_stderr = yes' option.
|
||||||
= yes' option.
|
|
||||||
inventory:
|
inventory:
|
||||||
docker_machine:
|
docker_machine:
|
||||||
redirect: community.docker.docker_machine
|
redirect: community.docker.docker_machine
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright: (c) 2020, quidame <quidame@poivron.org>
|
# Copyright: (c) 2020, quidame <quidame@poivron.org>
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
@@ -8,7 +7,7 @@ __metaclass__ = type
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
from ansible.plugins.action import ActionBase
|
from ansible.plugins.action import ActionBase
|
||||||
from ansible.errors import AnsibleActionFail, AnsibleConnectionFailure
|
from ansible.errors import AnsibleError, AnsibleActionFail, AnsibleConnectionFailure
|
||||||
from ansible.utils.vars import merge_hash
|
from ansible.utils.vars import merge_hash
|
||||||
from ansible.utils.display import Display
|
from ansible.utils.display import Display
|
||||||
|
|
||||||
@@ -41,27 +40,19 @@ class ActionModule(ActionBase):
|
|||||||
"(=%s) to 0, and 'async' (=%s) to a value >2 and not greater than "
|
"(=%s) to 0, and 'async' (=%s) to a value >2 and not greater than "
|
||||||
"'ansible_timeout' (=%s) (recommended).")
|
"'ansible_timeout' (=%s) (recommended).")
|
||||||
|
|
||||||
def _async_result(self, async_status_args, task_vars, timeout):
|
def _async_result(self, module_args, task_vars, timeout):
|
||||||
'''
|
'''
|
||||||
Retrieve results of the asynchonous task, and display them in place of
|
Retrieve results of the asynchonous task, and display them in place of
|
||||||
the async wrapper results (those with the ansible_job_id key).
|
the async wrapper results (those with the ansible_job_id key).
|
||||||
'''
|
'''
|
||||||
async_status = self._task.copy()
|
|
||||||
async_status.args = async_status_args
|
|
||||||
async_status.action = 'ansible.builtin.async_status'
|
|
||||||
async_status.async_val = 0
|
|
||||||
async_action = self._shared_loader_obj.action_loader.get(
|
|
||||||
async_status.action, task=async_status, connection=self._connection,
|
|
||||||
play_context=self._play_context, loader=self._loader, templar=self._templar,
|
|
||||||
shared_loader_obj=self._shared_loader_obj)
|
|
||||||
|
|
||||||
if async_status.args['mode'] == 'cleanup':
|
|
||||||
return async_action.run(task_vars=task_vars)
|
|
||||||
|
|
||||||
# At least one iteration is required, even if timeout is 0.
|
# At least one iteration is required, even if timeout is 0.
|
||||||
for dummy in range(max(1, timeout)):
|
for i in range(max(1, timeout)):
|
||||||
async_result = async_action.run(task_vars=task_vars)
|
async_result = self._execute_module(
|
||||||
if async_result.get('finished', 0) == 1:
|
module_name='ansible.builtin.async_status',
|
||||||
|
module_args=module_args,
|
||||||
|
task_vars=task_vars,
|
||||||
|
wrap_async=False)
|
||||||
|
if async_result['finished'] == 1:
|
||||||
break
|
break
|
||||||
time.sleep(min(1, timeout))
|
time.sleep(min(1, timeout))
|
||||||
|
|
||||||
@@ -85,6 +76,7 @@ class ActionModule(ActionBase):
|
|||||||
task_async = self._task.async_val
|
task_async = self._task.async_val
|
||||||
check_mode = self._play_context.check_mode
|
check_mode = self._play_context.check_mode
|
||||||
max_timeout = self._connection._play_context.timeout
|
max_timeout = self._connection._play_context.timeout
|
||||||
|
module_name = self._task.action
|
||||||
module_args = self._task.args
|
module_args = self._task.args
|
||||||
|
|
||||||
if module_args.get('state', None) == 'restored':
|
if module_args.get('state', None) == 'restored':
|
||||||
@@ -115,7 +107,7 @@ class ActionModule(ActionBase):
|
|||||||
# longer on the controller); and set a backup file path.
|
# longer on the controller); and set a backup file path.
|
||||||
module_args['_timeout'] = task_async
|
module_args['_timeout'] = task_async
|
||||||
module_args['_back'] = '%s/iptables.state' % async_dir
|
module_args['_back'] = '%s/iptables.state' % async_dir
|
||||||
async_status_args = dict(mode='status')
|
async_status_args = dict(_async_dir=async_dir)
|
||||||
confirm_cmd = 'rm -f %s' % module_args['_back']
|
confirm_cmd = 'rm -f %s' % module_args['_back']
|
||||||
starter_cmd = 'touch %s.starter' % module_args['_back']
|
starter_cmd = 'touch %s.starter' % module_args['_back']
|
||||||
remaining_time = max(task_async, max_timeout)
|
remaining_time = max(task_async, max_timeout)
|
||||||
@@ -141,7 +133,7 @@ class ActionModule(ActionBase):
|
|||||||
# The module is aware to not process the main iptables-restore
|
# The module is aware to not process the main iptables-restore
|
||||||
# command before finding (and deleting) the 'starter' cookie on
|
# command before finding (and deleting) the 'starter' cookie on
|
||||||
# the host, so the previous query will not reach ssh timeout.
|
# the host, so the previous query will not reach ssh timeout.
|
||||||
dummy = self._low_level_execute_command(starter_cmd, sudoable=self.DEFAULT_SUDOABLE)
|
garbage = self._low_level_execute_command(starter_cmd, sudoable=self.DEFAULT_SUDOABLE)
|
||||||
|
|
||||||
# As the main command is not yet executed on the target, here
|
# As the main command is not yet executed on the target, here
|
||||||
# 'finished' means 'failed before main command be executed'.
|
# 'finished' means 'failed before main command be executed'.
|
||||||
@@ -151,7 +143,7 @@ class ActionModule(ActionBase):
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
for dummy in range(max_timeout):
|
for x in range(max_timeout):
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
remaining_time -= 1
|
remaining_time -= 1
|
||||||
# - AnsibleConnectionFailure covers rejected requests (i.e.
|
# - AnsibleConnectionFailure covers rejected requests (i.e.
|
||||||
@@ -159,7 +151,7 @@ class ActionModule(ActionBase):
|
|||||||
# - ansible_timeout is able to cover dropped requests (due
|
# - ansible_timeout is able to cover dropped requests (due
|
||||||
# to a rule or policy DROP) if not lower than async_val.
|
# to a rule or policy DROP) if not lower than async_val.
|
||||||
try:
|
try:
|
||||||
dummy = self._low_level_execute_command(confirm_cmd, sudoable=self.DEFAULT_SUDOABLE)
|
garbage = self._low_level_execute_command(confirm_cmd, sudoable=self.DEFAULT_SUDOABLE)
|
||||||
break
|
break
|
||||||
except AnsibleConnectionFailure:
|
except AnsibleConnectionFailure:
|
||||||
continue
|
continue
|
||||||
@@ -172,12 +164,16 @@ class ActionModule(ActionBase):
|
|||||||
del result[key]
|
del result[key]
|
||||||
|
|
||||||
if result.get('invocation', {}).get('module_args'):
|
if result.get('invocation', {}).get('module_args'):
|
||||||
for key in ('_back', '_timeout', '_async_dir', 'jid'):
|
if '_timeout' in result['invocation']['module_args']:
|
||||||
if result['invocation']['module_args'].get(key):
|
del result['invocation']['module_args']['_back']
|
||||||
del result['invocation']['module_args'][key]
|
del result['invocation']['module_args']['_timeout']
|
||||||
|
|
||||||
async_status_args['mode'] = 'cleanup'
|
async_status_args['mode'] = 'cleanup'
|
||||||
dummy = self._async_result(async_status_args, task_vars, 0)
|
garbage = self._execute_module(
|
||||||
|
module_name='ansible.builtin.async_status',
|
||||||
|
module_args=async_status_args,
|
||||||
|
task_vars=task_vars,
|
||||||
|
wrap_async=False)
|
||||||
|
|
||||||
if not wrap_async:
|
if not wrap_async:
|
||||||
# remove a temporary path we created
|
# remove a temporary path we created
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright: (c) 2020, Amin Vakil <info@aminvakil.com>
|
# Copyright: (c) 2020, Amin Vakil <info@aminvakil.com>
|
||||||
# Copyright: (c) 2016-2018, Matt Davis <mdavis@ansible.com>
|
# Copyright: (c) 2016-2018, Matt Davis <mdavis@ansible.com>
|
||||||
# Copyright: (c) 2018, Sam Doran <sdoran@redhat.com>
|
# Copyright: (c) 2018, Sam Doran <sdoran@redhat.com>
|
||||||
@@ -8,7 +7,7 @@ from __future__ import (absolute_import, division, print_function)
|
|||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
from ansible.errors import AnsibleError, AnsibleConnectionFailure
|
from ansible.errors import AnsibleError, AnsibleConnectionFailure
|
||||||
from ansible.module_utils.common.text.converters import to_native, to_text
|
from ansible.module_utils._text import to_native, to_text
|
||||||
from ansible.module_utils.common.collections import is_string
|
from ansible.module_utils.common.collections import is_string
|
||||||
from ansible.plugins.action import ActionBase
|
from ansible.plugins.action import ActionBase
|
||||||
from ansible.utils.display import Display
|
from ansible.utils.display import Display
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ DOCUMENTATION = '''
|
|||||||
short_description: Do As user
|
short_description: Do As user
|
||||||
description:
|
description:
|
||||||
- This become plugins allows your remote/login user to execute commands as another user via the doas utility.
|
- This become plugins allows your remote/login user to execute commands as another user via the doas utility.
|
||||||
author: Ansible Core Team
|
author: ansible (@core)
|
||||||
options:
|
options:
|
||||||
become_user:
|
become_user:
|
||||||
description: User you 'become' to execute the task
|
description: User you 'become' to execute the task
|
||||||
@@ -81,7 +81,7 @@ DOCUMENTATION = '''
|
|||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from ansible.module_utils.common.text.converters import to_bytes
|
from ansible.module_utils._text import to_bytes
|
||||||
from ansible.plugins.become import BecomeBase
|
from ansible.plugins.become import BecomeBase
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ DOCUMENTATION = '''
|
|||||||
short_description: Centrify's Direct Authorize
|
short_description: Centrify's Direct Authorize
|
||||||
description:
|
description:
|
||||||
- This become plugins allows your remote/login user to execute commands as another user via the dzdo utility.
|
- This become plugins allows your remote/login user to execute commands as another user via the dzdo utility.
|
||||||
author: Ansible Core Team
|
author: ansible (@core)
|
||||||
options:
|
options:
|
||||||
become_user:
|
become_user:
|
||||||
description: User you 'become' to execute the task
|
description: User you 'become' to execute the task
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ DOCUMENTATION = '''
|
|||||||
short_description: Kerberos substitute user
|
short_description: Kerberos substitute user
|
||||||
description:
|
description:
|
||||||
- This become plugins allows your remote/login user to execute commands as another user via the ksu utility.
|
- This become plugins allows your remote/login user to execute commands as another user via the ksu utility.
|
||||||
author: Ansible Core Team
|
author: ansible (@core)
|
||||||
options:
|
options:
|
||||||
become_user:
|
become_user:
|
||||||
description: User you 'become' to execute the task
|
description: User you 'become' to execute the task
|
||||||
@@ -82,7 +82,7 @@ DOCUMENTATION = '''
|
|||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from ansible.module_utils.common.text.converters import to_bytes
|
from ansible.module_utils._text import to_bytes
|
||||||
from ansible.plugins.become import BecomeBase
|
from ansible.plugins.become import BecomeBase
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ DOCUMENTATION = '''
|
|||||||
short_description: Systemd's machinectl privilege escalation
|
short_description: Systemd's machinectl privilege escalation
|
||||||
description:
|
description:
|
||||||
- This become plugins allows your remote/login user to execute commands as another user via the machinectl utility.
|
- This become plugins allows your remote/login user to execute commands as another user via the machinectl utility.
|
||||||
author: Ansible Core Team
|
author: ansible (@core)
|
||||||
options:
|
options:
|
||||||
become_user:
|
become_user:
|
||||||
description: User you 'become' to execute the task
|
description: User you 'become' to execute the task
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ DOCUMENTATION = '''
|
|||||||
short_description: PowerBroker run
|
short_description: PowerBroker run
|
||||||
description:
|
description:
|
||||||
- This become plugins allows your remote/login user to execute commands as another user via the pbrun utility.
|
- This become plugins allows your remote/login user to execute commands as another user via the pbrun utility.
|
||||||
author: Ansible Core Team
|
author: ansible (@core)
|
||||||
options:
|
options:
|
||||||
become_user:
|
become_user:
|
||||||
description: User you 'become' to execute the task
|
description: User you 'become' to execute the task
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ DOCUMENTATION = '''
|
|||||||
short_description: profile based execution
|
short_description: profile based execution
|
||||||
description:
|
description:
|
||||||
- This become plugins allows your remote/login user to execute commands as another user via the pfexec utility.
|
- This become plugins allows your remote/login user to execute commands as another user via the pfexec utility.
|
||||||
author: Ansible Core Team
|
author: ansible (@core)
|
||||||
options:
|
options:
|
||||||
become_user:
|
become_user:
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ DOCUMENTATION = '''
|
|||||||
short_description: Privilege Manager run
|
short_description: Privilege Manager run
|
||||||
description:
|
description:
|
||||||
- This become plugins allows your remote/login user to execute commands as another user via the pmrun utility.
|
- This become plugins allows your remote/login user to execute commands as another user via the pmrun utility.
|
||||||
author: Ansible Core Team
|
author: ansible (@core)
|
||||||
options:
|
options:
|
||||||
become_exe:
|
become_exe:
|
||||||
description: Sudo executable
|
description: Sudo executable
|
||||||
|
|||||||
10
plugins/cache/memcached.py
vendored
10
plugins/cache/memcached.py
vendored
@@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# (c) 2014, Brian Coca, Josh Drake, et al
|
# (c) 2014, Brian Coca, Josh Drake, et al
|
||||||
# (c) 2017 Ansible Project
|
# (c) 2017 Ansible Project
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
@@ -20,7 +19,6 @@ DOCUMENTATION = '''
|
|||||||
- List of connection information for the memcached DBs
|
- List of connection information for the memcached DBs
|
||||||
default: ['127.0.0.1:11211']
|
default: ['127.0.0.1:11211']
|
||||||
type: list
|
type: list
|
||||||
elements: string
|
|
||||||
env:
|
env:
|
||||||
- name: ANSIBLE_CACHE_PLUGIN_CONNECTION
|
- name: ANSIBLE_CACHE_PLUGIN_CONNECTION
|
||||||
ini:
|
ini:
|
||||||
@@ -155,12 +153,12 @@ class CacheModuleKeys(MutableSet):
|
|||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self._keyset)
|
return len(self._keyset)
|
||||||
|
|
||||||
def add(self, value):
|
def add(self, key):
|
||||||
self._keyset[value] = time.time()
|
self._keyset[key] = time.time()
|
||||||
self._cache.set(self.PREFIX, self._keyset)
|
self._cache.set(self.PREFIX, self._keyset)
|
||||||
|
|
||||||
def discard(self, value):
|
def discard(self, key):
|
||||||
del self._keyset[value]
|
del self._keyset[key]
|
||||||
self._cache.set(self.PREFIX, self._keyset)
|
self._cache.set(self.PREFIX, self._keyset)
|
||||||
|
|
||||||
def remove_by_timerange(self, s_min, s_max):
|
def remove_by_timerange(self, s_min, s_max):
|
||||||
|
|||||||
1
plugins/cache/pickle.py
vendored
1
plugins/cache/pickle.py
vendored
@@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# (c) 2017, Brian Coca
|
# (c) 2017, Brian Coca
|
||||||
# (c) 2017 Ansible Project
|
# (c) 2017 Ansible Project
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|||||||
17
plugins/cache/redis.py
vendored
17
plugins/cache/redis.py
vendored
@@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# (c) 2014, Brian Coca, Josh Drake, et al
|
# (c) 2014, Brian Coca, Josh Drake, et al
|
||||||
# (c) 2017 Ansible Project
|
# (c) 2017 Ansible Project
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
@@ -62,13 +61,12 @@ DOCUMENTATION = '''
|
|||||||
type: integer
|
type: integer
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import re
|
|
||||||
import time
|
import time
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
from ansible.module_utils.common.text.converters import to_native
|
from ansible.module_utils._text import to_native
|
||||||
from ansible.parsing.ajson import AnsibleJSONEncoder, AnsibleJSONDecoder
|
from ansible.parsing.ajson import AnsibleJSONEncoder, AnsibleJSONDecoder
|
||||||
from ansible.plugins.cache import BaseCacheModule
|
from ansible.plugins.cache import BaseCacheModule
|
||||||
from ansible.release import __version__ as ansible_base_version
|
from ansible.release import __version__ as ansible_base_version
|
||||||
@@ -93,8 +91,6 @@ class CacheModule(BaseCacheModule):
|
|||||||
performance.
|
performance.
|
||||||
"""
|
"""
|
||||||
_sentinel_service_name = None
|
_sentinel_service_name = None
|
||||||
re_url_conn = re.compile(r'^([^:]+|\[[^]]+\]):(\d+):(\d+)(?::(.*))?$')
|
|
||||||
re_sent_conn = re.compile(r'^(.*):(\d+)$')
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
uri = ''
|
uri = ''
|
||||||
@@ -134,18 +130,11 @@ class CacheModule(BaseCacheModule):
|
|||||||
self._db = self._get_sentinel_connection(uri, kw)
|
self._db = self._get_sentinel_connection(uri, kw)
|
||||||
# normal connection
|
# normal connection
|
||||||
else:
|
else:
|
||||||
connection = self._parse_connection(self.re_url_conn, uri)
|
connection = uri.split(':')
|
||||||
self._db = StrictRedis(*connection, **kw)
|
self._db = StrictRedis(*connection, **kw)
|
||||||
|
|
||||||
display.vv('Redis connection: %s' % self._db)
|
display.vv('Redis connection: %s' % self._db)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _parse_connection(re_patt, uri):
|
|
||||||
match = re_patt.match(uri)
|
|
||||||
if not match:
|
|
||||||
raise AnsibleError("Unable to parse connection string")
|
|
||||||
return match.groups()
|
|
||||||
|
|
||||||
def _get_sentinel_connection(self, uri, kw):
|
def _get_sentinel_connection(self, uri, kw):
|
||||||
"""
|
"""
|
||||||
get sentinel connection details from _uri
|
get sentinel connection details from _uri
|
||||||
@@ -169,7 +158,7 @@ class CacheModule(BaseCacheModule):
|
|||||||
except IndexError:
|
except IndexError:
|
||||||
pass # password is optional
|
pass # password is optional
|
||||||
|
|
||||||
sentinels = [self._parse_connection(self.re_sent_conn, shost) for shost in connections]
|
sentinels = [tuple(shost.split(':')) for shost in connections]
|
||||||
display.vv('\nUsing redis sentinels: %s' % sentinels)
|
display.vv('\nUsing redis sentinels: %s' % sentinels)
|
||||||
scon = Sentinel(sentinels, **kw)
|
scon = Sentinel(sentinels, **kw)
|
||||||
try:
|
try:
|
||||||
|
|||||||
1
plugins/cache/yaml.py
vendored
1
plugins/cache/yaml.py
vendored
@@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# (c) 2017, Brian Coca
|
# (c) 2017, Brian Coca
|
||||||
# (c) 2017 Ansible Project
|
# (c) 2017 Ansible Project
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# (C) 2012, Michael DeHaan, <michael.dehaan@gmail.com>
|
# (C) 2012, Michael DeHaan, <michael.dehaan@gmail.com>
|
||||||
# (c) 2017 Ansible Project
|
# (c) 2017 Ansible Project
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# (c) 2018, Ivan Aragones Muniesa <ivan.aragones.muniesa@gmail.com>
|
# (c) 2018, Ivan Aragones Muniesa <ivan.aragones.muniesa@gmail.com>
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
'''
|
'''
|
||||||
@@ -45,8 +44,6 @@ class CallbackModule(CallbackBase):
|
|||||||
_task_total = 0
|
_task_total = 0
|
||||||
_host_counter = 1
|
_host_counter = 1
|
||||||
_host_total = 0
|
_host_total = 0
|
||||||
_current_batch_total = 0
|
|
||||||
_previous_batch_total = 0
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(CallbackModule, self).__init__()
|
super(CallbackModule, self).__init__()
|
||||||
@@ -78,11 +75,8 @@ class CallbackModule(CallbackBase):
|
|||||||
self._display.banner(msg)
|
self._display.banner(msg)
|
||||||
self._play = play
|
self._play = play
|
||||||
|
|
||||||
self._previous_batch_total = self._current_batch_total
|
|
||||||
self._current_batch_total = self._previous_batch_total + len(self._all_vars()['vars']['ansible_play_batch'])
|
|
||||||
self._host_total = len(self._all_vars()['vars']['ansible_play_hosts_all'])
|
self._host_total = len(self._all_vars()['vars']['ansible_play_hosts_all'])
|
||||||
self._task_total = len(self._play.get_tasks()[0])
|
self._task_total = len(self._play.get_tasks()[0])
|
||||||
self._task_counter = 1
|
|
||||||
|
|
||||||
def v2_playbook_on_stats(self, stats):
|
def v2_playbook_on_stats(self, stats):
|
||||||
self._display.banner("PLAY RECAP")
|
self._display.banner("PLAY RECAP")
|
||||||
@@ -150,7 +144,7 @@ class CallbackModule(CallbackBase):
|
|||||||
path = task.get_path()
|
path = task.get_path()
|
||||||
if path:
|
if path:
|
||||||
self._display.display("task path: %s" % path, color=C.COLOR_DEBUG)
|
self._display.display("task path: %s" % path, color=C.COLOR_DEBUG)
|
||||||
self._host_counter = self._previous_batch_total
|
self._host_counter = 0
|
||||||
self._task_counter += 1
|
self._task_counter += 1
|
||||||
|
|
||||||
def v2_runner_on_ok(self, result):
|
def v2_runner_on_ok(self, result):
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# (c) 2016, Dag Wieers <dag@wieers.com>
|
# (c) 2016, Dag Wieers <dag@wieers.com>
|
||||||
# (c) 2017 Ansible Project
|
# (c) 2017 Ansible Project
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|||||||
@@ -792,7 +792,7 @@ from ansible.utils.color import colorize, hostcolor
|
|||||||
from ansible.template import Templar
|
from ansible.template import Templar
|
||||||
from ansible.vars.manager import VariableManager
|
from ansible.vars.manager import VariableManager
|
||||||
from ansible.plugins.callback.default import CallbackModule as Default
|
from ansible.plugins.callback.default import CallbackModule as Default
|
||||||
from ansible.module_utils.common.text.converters import to_text
|
from ansible.module_utils._text import to_text
|
||||||
|
|
||||||
|
|
||||||
class DummyStdout(object):
|
class DummyStdout(object):
|
||||||
|
|||||||
@@ -1,423 +0,0 @@
|
|||||||
# (C) 2021, Victor Martinez <VictorMartinezRubio@gmail.com>
|
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
|
|
||||||
from __future__ import (absolute_import, division, print_function)
|
|
||||||
__metaclass__ = type
|
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
|
||||||
author: Victor Martinez (@v1v) <VictorMartinezRubio@gmail.com>
|
|
||||||
name: elastic
|
|
||||||
type: notification
|
|
||||||
short_description: Create distributed traces for each Ansible task in Elastic APM
|
|
||||||
version_added: 3.8.0
|
|
||||||
description:
|
|
||||||
- This callback creates distributed traces for each Ansible task in Elastic APM.
|
|
||||||
- You can configure the plugin with environment variables.
|
|
||||||
- See U(https://www.elastic.co/guide/en/apm/agent/python/current/configuration.html).
|
|
||||||
options:
|
|
||||||
hide_task_arguments:
|
|
||||||
default: false
|
|
||||||
type: bool
|
|
||||||
description:
|
|
||||||
- Hide the arguments for a task.
|
|
||||||
env:
|
|
||||||
- name: ANSIBLE_OPENTELEMETRY_HIDE_TASK_ARGUMENTS
|
|
||||||
apm_service_name:
|
|
||||||
default: ansible
|
|
||||||
type: str
|
|
||||||
description:
|
|
||||||
- The service name resource attribute.
|
|
||||||
env:
|
|
||||||
- name: ELASTIC_APM_SERVICE_NAME
|
|
||||||
apm_server_url:
|
|
||||||
type: str
|
|
||||||
description:
|
|
||||||
- Use the APM server and its environment variables.
|
|
||||||
env:
|
|
||||||
- name: ELASTIC_APM_SERVER_URL
|
|
||||||
apm_secret_token:
|
|
||||||
type: str
|
|
||||||
description:
|
|
||||||
- Use the APM server token
|
|
||||||
env:
|
|
||||||
- name: ELASTIC_APM_SECRET_TOKEN
|
|
||||||
apm_api_key:
|
|
||||||
type: str
|
|
||||||
description:
|
|
||||||
- Use the APM API key
|
|
||||||
env:
|
|
||||||
- name: ELASTIC_APM_API_KEY
|
|
||||||
apm_verify_server_cert:
|
|
||||||
default: true
|
|
||||||
type: bool
|
|
||||||
description:
|
|
||||||
- Verifies the SSL certificate if an HTTPS connection.
|
|
||||||
env:
|
|
||||||
- name: ELASTIC_APM_VERIFY_SERVER_CERT
|
|
||||||
traceparent:
|
|
||||||
type: str
|
|
||||||
description:
|
|
||||||
- The L(W3C Trace Context header traceparent,https://www.w3.org/TR/trace-context-1/#traceparent-header).
|
|
||||||
env:
|
|
||||||
- name: TRACEPARENT
|
|
||||||
requirements:
|
|
||||||
- elastic-apm (Python library)
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
EXAMPLES = '''
|
|
||||||
examples: |
|
|
||||||
Enable the plugin in ansible.cfg:
|
|
||||||
[defaults]
|
|
||||||
callbacks_enabled = community.general.elastic
|
|
||||||
|
|
||||||
Set the environment variable:
|
|
||||||
export ELASTIC_APM_SERVER_URL=<your APM server URL)>
|
|
||||||
export ELASTIC_APM_SERVICE_NAME=your_service_name
|
|
||||||
export ELASTIC_APM_API_KEY=your_APM_API_KEY
|
|
||||||
'''
|
|
||||||
|
|
||||||
import getpass
|
|
||||||
import socket
|
|
||||||
import time
|
|
||||||
import uuid
|
|
||||||
|
|
||||||
from collections import OrderedDict
|
|
||||||
from os.path import basename
|
|
||||||
|
|
||||||
from ansible.errors import AnsibleError, AnsibleRuntimeError
|
|
||||||
from ansible.module_utils.six import raise_from
|
|
||||||
from ansible.plugins.callback import CallbackBase
|
|
||||||
|
|
||||||
try:
|
|
||||||
from elasticapm import Client, capture_span, trace_parent_from_string, instrument, label
|
|
||||||
except ImportError as imp_exc:
|
|
||||||
ELASTIC_LIBRARY_IMPORT_ERROR = imp_exc
|
|
||||||
else:
|
|
||||||
ELASTIC_LIBRARY_IMPORT_ERROR = None
|
|
||||||
|
|
||||||
|
|
||||||
class TaskData:
|
|
||||||
"""
|
|
||||||
Data about an individual task.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, uuid, name, path, play, action, args):
|
|
||||||
self.uuid = uuid
|
|
||||||
self.name = name
|
|
||||||
self.path = path
|
|
||||||
self.play = play
|
|
||||||
self.host_data = OrderedDict()
|
|
||||||
self.start = time.time()
|
|
||||||
self.action = action
|
|
||||||
self.args = args
|
|
||||||
|
|
||||||
def add_host(self, host):
|
|
||||||
if host.uuid in self.host_data:
|
|
||||||
if host.status == 'included':
|
|
||||||
# concatenate task include output from multiple items
|
|
||||||
host.result = '%s\n%s' % (self.host_data[host.uuid].result, host.result)
|
|
||||||
else:
|
|
||||||
return
|
|
||||||
|
|
||||||
self.host_data[host.uuid] = host
|
|
||||||
|
|
||||||
|
|
||||||
class HostData:
|
|
||||||
"""
|
|
||||||
Data about an individual host.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, uuid, name, status, result):
|
|
||||||
self.uuid = uuid
|
|
||||||
self.name = name
|
|
||||||
self.status = status
|
|
||||||
self.result = result
|
|
||||||
self.finish = time.time()
|
|
||||||
|
|
||||||
|
|
||||||
class ElasticSource(object):
|
|
||||||
def __init__(self, display):
|
|
||||||
self.ansible_playbook = ""
|
|
||||||
self.ansible_version = None
|
|
||||||
self.session = str(uuid.uuid4())
|
|
||||||
self.host = socket.gethostname()
|
|
||||||
try:
|
|
||||||
self.ip_address = socket.gethostbyname(socket.gethostname())
|
|
||||||
except Exception as e:
|
|
||||||
self.ip_address = None
|
|
||||||
self.user = getpass.getuser()
|
|
||||||
|
|
||||||
self._display = display
|
|
||||||
|
|
||||||
def start_task(self, tasks_data, hide_task_arguments, play_name, task):
|
|
||||||
""" record the start of a task for one or more hosts """
|
|
||||||
|
|
||||||
uuid = task._uuid
|
|
||||||
|
|
||||||
if uuid in tasks_data:
|
|
||||||
return
|
|
||||||
|
|
||||||
name = task.get_name().strip()
|
|
||||||
path = task.get_path()
|
|
||||||
action = task.action
|
|
||||||
args = None
|
|
||||||
|
|
||||||
if not task.no_log and not hide_task_arguments:
|
|
||||||
args = ', '.join(('%s=%s' % a for a in task.args.items()))
|
|
||||||
|
|
||||||
tasks_data[uuid] = TaskData(uuid, name, path, play_name, action, args)
|
|
||||||
|
|
||||||
def finish_task(self, tasks_data, status, result):
|
|
||||||
""" record the results of a task for a single host """
|
|
||||||
|
|
||||||
task_uuid = result._task._uuid
|
|
||||||
|
|
||||||
if hasattr(result, '_host') and result._host is not None:
|
|
||||||
host_uuid = result._host._uuid
|
|
||||||
host_name = result._host.name
|
|
||||||
else:
|
|
||||||
host_uuid = 'include'
|
|
||||||
host_name = 'include'
|
|
||||||
|
|
||||||
task = tasks_data[task_uuid]
|
|
||||||
|
|
||||||
if self.ansible_version is None and result._task_fields['args'].get('_ansible_version'):
|
|
||||||
self.ansible_version = result._task_fields['args'].get('_ansible_version')
|
|
||||||
|
|
||||||
task.add_host(HostData(host_uuid, host_name, status, result))
|
|
||||||
|
|
||||||
def generate_distributed_traces(self, tasks_data, status, end_time, traceparent, apm_service_name,
|
|
||||||
apm_server_url, apm_verify_server_cert, apm_secret_token, apm_api_key):
|
|
||||||
""" generate distributed traces from the collected TaskData and HostData """
|
|
||||||
|
|
||||||
tasks = []
|
|
||||||
parent_start_time = None
|
|
||||||
for task_uuid, task in tasks_data.items():
|
|
||||||
if parent_start_time is None:
|
|
||||||
parent_start_time = task.start
|
|
||||||
tasks.append(task)
|
|
||||||
|
|
||||||
apm_cli = self.init_apm_client(apm_server_url, apm_service_name, apm_verify_server_cert, apm_secret_token, apm_api_key)
|
|
||||||
if apm_cli:
|
|
||||||
instrument() # Only call this once, as early as possible.
|
|
||||||
if traceparent:
|
|
||||||
parent = trace_parent_from_string(traceparent)
|
|
||||||
apm_cli.begin_transaction("Session", trace_parent=parent, start=parent_start_time)
|
|
||||||
else:
|
|
||||||
apm_cli.begin_transaction("Session", start=parent_start_time)
|
|
||||||
# Populate trace metadata attributes
|
|
||||||
if self.ansible_version is not None:
|
|
||||||
label(ansible_version=self.ansible_version)
|
|
||||||
label(ansible_session=self.session, ansible_host_name=self.host, ansible_host_user=self.user)
|
|
||||||
if self.ip_address is not None:
|
|
||||||
label(ansible_host_ip=self.ip_address)
|
|
||||||
|
|
||||||
for task_data in tasks:
|
|
||||||
for host_uuid, host_data in task_data.host_data.items():
|
|
||||||
self.create_span_data(apm_cli, task_data, host_data)
|
|
||||||
|
|
||||||
apm_cli.end_transaction(name=__name__, result=status, duration=end_time - parent_start_time)
|
|
||||||
|
|
||||||
def create_span_data(self, apm_cli, task_data, host_data):
|
|
||||||
""" create the span with the given TaskData and HostData """
|
|
||||||
|
|
||||||
name = '[%s] %s: %s' % (host_data.name, task_data.play, task_data.name)
|
|
||||||
|
|
||||||
message = "success"
|
|
||||||
status = "success"
|
|
||||||
enriched_error_message = None
|
|
||||||
if host_data.status == 'included':
|
|
||||||
rc = 0
|
|
||||||
else:
|
|
||||||
res = host_data.result._result
|
|
||||||
rc = res.get('rc', 0)
|
|
||||||
if host_data.status == 'failed':
|
|
||||||
message = self.get_error_message(res)
|
|
||||||
enriched_error_message = self.enrich_error_message(res)
|
|
||||||
status = "failure"
|
|
||||||
elif host_data.status == 'skipped':
|
|
||||||
if 'skip_reason' in res:
|
|
||||||
message = res['skip_reason']
|
|
||||||
else:
|
|
||||||
message = 'skipped'
|
|
||||||
status = "unknown"
|
|
||||||
|
|
||||||
with capture_span(task_data.name,
|
|
||||||
start=task_data.start,
|
|
||||||
span_type="ansible.task.run",
|
|
||||||
duration=host_data.finish - task_data.start,
|
|
||||||
labels={"ansible.task.args": task_data.args,
|
|
||||||
"ansible.task.message": message,
|
|
||||||
"ansible.task.module": task_data.action,
|
|
||||||
"ansible.task.name": name,
|
|
||||||
"ansible.task.result": rc,
|
|
||||||
"ansible.task.host.name": host_data.name,
|
|
||||||
"ansible.task.host.status": host_data.status}) as span:
|
|
||||||
span.outcome = status
|
|
||||||
if 'failure' in status:
|
|
||||||
exception = AnsibleRuntimeError(message="{0}: {1} failed with error message {2}".format(task_data.action, name, enriched_error_message))
|
|
||||||
apm_cli.capture_exception(exc_info=(type(exception), exception, exception.__traceback__), handled=True)
|
|
||||||
|
|
||||||
def init_apm_client(self, apm_server_url, apm_service_name, apm_verify_server_cert, apm_secret_token, apm_api_key):
|
|
||||||
if apm_server_url:
|
|
||||||
return Client(service_name=apm_service_name,
|
|
||||||
server_url=apm_server_url,
|
|
||||||
verify_server_cert=False,
|
|
||||||
secret_token=apm_secret_token,
|
|
||||||
api_key=apm_api_key,
|
|
||||||
use_elastic_traceparent_header=True,
|
|
||||||
debug=True)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_error_message(result):
|
|
||||||
if result.get('exception') is not None:
|
|
||||||
return ElasticSource._last_line(result['exception'])
|
|
||||||
return result.get('msg', 'failed')
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _last_line(text):
|
|
||||||
lines = text.strip().split('\n')
|
|
||||||
return lines[-1]
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def enrich_error_message(result):
|
|
||||||
message = result.get('msg', 'failed')
|
|
||||||
exception = result.get('exception')
|
|
||||||
stderr = result.get('stderr')
|
|
||||||
return ('message: "{0}"\nexception: "{1}"\nstderr: "{2}"').format(message, exception, stderr)
|
|
||||||
|
|
||||||
|
|
||||||
class CallbackModule(CallbackBase):
|
|
||||||
"""
|
|
||||||
This callback creates distributed traces with Elastic APM.
|
|
||||||
"""
|
|
||||||
|
|
||||||
CALLBACK_VERSION = 2.0
|
|
||||||
CALLBACK_TYPE = 'notification'
|
|
||||||
CALLBACK_NAME = 'community.general.elastic'
|
|
||||||
CALLBACK_NEEDS_ENABLED = True
|
|
||||||
|
|
||||||
def __init__(self, display=None):
|
|
||||||
super(CallbackModule, self).__init__(display=display)
|
|
||||||
self.hide_task_arguments = None
|
|
||||||
self.apm_service_name = None
|
|
||||||
self.ansible_playbook = None
|
|
||||||
self.traceparent = False
|
|
||||||
self.play_name = None
|
|
||||||
self.tasks_data = None
|
|
||||||
self.errors = 0
|
|
||||||
self.disabled = False
|
|
||||||
|
|
||||||
if ELASTIC_LIBRARY_IMPORT_ERROR:
|
|
||||||
raise_from(
|
|
||||||
AnsibleError('The `elastic-apm` must be installed to use this plugin'),
|
|
||||||
ELASTIC_LIBRARY_IMPORT_ERROR)
|
|
||||||
|
|
||||||
self.tasks_data = OrderedDict()
|
|
||||||
|
|
||||||
self.elastic = ElasticSource(display=self._display)
|
|
||||||
|
|
||||||
def set_options(self, task_keys=None, var_options=None, direct=None):
|
|
||||||
super(CallbackModule, self).set_options(task_keys=task_keys,
|
|
||||||
var_options=var_options,
|
|
||||||
direct=direct)
|
|
||||||
|
|
||||||
self.hide_task_arguments = self.get_option('hide_task_arguments')
|
|
||||||
|
|
||||||
self.apm_service_name = self.get_option('apm_service_name')
|
|
||||||
if not self.apm_service_name:
|
|
||||||
self.apm_service_name = 'ansible'
|
|
||||||
|
|
||||||
self.apm_server_url = self.get_option('apm_server_url')
|
|
||||||
self.apm_secret_token = self.get_option('apm_secret_token')
|
|
||||||
self.apm_api_key = self.get_option('apm_api_key')
|
|
||||||
self.apm_verify_server_cert = self.get_option('apm_verify_server_cert')
|
|
||||||
self.traceparent = self.get_option('traceparent')
|
|
||||||
|
|
||||||
def v2_playbook_on_start(self, playbook):
|
|
||||||
self.ansible_playbook = basename(playbook._file_name)
|
|
||||||
|
|
||||||
def v2_playbook_on_play_start(self, play):
|
|
||||||
self.play_name = play.get_name()
|
|
||||||
|
|
||||||
def v2_runner_on_no_hosts(self, task):
|
|
||||||
self.elastic.start_task(
|
|
||||||
self.tasks_data,
|
|
||||||
self.hide_task_arguments,
|
|
||||||
self.play_name,
|
|
||||||
task
|
|
||||||
)
|
|
||||||
|
|
||||||
def v2_playbook_on_task_start(self, task, is_conditional):
|
|
||||||
self.elastic.start_task(
|
|
||||||
self.tasks_data,
|
|
||||||
self.hide_task_arguments,
|
|
||||||
self.play_name,
|
|
||||||
task
|
|
||||||
)
|
|
||||||
|
|
||||||
def v2_playbook_on_cleanup_task_start(self, task):
|
|
||||||
self.elastic.start_task(
|
|
||||||
self.tasks_data,
|
|
||||||
self.hide_task_arguments,
|
|
||||||
self.play_name,
|
|
||||||
task
|
|
||||||
)
|
|
||||||
|
|
||||||
def v2_playbook_on_handler_task_start(self, task):
|
|
||||||
self.elastic.start_task(
|
|
||||||
self.tasks_data,
|
|
||||||
self.hide_task_arguments,
|
|
||||||
self.play_name,
|
|
||||||
task
|
|
||||||
)
|
|
||||||
|
|
||||||
def v2_runner_on_failed(self, result, ignore_errors=False):
|
|
||||||
self.errors += 1
|
|
||||||
self.elastic.finish_task(
|
|
||||||
self.tasks_data,
|
|
||||||
'failed',
|
|
||||||
result
|
|
||||||
)
|
|
||||||
|
|
||||||
def v2_runner_on_ok(self, result):
|
|
||||||
self.elastic.finish_task(
|
|
||||||
self.tasks_data,
|
|
||||||
'ok',
|
|
||||||
result
|
|
||||||
)
|
|
||||||
|
|
||||||
def v2_runner_on_skipped(self, result):
|
|
||||||
self.elastic.finish_task(
|
|
||||||
self.tasks_data,
|
|
||||||
'skipped',
|
|
||||||
result
|
|
||||||
)
|
|
||||||
|
|
||||||
def v2_playbook_on_include(self, included_file):
|
|
||||||
self.elastic.finish_task(
|
|
||||||
self.tasks_data,
|
|
||||||
'included',
|
|
||||||
included_file
|
|
||||||
)
|
|
||||||
|
|
||||||
def v2_playbook_on_stats(self, stats):
|
|
||||||
if self.errors == 0:
|
|
||||||
status = "success"
|
|
||||||
else:
|
|
||||||
status = "failure"
|
|
||||||
self.elastic.generate_distributed_traces(
|
|
||||||
self.tasks_data,
|
|
||||||
status,
|
|
||||||
time.time(),
|
|
||||||
self.traceparent,
|
|
||||||
self.apm_service_name,
|
|
||||||
self.apm_server_url,
|
|
||||||
self.apm_verify_server_cert,
|
|
||||||
self.apm_secret_token,
|
|
||||||
self.apm_api_key
|
|
||||||
)
|
|
||||||
|
|
||||||
def v2_runner_on_async_failed(self, result, **kwargs):
|
|
||||||
self.errors += 1
|
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# (C) 2014, Matt Martz <matt@sivel.net>
|
# (C) 2014, Matt Martz <matt@sivel.net>
|
||||||
# (c) 2017 Ansible Project
|
# (c) 2017 Ansible Project
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (C) 2016 maxn nikolaev.makc@gmail.com
|
# Copyright (C) 2016 maxn nikolaev.makc@gmail.com
|
||||||
# Copyright (c) 2017 Ansible Project
|
# Copyright (c) 2017 Ansible Project
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# (C) 2012, Michael DeHaan, <michael.dehaan@gmail.com>
|
# (C) 2012, Michael DeHaan, <michael.dehaan@gmail.com>
|
||||||
# (c) 2017 Ansible Project
|
# (c) 2017 Ansible Project
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
@@ -32,7 +31,7 @@ import time
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
from ansible.utils.path import makedirs_safe
|
from ansible.utils.path import makedirs_safe
|
||||||
from ansible.module_utils.common.text.converters import to_bytes
|
from ansible.module_utils._text import to_bytes
|
||||||
from ansible.module_utils.common._collections_compat import MutableMapping
|
from ansible.module_utils.common._collections_compat import MutableMapping
|
||||||
from ansible.parsing.ajson import AnsibleJSONEncoder
|
from ansible.parsing.ajson import AnsibleJSONEncoder
|
||||||
from ansible.plugins.callback import CallbackBase
|
from ansible.plugins.callback import CallbackBase
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
from __future__ import (absolute_import, division, print_function)
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# (c) 2018, Samir Musali <samir.musali@logdna.com>
|
# (c) 2018, Samir Musali <samir.musali@logdna.com>
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
@@ -78,7 +77,7 @@ def get_mac():
|
|||||||
|
|
||||||
# Getting hostname of system:
|
# Getting hostname of system:
|
||||||
def get_hostname():
|
def get_hostname():
|
||||||
return str(socket.gethostname()).split('.local', 1)[0]
|
return str(socket.gethostname()).split('.local')[0]
|
||||||
|
|
||||||
|
|
||||||
# Getting IP of system:
|
# Getting IP of system:
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# (c) 2015, Logentries.com, Jimmy Tang <jimmy.tang@logentries.com>
|
# (c) 2015, Logentries.com, Jimmy Tang <jimmy.tang@logentries.com>
|
||||||
# (c) 2017 Ansible Project
|
# (c) 2017 Ansible Project
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
@@ -112,7 +111,7 @@ try:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
HAS_FLATDICT = False
|
HAS_FLATDICT = False
|
||||||
|
|
||||||
from ansible.module_utils.common.text.converters import to_bytes, to_text
|
from ansible.module_utils._text import to_bytes, to_text
|
||||||
from ansible.plugins.callback import CallbackBase
|
from ansible.plugins.callback import CallbackBase
|
||||||
|
|
||||||
# Todo:
|
# Todo:
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# (C) 2020, Yevhen Khmelenko <ujenmr@gmail.com>
|
# (C) 2020, Yevhen Khmelenko <ujenmr@gmail.com>
|
||||||
# (C) 2017 Ansible Project
|
# (C) 2017 Ansible Project
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
@@ -94,7 +93,6 @@ ansible.cfg: |
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
from ansible import context
|
|
||||||
import socket
|
import socket
|
||||||
import uuid
|
import uuid
|
||||||
import logging
|
import logging
|
||||||
@@ -153,11 +151,11 @@ class CallbackModule(CallbackBase):
|
|||||||
self.base_data['ansible_pre_command_output'] = os.popen(
|
self.base_data['ansible_pre_command_output'] = os.popen(
|
||||||
self.ls_pre_command).read()
|
self.ls_pre_command).read()
|
||||||
|
|
||||||
if context.CLIARGS is not None:
|
if self._options is not None:
|
||||||
self.base_data['ansible_checkmode'] = context.CLIARGS.get('check')
|
self.base_data['ansible_checkmode'] = self._options.check
|
||||||
self.base_data['ansible_tags'] = context.CLIARGS.get('tags')
|
self.base_data['ansible_tags'] = self._options.tags
|
||||||
self.base_data['ansible_skip_tags'] = context.CLIARGS.get('skip_tags')
|
self.base_data['ansible_skip_tags'] = self._options.skip_tags
|
||||||
self.base_data['inventory'] = context.CLIARGS.get('inventory')
|
self.base_data['inventory'] = self._options.inventory
|
||||||
|
|
||||||
def set_options(self, task_keys=None, var_options=None, direct=None):
|
def set_options(self, task_keys=None, var_options=None, direct=None):
|
||||||
super(CallbackModule, self).set_options(task_keys=task_keys, var_options=var_options, direct=direct)
|
super(CallbackModule, self).set_options(task_keys=task_keys, var_options=var_options, direct=direct)
|
||||||
|
|||||||
@@ -11,16 +11,14 @@ name: mail
|
|||||||
type: notification
|
type: notification
|
||||||
short_description: Sends failure events via email
|
short_description: Sends failure events via email
|
||||||
description:
|
description:
|
||||||
- This callback will report failures via email.
|
- This callback will report failures via email
|
||||||
author:
|
author:
|
||||||
- Dag Wieers (@dagwieers)
|
- Dag Wieers (@dagwieers)
|
||||||
requirements:
|
requirements:
|
||||||
- whitelisting in configuration
|
- whitelisting in configuration
|
||||||
options:
|
options:
|
||||||
mta:
|
mta:
|
||||||
description:
|
description: Mail Transfer Agent, server that accepts SMTP
|
||||||
- Mail Transfer Agent, server that accepts SMTP.
|
|
||||||
type: str
|
|
||||||
env:
|
env:
|
||||||
- name: SMTPHOST
|
- name: SMTPHOST
|
||||||
ini:
|
ini:
|
||||||
@@ -28,57 +26,43 @@ options:
|
|||||||
key: smtphost
|
key: smtphost
|
||||||
default: localhost
|
default: localhost
|
||||||
mtaport:
|
mtaport:
|
||||||
description:
|
description: Mail Transfer Agent Port, port at which server SMTP
|
||||||
- Mail Transfer Agent Port.
|
|
||||||
- Port at which server SMTP.
|
|
||||||
type: int
|
|
||||||
ini:
|
ini:
|
||||||
- section: callback_mail
|
- section: callback_mail
|
||||||
key: smtpport
|
key: smtpport
|
||||||
default: 25
|
default: 25
|
||||||
to:
|
to:
|
||||||
description:
|
description: Mail recipient
|
||||||
- Mail recipient.
|
|
||||||
type: list
|
|
||||||
elements: str
|
|
||||||
ini:
|
ini:
|
||||||
- section: callback_mail
|
- section: callback_mail
|
||||||
key: to
|
key: to
|
||||||
default: [root]
|
default: root
|
||||||
sender:
|
sender:
|
||||||
description:
|
description: Mail sender
|
||||||
- Mail sender.
|
|
||||||
- Note that this will be required from community.general 6.0.0 on.
|
|
||||||
type: str
|
|
||||||
ini:
|
ini:
|
||||||
- section: callback_mail
|
- section: callback_mail
|
||||||
key: sender
|
key: sender
|
||||||
cc:
|
cc:
|
||||||
description:
|
description: CC'd recipient
|
||||||
- CC'd recipients.
|
|
||||||
type: list
|
|
||||||
elements: str
|
|
||||||
ini:
|
ini:
|
||||||
- section: callback_mail
|
- section: callback_mail
|
||||||
key: cc
|
key: cc
|
||||||
bcc:
|
bcc:
|
||||||
description:
|
description: BCC'd recipient
|
||||||
- BCC'd recipients.
|
|
||||||
type: list
|
|
||||||
elements: str
|
|
||||||
ini:
|
ini:
|
||||||
- section: callback_mail
|
- section: callback_mail
|
||||||
key: bcc
|
key: bcc
|
||||||
|
notes:
|
||||||
|
- "TODO: expand configuration options now that plugins can leverage Ansible's configuration"
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import email.utils
|
|
||||||
import smtplib
|
import smtplib
|
||||||
|
|
||||||
from ansible.module_utils.six import string_types
|
from ansible.module_utils.six import string_types
|
||||||
from ansible.module_utils.common.text.converters import to_bytes
|
from ansible.module_utils._text import to_bytes
|
||||||
from ansible.parsing.ajson import AnsibleJSONEncoder
|
from ansible.parsing.ajson import AnsibleJSONEncoder
|
||||||
from ansible.plugins.callback import CallbackBase
|
from ansible.plugins.callback import CallbackBase
|
||||||
|
|
||||||
@@ -104,13 +88,9 @@ class CallbackModule(CallbackBase):
|
|||||||
super(CallbackModule, self).set_options(task_keys=task_keys, var_options=var_options, direct=direct)
|
super(CallbackModule, self).set_options(task_keys=task_keys, var_options=var_options, direct=direct)
|
||||||
|
|
||||||
self.sender = self.get_option('sender')
|
self.sender = self.get_option('sender')
|
||||||
if self.sender is None:
|
|
||||||
self._display.deprecated(
|
|
||||||
'The sender for the mail callback has not been specified. This will be an error in the future',
|
|
||||||
version='6.0.0', collection_name='community.general')
|
|
||||||
self.to = self.get_option('to')
|
self.to = self.get_option('to')
|
||||||
self.smtphost = self.get_option('mta')
|
self.smtphost = self.get_option('mta')
|
||||||
self.smtpport = self.get_option('mtaport')
|
self.smtpport = int(self.get_option('mtaport'))
|
||||||
self.cc = self.get_option('cc')
|
self.cc = self.get_option('cc')
|
||||||
self.bcc = self.get_option('bcc')
|
self.bcc = self.get_option('bcc')
|
||||||
|
|
||||||
@@ -120,34 +100,28 @@ class CallbackModule(CallbackBase):
|
|||||||
|
|
||||||
smtp = smtplib.SMTP(self.smtphost, port=self.smtpport)
|
smtp = smtplib.SMTP(self.smtphost, port=self.smtpport)
|
||||||
|
|
||||||
sender_address = email.utils.parseaddr(self.sender)
|
b_sender = to_bytes(self.sender)
|
||||||
if self.to:
|
b_to = to_bytes(self.to)
|
||||||
to_addresses = email.utils.getaddresses(self.to)
|
b_cc = to_bytes(self.cc)
|
||||||
|
b_bcc = to_bytes(self.bcc)
|
||||||
|
b_subject = to_bytes(subject)
|
||||||
|
b_body = to_bytes(body)
|
||||||
|
|
||||||
|
b_content = b'From: %s\n' % b_sender
|
||||||
|
b_content += b'To: %s\n' % b_to
|
||||||
if self.cc:
|
if self.cc:
|
||||||
cc_addresses = email.utils.getaddresses(self.cc)
|
b_content += b'Cc: %s\n' % b_cc
|
||||||
|
b_content += b'Subject: %s\n\n' % b_subject
|
||||||
|
b_content += b_body
|
||||||
|
|
||||||
|
b_addresses = b_to.split(b',')
|
||||||
|
if self.cc:
|
||||||
|
b_addresses += b_cc.split(b',')
|
||||||
if self.bcc:
|
if self.bcc:
|
||||||
bcc_addresses = email.utils.getaddresses(self.bcc)
|
b_addresses += b_bcc.split(b',')
|
||||||
|
|
||||||
content = 'Date: %s\n' % email.utils.formatdate()
|
for b_address in b_addresses:
|
||||||
content += 'From: %s\n' % email.utils.formataddr(sender_address)
|
smtp.sendmail(b_sender, b_address, b_content)
|
||||||
if self.to:
|
|
||||||
content += 'To: %s\n' % ', '.join([email.utils.formataddr(pair) for pair in to_addresses])
|
|
||||||
if self.cc:
|
|
||||||
content += 'Cc: %s\n' % ', '.join([email.utils.formataddr(pair) for pair in cc_addresses])
|
|
||||||
content += 'Message-ID: %s\n' % email.utils.make_msgid()
|
|
||||||
content += 'Subject: %s\n\n' % subject.strip()
|
|
||||||
content += body
|
|
||||||
|
|
||||||
addresses = to_addresses
|
|
||||||
if self.cc:
|
|
||||||
addresses += cc_addresses
|
|
||||||
if self.bcc:
|
|
||||||
addresses += bcc_addresses
|
|
||||||
|
|
||||||
if not addresses:
|
|
||||||
self._display.warning('No receiver has been specified for the mail callback plugin.')
|
|
||||||
|
|
||||||
smtp.sendmail(self.sender, [address for name, address in addresses], to_bytes(content))
|
|
||||||
|
|
||||||
smtp.quit()
|
smtp.quit()
|
||||||
|
|
||||||
|
|||||||
@@ -10,23 +10,22 @@ DOCUMENTATION = '''
|
|||||||
name: nrdp
|
name: nrdp
|
||||||
type: notification
|
type: notification
|
||||||
author: "Remi VERCHERE (@rverchere)"
|
author: "Remi VERCHERE (@rverchere)"
|
||||||
short_description: Post task results to a Nagios server through nrdp
|
short_description: post task result to a nagios server through nrdp
|
||||||
description:
|
description:
|
||||||
- This callback send playbook result to Nagios.
|
- this callback send playbook result to nagios
|
||||||
- Nagios shall use NRDP to recive passive events.
|
- nagios shall use NRDP to recive passive events
|
||||||
- The passive check is sent to a dedicated host/service for Ansible.
|
- the passive check is sent to a dedicated host/service for ansible
|
||||||
options:
|
options:
|
||||||
url:
|
url:
|
||||||
description: URL of the nrdp server.
|
description: url of the nrdp server
|
||||||
required: true
|
required: True
|
||||||
env:
|
env:
|
||||||
- name : NRDP_URL
|
- name : NRDP_URL
|
||||||
ini:
|
ini:
|
||||||
- section: callback_nrdp
|
- section: callback_nrdp
|
||||||
key: url
|
key: url
|
||||||
type: string
|
|
||||||
validate_certs:
|
validate_certs:
|
||||||
description: Validate the SSL certificate of the nrdp server. (Used for HTTPS URLs.)
|
description: (bool) validate the SSL certificate of the nrdp server. (For HTTPS url)
|
||||||
env:
|
env:
|
||||||
- name: NRDP_VALIDATE_CERTS
|
- name: NRDP_VALIDATE_CERTS
|
||||||
ini:
|
ini:
|
||||||
@@ -34,43 +33,38 @@ DOCUMENTATION = '''
|
|||||||
key: validate_nrdp_certs
|
key: validate_nrdp_certs
|
||||||
- section: callback_nrdp
|
- section: callback_nrdp
|
||||||
key: validate_certs
|
key: validate_certs
|
||||||
type: boolean
|
default: False
|
||||||
default: false
|
|
||||||
aliases: [ validate_nrdp_certs ]
|
aliases: [ validate_nrdp_certs ]
|
||||||
token:
|
token:
|
||||||
description: Token to be allowed to push nrdp events.
|
description: token to be allowed to push nrdp events
|
||||||
required: true
|
required: True
|
||||||
env:
|
env:
|
||||||
- name: NRDP_TOKEN
|
- name: NRDP_TOKEN
|
||||||
ini:
|
ini:
|
||||||
- section: callback_nrdp
|
- section: callback_nrdp
|
||||||
key: token
|
key: token
|
||||||
type: string
|
|
||||||
hostname:
|
hostname:
|
||||||
description: Hostname where the passive check is linked to.
|
description: hostname where the passive check is linked to
|
||||||
required: true
|
required: True
|
||||||
env:
|
env:
|
||||||
- name : NRDP_HOSTNAME
|
- name : NRDP_HOSTNAME
|
||||||
ini:
|
ini:
|
||||||
- section: callback_nrdp
|
- section: callback_nrdp
|
||||||
key: hostname
|
key: hostname
|
||||||
type: string
|
|
||||||
servicename:
|
servicename:
|
||||||
description: Service where the passive check is linked to.
|
description: service where the passive check is linked to
|
||||||
required: true
|
required: True
|
||||||
env:
|
env:
|
||||||
- name : NRDP_SERVICENAME
|
- name : NRDP_SERVICENAME
|
||||||
ini:
|
ini:
|
||||||
- section: callback_nrdp
|
- section: callback_nrdp
|
||||||
key: servicename
|
key: servicename
|
||||||
type: string
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from ansible.module_utils.six.moves.urllib.parse import urlencode
|
from ansible.module_utils.six.moves.urllib.parse import urlencode
|
||||||
from ansible.module_utils.common.text.converters import to_bytes
|
|
||||||
from ansible.module_utils.urls import open_url
|
from ansible.module_utils.urls import open_url
|
||||||
from ansible.plugins.callback import CallbackBase
|
from ansible.plugins.callback import CallbackBase
|
||||||
|
|
||||||
@@ -144,7 +138,7 @@ class CallbackModule(CallbackBase):
|
|||||||
body = {
|
body = {
|
||||||
'cmd': 'submitcheck',
|
'cmd': 'submitcheck',
|
||||||
'token': self.token,
|
'token': self.token,
|
||||||
'XMLDATA': to_bytes(xmldata)
|
'XMLDATA': bytes(xmldata)
|
||||||
}
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# (c) 2017 Ansible Project
|
# (c) 2017 Ansible Project
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
|||||||
@@ -1,515 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# (C) 2021, Victor Martinez <VictorMartinezRubio@gmail.com>
|
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
|
|
||||||
from __future__ import (absolute_import, division, print_function)
|
|
||||||
__metaclass__ = type
|
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
|
||||||
author: Victor Martinez (@v1v) <VictorMartinezRubio@gmail.com>
|
|
||||||
name: opentelemetry
|
|
||||||
type: notification
|
|
||||||
short_description: Create distributed traces with OpenTelemetry
|
|
||||||
version_added: 3.7.0
|
|
||||||
description:
|
|
||||||
- This callback creates distributed traces for each Ansible task with OpenTelemetry.
|
|
||||||
- You can configure the OpenTelemetry exporter and SDK with environment variables.
|
|
||||||
- See U(https://opentelemetry-python.readthedocs.io/en/latest/exporter/otlp/otlp.html).
|
|
||||||
- See U(https://opentelemetry-python.readthedocs.io/en/latest/sdk/environment_variables.html#opentelemetry-sdk-environment-variables).
|
|
||||||
options:
|
|
||||||
hide_task_arguments:
|
|
||||||
default: false
|
|
||||||
type: bool
|
|
||||||
description:
|
|
||||||
- Hide the arguments for a task.
|
|
||||||
env:
|
|
||||||
- name: ANSIBLE_OPENTELEMETRY_HIDE_TASK_ARGUMENTS
|
|
||||||
enable_from_environment:
|
|
||||||
type: str
|
|
||||||
description:
|
|
||||||
- Whether to enable this callback only if the given environment variable exists and it is set to C(true).
|
|
||||||
- This is handy when you use Configuration as Code and want to send distributed traces
|
|
||||||
if running in the CI rather when running Ansible locally.
|
|
||||||
- For such, it evaluates the given I(enable_from_environment) value as environment variable
|
|
||||||
and if set to true this plugin will be enabled.
|
|
||||||
env:
|
|
||||||
- name: ANSIBLE_OPENTELEMETRY_ENABLE_FROM_ENVIRONMENT
|
|
||||||
version_added: 3.8.0
|
|
||||||
otel_service_name:
|
|
||||||
default: ansible
|
|
||||||
type: str
|
|
||||||
description:
|
|
||||||
- The service name resource attribute.
|
|
||||||
env:
|
|
||||||
- name: OTEL_SERVICE_NAME
|
|
||||||
traceparent:
|
|
||||||
default: None
|
|
||||||
type: str
|
|
||||||
description:
|
|
||||||
- The L(W3C Trace Context header traceparent,https://www.w3.org/TR/trace-context-1/#traceparent-header).
|
|
||||||
env:
|
|
||||||
- name: TRACEPARENT
|
|
||||||
requirements:
|
|
||||||
- opentelemetry-api (Python library)
|
|
||||||
- opentelemetry-exporter-otlp (Python library)
|
|
||||||
- opentelemetry-sdk (Python library)
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
EXAMPLES = '''
|
|
||||||
examples: |
|
|
||||||
Enable the plugin in ansible.cfg:
|
|
||||||
[defaults]
|
|
||||||
callbacks_enabled = community.general.opentelemetry
|
|
||||||
|
|
||||||
Set the environment variable:
|
|
||||||
export OTEL_EXPORTER_OTLP_ENDPOINT=<your endpoint (OTLP/HTTP)>
|
|
||||||
export OTEL_EXPORTER_OTLP_HEADERS="authorization=Bearer your_otel_token"
|
|
||||||
export OTEL_SERVICE_NAME=your_service_name
|
|
||||||
'''
|
|
||||||
|
|
||||||
import getpass
|
|
||||||
import os
|
|
||||||
import socket
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
import uuid
|
|
||||||
|
|
||||||
from collections import OrderedDict
|
|
||||||
from os.path import basename
|
|
||||||
|
|
||||||
from ansible.errors import AnsibleError
|
|
||||||
from ansible.module_utils.six import raise_from
|
|
||||||
from ansible.module_utils.six.moves.urllib.parse import urlparse
|
|
||||||
from ansible.plugins.callback import CallbackBase
|
|
||||||
|
|
||||||
try:
|
|
||||||
from opentelemetry import trace
|
|
||||||
from opentelemetry.trace import SpanKind
|
|
||||||
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
|
|
||||||
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
|
|
||||||
from opentelemetry.trace.status import Status, StatusCode
|
|
||||||
from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
|
|
||||||
from opentelemetry.sdk.trace import TracerProvider
|
|
||||||
from opentelemetry.sdk.trace.export import (
|
|
||||||
BatchSpanProcessor
|
|
||||||
)
|
|
||||||
from opentelemetry.util._time import _time_ns
|
|
||||||
except ImportError as imp_exc:
|
|
||||||
OTEL_LIBRARY_IMPORT_ERROR = imp_exc
|
|
||||||
else:
|
|
||||||
OTEL_LIBRARY_IMPORT_ERROR = None
|
|
||||||
|
|
||||||
|
|
||||||
class TaskData:
|
|
||||||
"""
|
|
||||||
Data about an individual task.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, uuid, name, path, play, action, args):
|
|
||||||
self.uuid = uuid
|
|
||||||
self.name = name
|
|
||||||
self.path = path
|
|
||||||
self.play = play
|
|
||||||
self.host_data = OrderedDict()
|
|
||||||
if sys.version_info >= (3, 7):
|
|
||||||
self.start = time.time_ns()
|
|
||||||
else:
|
|
||||||
self.start = _time_ns()
|
|
||||||
self.action = action
|
|
||||||
self.args = args
|
|
||||||
|
|
||||||
def add_host(self, host):
|
|
||||||
if host.uuid in self.host_data:
|
|
||||||
if host.status == 'included':
|
|
||||||
# concatenate task include output from multiple items
|
|
||||||
host.result = '%s\n%s' % (self.host_data[host.uuid].result, host.result)
|
|
||||||
else:
|
|
||||||
return
|
|
||||||
|
|
||||||
self.host_data[host.uuid] = host
|
|
||||||
|
|
||||||
|
|
||||||
class HostData:
|
|
||||||
"""
|
|
||||||
Data about an individual host.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, uuid, name, status, result):
|
|
||||||
self.uuid = uuid
|
|
||||||
self.name = name
|
|
||||||
self.status = status
|
|
||||||
self.result = result
|
|
||||||
if sys.version_info >= (3, 7):
|
|
||||||
self.finish = time.time_ns()
|
|
||||||
else:
|
|
||||||
self.finish = _time_ns()
|
|
||||||
|
|
||||||
|
|
||||||
class OpenTelemetrySource(object):
|
|
||||||
def __init__(self, display):
|
|
||||||
self.ansible_playbook = ""
|
|
||||||
self.ansible_version = None
|
|
||||||
self.session = str(uuid.uuid4())
|
|
||||||
self.host = socket.gethostname()
|
|
||||||
try:
|
|
||||||
self.ip_address = socket.gethostbyname(socket.gethostname())
|
|
||||||
except Exception as e:
|
|
||||||
self.ip_address = None
|
|
||||||
self.user = getpass.getuser()
|
|
||||||
|
|
||||||
self._display = display
|
|
||||||
|
|
||||||
def traceparent_context(self, traceparent):
|
|
||||||
carrier = dict()
|
|
||||||
carrier['traceparent'] = traceparent
|
|
||||||
return TraceContextTextMapPropagator().extract(carrier=carrier)
|
|
||||||
|
|
||||||
def start_task(self, tasks_data, hide_task_arguments, play_name, task):
|
|
||||||
""" record the start of a task for one or more hosts """
|
|
||||||
|
|
||||||
uuid = task._uuid
|
|
||||||
|
|
||||||
if uuid in tasks_data:
|
|
||||||
return
|
|
||||||
|
|
||||||
name = task.get_name().strip()
|
|
||||||
path = task.get_path()
|
|
||||||
action = task.action
|
|
||||||
args = None
|
|
||||||
|
|
||||||
if not task.no_log and not hide_task_arguments:
|
|
||||||
args = task.args
|
|
||||||
|
|
||||||
tasks_data[uuid] = TaskData(uuid, name, path, play_name, action, args)
|
|
||||||
|
|
||||||
def finish_task(self, tasks_data, status, result):
|
|
||||||
""" record the results of a task for a single host """
|
|
||||||
|
|
||||||
task_uuid = result._task._uuid
|
|
||||||
|
|
||||||
if hasattr(result, '_host') and result._host is not None:
|
|
||||||
host_uuid = result._host._uuid
|
|
||||||
host_name = result._host.name
|
|
||||||
else:
|
|
||||||
host_uuid = 'include'
|
|
||||||
host_name = 'include'
|
|
||||||
|
|
||||||
task = tasks_data[task_uuid]
|
|
||||||
|
|
||||||
if self.ansible_version is None and result._task_fields['args'].get('_ansible_version'):
|
|
||||||
self.ansible_version = result._task_fields['args'].get('_ansible_version')
|
|
||||||
|
|
||||||
task.add_host(HostData(host_uuid, host_name, status, result))
|
|
||||||
|
|
||||||
def generate_distributed_traces(self, otel_service_name, ansible_playbook, tasks_data, status, traceparent):
|
|
||||||
""" generate distributed traces from the collected TaskData and HostData """
|
|
||||||
|
|
||||||
tasks = []
|
|
||||||
parent_start_time = None
|
|
||||||
for task_uuid, task in tasks_data.items():
|
|
||||||
if parent_start_time is None:
|
|
||||||
parent_start_time = task.start
|
|
||||||
tasks.append(task)
|
|
||||||
|
|
||||||
trace.set_tracer_provider(
|
|
||||||
TracerProvider(
|
|
||||||
resource=Resource.create({SERVICE_NAME: otel_service_name})
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
processor = BatchSpanProcessor(OTLPSpanExporter())
|
|
||||||
|
|
||||||
trace.get_tracer_provider().add_span_processor(processor)
|
|
||||||
|
|
||||||
tracer = trace.get_tracer(__name__)
|
|
||||||
|
|
||||||
with tracer.start_as_current_span(ansible_playbook, context=self.traceparent_context(traceparent),
|
|
||||||
start_time=parent_start_time, kind=SpanKind.SERVER) as parent:
|
|
||||||
parent.set_status(status)
|
|
||||||
# Populate trace metadata attributes
|
|
||||||
if self.ansible_version is not None:
|
|
||||||
parent.set_attribute("ansible.version", self.ansible_version)
|
|
||||||
parent.set_attribute("ansible.session", self.session)
|
|
||||||
parent.set_attribute("ansible.host.name", self.host)
|
|
||||||
if self.ip_address is not None:
|
|
||||||
parent.set_attribute("ansible.host.ip", self.ip_address)
|
|
||||||
parent.set_attribute("ansible.host.user", self.user)
|
|
||||||
for task in tasks:
|
|
||||||
for host_uuid, host_data in task.host_data.items():
|
|
||||||
with tracer.start_as_current_span(task.name, start_time=task.start, end_on_exit=False) as span:
|
|
||||||
self.update_span_data(task, host_data, span)
|
|
||||||
|
|
||||||
def update_span_data(self, task_data, host_data, span):
|
|
||||||
""" update the span with the given TaskData and HostData """
|
|
||||||
|
|
||||||
name = '[%s] %s: %s' % (host_data.name, task_data.play, task_data.name)
|
|
||||||
|
|
||||||
message = 'success'
|
|
||||||
res = {}
|
|
||||||
rc = 0
|
|
||||||
status = Status(status_code=StatusCode.OK)
|
|
||||||
if host_data.status != 'included':
|
|
||||||
# Support loops
|
|
||||||
if 'results' in host_data.result._result:
|
|
||||||
if host_data.status == 'failed':
|
|
||||||
message = self.get_error_message_from_results(host_data.result._result['results'], task_data.action)
|
|
||||||
enriched_error_message = self.enrich_error_message_from_results(host_data.result._result['results'], task_data.action)
|
|
||||||
else:
|
|
||||||
res = host_data.result._result
|
|
||||||
rc = res.get('rc', 0)
|
|
||||||
message = self.get_error_message(res)
|
|
||||||
enriched_error_message = self.enrich_error_message(res)
|
|
||||||
|
|
||||||
if host_data.status == 'failed':
|
|
||||||
status = Status(status_code=StatusCode.ERROR, description=message)
|
|
||||||
# Record an exception with the task message
|
|
||||||
span.record_exception(BaseException(enriched_error_message))
|
|
||||||
elif host_data.status == 'skipped':
|
|
||||||
message = res['skip_reason'] if 'skip_reason' in res else 'skipped'
|
|
||||||
status = Status(status_code=StatusCode.UNSET)
|
|
||||||
elif host_data.status == 'ignored':
|
|
||||||
status = Status(status_code=StatusCode.UNSET)
|
|
||||||
|
|
||||||
span.set_status(status)
|
|
||||||
if isinstance(task_data.args, dict) and "gather_facts" not in task_data.action:
|
|
||||||
names = tuple(self.transform_ansible_unicode_to_str(k) for k in task_data.args.keys())
|
|
||||||
values = tuple(self.transform_ansible_unicode_to_str(k) for k in task_data.args.values())
|
|
||||||
self.set_span_attribute(span, ("ansible.task.args.name"), names)
|
|
||||||
self.set_span_attribute(span, ("ansible.task.args.value"), values)
|
|
||||||
self.set_span_attribute(span, "ansible.task.module", task_data.action)
|
|
||||||
self.set_span_attribute(span, "ansible.task.message", message)
|
|
||||||
self.set_span_attribute(span, "ansible.task.name", name)
|
|
||||||
self.set_span_attribute(span, "ansible.task.result", rc)
|
|
||||||
self.set_span_attribute(span, "ansible.task.host.name", host_data.name)
|
|
||||||
self.set_span_attribute(span, "ansible.task.host.status", host_data.status)
|
|
||||||
# This will allow to enrich the service map
|
|
||||||
self.add_attributes_for_service_map_if_possible(span, task_data)
|
|
||||||
span.end(end_time=host_data.finish)
|
|
||||||
|
|
||||||
def set_span_attribute(self, span, attributeName, attributeValue):
|
|
||||||
""" update the span attribute with the given attribute and value if not None """
|
|
||||||
|
|
||||||
if span is None and self._display is not None:
|
|
||||||
self._display.warning('span object is None. Please double check if that is expected.')
|
|
||||||
else:
|
|
||||||
if attributeValue is not None:
|
|
||||||
span.set_attribute(attributeName, attributeValue)
|
|
||||||
|
|
||||||
def add_attributes_for_service_map_if_possible(self, span, task_data):
|
|
||||||
"""Update the span attributes with the service that the task interacted with, if possible."""
|
|
||||||
|
|
||||||
redacted_url = self.parse_and_redact_url_if_possible(task_data.args)
|
|
||||||
if redacted_url:
|
|
||||||
self.set_span_attribute(span, "http.url", redacted_url.geturl())
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def parse_and_redact_url_if_possible(args):
|
|
||||||
"""Parse and redact the url, if possible."""
|
|
||||||
|
|
||||||
try:
|
|
||||||
parsed_url = urlparse(OpenTelemetrySource.url_from_args(args))
|
|
||||||
except ValueError:
|
|
||||||
return None
|
|
||||||
|
|
||||||
if OpenTelemetrySource.is_valid_url(parsed_url):
|
|
||||||
return OpenTelemetrySource.redact_user_password(parsed_url)
|
|
||||||
return None
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def url_from_args(args):
|
|
||||||
# the order matters
|
|
||||||
url_args = ("url", "api_url", "baseurl", "repo", "server_url", "chart_repo_url", "registry_url", "endpoint", "uri", "updates_url")
|
|
||||||
for arg in url_args:
|
|
||||||
if args is not None and args.get(arg):
|
|
||||||
return args.get(arg)
|
|
||||||
return ""
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def redact_user_password(url):
|
|
||||||
return url._replace(netloc=url.hostname) if url.password else url
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def is_valid_url(url):
|
|
||||||
if all([url.scheme, url.netloc, url.hostname]):
|
|
||||||
return "{{" not in url.hostname
|
|
||||||
return False
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def transform_ansible_unicode_to_str(value):
|
|
||||||
parsed_url = urlparse(str(value))
|
|
||||||
if OpenTelemetrySource.is_valid_url(parsed_url):
|
|
||||||
return OpenTelemetrySource.redact_user_password(parsed_url).geturl()
|
|
||||||
return str(value)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_error_message(result):
|
|
||||||
if result.get('exception') is not None:
|
|
||||||
return OpenTelemetrySource._last_line(result['exception'])
|
|
||||||
return result.get('msg', 'failed')
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_error_message_from_results(results, action):
|
|
||||||
for result in results:
|
|
||||||
if result.get('failed', False):
|
|
||||||
return ('{0}({1}) - {2}').format(action, result.get('item', 'none'), OpenTelemetrySource.get_error_message(result))
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _last_line(text):
|
|
||||||
lines = text.strip().split('\n')
|
|
||||||
return lines[-1]
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def enrich_error_message(result):
|
|
||||||
message = result.get('msg', 'failed')
|
|
||||||
exception = result.get('exception')
|
|
||||||
stderr = result.get('stderr')
|
|
||||||
return ('message: "{0}"\nexception: "{1}"\nstderr: "{2}"').format(message, exception, stderr)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def enrich_error_message_from_results(results, action):
|
|
||||||
message = ""
|
|
||||||
for result in results:
|
|
||||||
if result.get('failed', False):
|
|
||||||
message = ('{0}({1}) - {2}\n{3}').format(action, result.get('item', 'none'), OpenTelemetrySource.enrich_error_message(result), message)
|
|
||||||
return message
|
|
||||||
|
|
||||||
|
|
||||||
class CallbackModule(CallbackBase):
|
|
||||||
"""
|
|
||||||
This callback creates distributed traces.
|
|
||||||
"""
|
|
||||||
|
|
||||||
CALLBACK_VERSION = 2.0
|
|
||||||
CALLBACK_TYPE = 'notification'
|
|
||||||
CALLBACK_NAME = 'community.general.opentelemetry'
|
|
||||||
CALLBACK_NEEDS_ENABLED = True
|
|
||||||
|
|
||||||
def __init__(self, display=None):
|
|
||||||
super(CallbackModule, self).__init__(display=display)
|
|
||||||
self.hide_task_arguments = None
|
|
||||||
self.otel_service_name = None
|
|
||||||
self.ansible_playbook = None
|
|
||||||
self.play_name = None
|
|
||||||
self.tasks_data = None
|
|
||||||
self.errors = 0
|
|
||||||
self.disabled = False
|
|
||||||
self.traceparent = False
|
|
||||||
|
|
||||||
if OTEL_LIBRARY_IMPORT_ERROR:
|
|
||||||
raise_from(
|
|
||||||
AnsibleError('The `opentelemetry-api`, `opentelemetry-exporter-otlp` or `opentelemetry-sdk` must be installed to use this plugin'),
|
|
||||||
OTEL_LIBRARY_IMPORT_ERROR)
|
|
||||||
|
|
||||||
self.tasks_data = OrderedDict()
|
|
||||||
|
|
||||||
self.opentelemetry = OpenTelemetrySource(display=self._display)
|
|
||||||
|
|
||||||
def set_options(self, task_keys=None, var_options=None, direct=None):
|
|
||||||
super(CallbackModule, self).set_options(task_keys=task_keys,
|
|
||||||
var_options=var_options,
|
|
||||||
direct=direct)
|
|
||||||
|
|
||||||
environment_variable = self.get_option('enable_from_environment')
|
|
||||||
if environment_variable is not None and os.environ.get(environment_variable, 'false').lower() != 'true':
|
|
||||||
self.disabled = True
|
|
||||||
self._display.warning("The `enable_from_environment` option has been set and {0} is not enabled. "
|
|
||||||
"Disabling the `opentelemetry` callback plugin.".format(environment_variable))
|
|
||||||
|
|
||||||
self.hide_task_arguments = self.get_option('hide_task_arguments')
|
|
||||||
|
|
||||||
self.otel_service_name = self.get_option('otel_service_name')
|
|
||||||
|
|
||||||
if not self.otel_service_name:
|
|
||||||
self.otel_service_name = 'ansible'
|
|
||||||
|
|
||||||
# See https://github.com/open-telemetry/opentelemetry-specification/issues/740
|
|
||||||
self.traceparent = self.get_option('traceparent')
|
|
||||||
|
|
||||||
def v2_playbook_on_start(self, playbook):
|
|
||||||
self.ansible_playbook = basename(playbook._file_name)
|
|
||||||
|
|
||||||
def v2_playbook_on_play_start(self, play):
|
|
||||||
self.play_name = play.get_name()
|
|
||||||
|
|
||||||
def v2_runner_on_no_hosts(self, task):
|
|
||||||
self.opentelemetry.start_task(
|
|
||||||
self.tasks_data,
|
|
||||||
self.hide_task_arguments,
|
|
||||||
self.play_name,
|
|
||||||
task
|
|
||||||
)
|
|
||||||
|
|
||||||
def v2_playbook_on_task_start(self, task, is_conditional):
|
|
||||||
self.opentelemetry.start_task(
|
|
||||||
self.tasks_data,
|
|
||||||
self.hide_task_arguments,
|
|
||||||
self.play_name,
|
|
||||||
task
|
|
||||||
)
|
|
||||||
|
|
||||||
def v2_playbook_on_cleanup_task_start(self, task):
|
|
||||||
self.opentelemetry.start_task(
|
|
||||||
self.tasks_data,
|
|
||||||
self.hide_task_arguments,
|
|
||||||
self.play_name,
|
|
||||||
task
|
|
||||||
)
|
|
||||||
|
|
||||||
def v2_playbook_on_handler_task_start(self, task):
|
|
||||||
self.opentelemetry.start_task(
|
|
||||||
self.tasks_data,
|
|
||||||
self.hide_task_arguments,
|
|
||||||
self.play_name,
|
|
||||||
task
|
|
||||||
)
|
|
||||||
|
|
||||||
def v2_runner_on_failed(self, result, ignore_errors=False):
|
|
||||||
if ignore_errors:
|
|
||||||
status = 'ignored'
|
|
||||||
else:
|
|
||||||
status = 'failed'
|
|
||||||
self.errors += 1
|
|
||||||
|
|
||||||
self.opentelemetry.finish_task(
|
|
||||||
self.tasks_data,
|
|
||||||
status,
|
|
||||||
result
|
|
||||||
)
|
|
||||||
|
|
||||||
def v2_runner_on_ok(self, result):
|
|
||||||
self.opentelemetry.finish_task(
|
|
||||||
self.tasks_data,
|
|
||||||
'ok',
|
|
||||||
result
|
|
||||||
)
|
|
||||||
|
|
||||||
def v2_runner_on_skipped(self, result):
|
|
||||||
self.opentelemetry.finish_task(
|
|
||||||
self.tasks_data,
|
|
||||||
'skipped',
|
|
||||||
result
|
|
||||||
)
|
|
||||||
|
|
||||||
def v2_playbook_on_include(self, included_file):
|
|
||||||
self.opentelemetry.finish_task(
|
|
||||||
self.tasks_data,
|
|
||||||
'included',
|
|
||||||
included_file
|
|
||||||
)
|
|
||||||
|
|
||||||
def v2_playbook_on_stats(self, stats):
|
|
||||||
if self.errors == 0:
|
|
||||||
status = Status(status_code=StatusCode.OK)
|
|
||||||
else:
|
|
||||||
status = Status(status_code=StatusCode.ERROR)
|
|
||||||
self.opentelemetry.generate_distributed_traces(
|
|
||||||
self.otel_service_name,
|
|
||||||
self.ansible_playbook,
|
|
||||||
self.tasks_data,
|
|
||||||
status,
|
|
||||||
self.traceparent
|
|
||||||
)
|
|
||||||
|
|
||||||
def v2_runner_on_async_failed(self, result, **kwargs):
|
|
||||||
self.errors += 1
|
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# (c) 2012, Michael DeHaan, <michael.dehaan@gmail.com>
|
# (c) 2012, Michael DeHaan, <michael.dehaan@gmail.com>
|
||||||
# (c) 2017 Ansible Project
|
# (c) 2017 Ansible Project
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
@@ -21,11 +20,11 @@ DOCUMENTATION = '''
|
|||||||
- In 2.8, this callback has been renamed from C(osx_say) into M(community.general.say).
|
- In 2.8, this callback has been renamed from C(osx_say) into M(community.general.say).
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
import distutils.spawn
|
||||||
import platform
|
import platform
|
||||||
import subprocess
|
import subprocess
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from ansible.module_utils.common.process import get_bin_path
|
|
||||||
from ansible.plugins.callback import CallbackBase
|
from ansible.plugins.callback import CallbackBase
|
||||||
|
|
||||||
|
|
||||||
@@ -47,24 +46,21 @@ class CallbackModule(CallbackBase):
|
|||||||
self.HAPPY_VOICE = None
|
self.HAPPY_VOICE = None
|
||||||
self.LASER_VOICE = None
|
self.LASER_VOICE = None
|
||||||
|
|
||||||
try:
|
self.synthesizer = distutils.spawn.find_executable('say')
|
||||||
self.synthesizer = get_bin_path('say')
|
if not self.synthesizer:
|
||||||
if platform.system() != 'Darwin':
|
self.synthesizer = distutils.spawn.find_executable('espeak')
|
||||||
# 'say' binary available, it might be GNUstep tool which doesn't support 'voice' parameter
|
if self.synthesizer:
|
||||||
self._display.warning("'say' executable found but system is '%s': ignoring voice parameter" % platform.system())
|
|
||||||
else:
|
|
||||||
self.FAILED_VOICE = 'Zarvox'
|
|
||||||
self.REGULAR_VOICE = 'Trinoids'
|
|
||||||
self.HAPPY_VOICE = 'Cellos'
|
|
||||||
self.LASER_VOICE = 'Princess'
|
|
||||||
except ValueError:
|
|
||||||
try:
|
|
||||||
self.synthesizer = get_bin_path('espeak')
|
|
||||||
self.FAILED_VOICE = 'klatt'
|
self.FAILED_VOICE = 'klatt'
|
||||||
self.HAPPY_VOICE = 'f5'
|
self.HAPPY_VOICE = 'f5'
|
||||||
self.LASER_VOICE = 'whisper'
|
self.LASER_VOICE = 'whisper'
|
||||||
except ValueError:
|
elif platform.system() != 'Darwin':
|
||||||
self.synthesizer = None
|
# 'say' binary available, it might be GNUstep tool which doesn't support 'voice' parameter
|
||||||
|
self._display.warning("'say' executable found but system is '%s': ignoring voice parameter" % platform.system())
|
||||||
|
else:
|
||||||
|
self.FAILED_VOICE = 'Zarvox'
|
||||||
|
self.REGULAR_VOICE = 'Trinoids'
|
||||||
|
self.HAPPY_VOICE = 'Cellos'
|
||||||
|
self.LASER_VOICE = 'Princess'
|
||||||
|
|
||||||
# plugin disable itself if say is not present
|
# plugin disable itself if say is not present
|
||||||
# ansible will not call any callback if disabled is set to True
|
# ansible will not call any callback if disabled is set to True
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user