mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-04-30 02:16:50 +00:00
Compare commits
375 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
be5b4adf5b | ||
|
|
62b45e235d | ||
|
|
f99508b307 | ||
|
|
9afc096cd2 | ||
|
|
27c0c29cf3 | ||
|
|
c890a161ae | ||
|
|
c911aa8a84 | ||
|
|
a3cb344689 | ||
|
|
bd4112e87b | ||
|
|
ec9b1fc503 | ||
|
|
5467334117 | ||
|
|
e962b9237d | ||
|
|
48c36bc72b | ||
|
|
56bb7d7b9d | ||
|
|
af2438f664 | ||
|
|
a68de9bfb6 | ||
|
|
4614047132 | ||
|
|
6b02eaa795 | ||
|
|
6f774fd4a5 | ||
|
|
f05618a6f2 | ||
|
|
98a956a9d6 | ||
|
|
60d51f7b49 | ||
|
|
245be47a4e | ||
|
|
6d346ddadd | ||
|
|
cb969fc468 | ||
|
|
ec6c2a76ad | ||
|
|
b22777de44 | ||
|
|
151f6c9ce3 | ||
|
|
0acaad60c8 | ||
|
|
a06c1f5c9a | ||
|
|
becda864c4 | ||
|
|
92d077e816 | ||
|
|
700623863c | ||
|
|
31f57b9385 | ||
|
|
14038511a1 | ||
|
|
3db0a11148 | ||
|
|
05ba79c5fe | ||
|
|
0df708b15a | ||
|
|
1829ad4fdc | ||
|
|
0e99b006a2 | ||
|
|
f66bd1035d | ||
|
|
7732d64abb | ||
|
|
03f3b74934 | ||
|
|
29e9afcbf4 | ||
|
|
11ba71c802 | ||
|
|
d3badc6d43 | ||
|
|
92a07f1794 | ||
|
|
7a44dbfe45 | ||
|
|
4f9e7bd793 | ||
|
|
872bc91096 | ||
|
|
641b0693b4 | ||
|
|
45a3396ab0 | ||
|
|
e38f9e5cfc | ||
|
|
60ba39da58 | ||
|
|
f6fa7fb273 | ||
|
|
899fcb8749 | ||
|
|
a5c448d6e8 | ||
|
|
74bd7f1471 | ||
|
|
7e6514b4d4 | ||
|
|
3c7f05c42d | ||
|
|
a13a6d284c | ||
|
|
122086e83b | ||
|
|
92e4bd184d | ||
|
|
12f2d71950 | ||
|
|
e3f72bca4f | ||
|
|
429b4b14a8 | ||
|
|
2d12c6678c | ||
|
|
474c7a7240 | ||
|
|
434032080e | ||
|
|
eec5c82a55 | ||
|
|
97ea891377 | ||
|
|
b3ad22f33f | ||
|
|
977f53f823 | ||
|
|
4c26dc0760 | ||
|
|
3c6131b451 | ||
|
|
2499c1132d | ||
|
|
3fe559b88f | ||
|
|
28fed38757 | ||
|
|
f2196d452f | ||
|
|
07124473cc | ||
|
|
a56cec8582 | ||
|
|
5c2e9e0c5b | ||
|
|
df5818282b | ||
|
|
69aea38683 | ||
|
|
01dce04e33 | ||
|
|
5ab43f0ff1 | ||
|
|
910fb933a7 | ||
|
|
7537674d4b | ||
|
|
6e42e442bc | ||
|
|
161539729d | ||
|
|
8f76c847fe | ||
|
|
3f29683191 | ||
|
|
a89990ab9b | ||
|
|
7bc937b5e8 | ||
|
|
a1c39cc882 | ||
|
|
859039c47a | ||
|
|
b3f669a574 | ||
|
|
770bae70db | ||
|
|
0a6c57bc4d | ||
|
|
459b9f3f9a | ||
|
|
d9436069f1 | ||
|
|
fcf1cb7fbc | ||
|
|
5727f1afd4 | ||
|
|
fbada0026e | ||
|
|
c4373d5ed5 | ||
|
|
54291ab1d1 | ||
|
|
bbd67b5017 | ||
|
|
6d6d3e8039 | ||
|
|
e31999f369 | ||
|
|
09f99e66fe | ||
|
|
5491ff7c6a | ||
|
|
163f3ee305 | ||
|
|
4152770281 | ||
|
|
ecc9afab0b | ||
|
|
6f9b954048 | ||
|
|
74cd18b682 | ||
|
|
0b64fc1ee4 | ||
|
|
5fe39082d5 | ||
|
|
0ff52abfdd | ||
|
|
653ae1b48a | ||
|
|
16d124bbe2 | ||
|
|
4455df380e | ||
|
|
06c7ba640e | ||
|
|
a6f6bcc555 | ||
|
|
cd06325f6b | ||
|
|
a20ee0e816 | ||
|
|
acb6a2f76d | ||
|
|
5a1c68cb62 | ||
|
|
776374ee78 | ||
|
|
c916052124 | ||
|
|
88b1fbbdf0 | ||
|
|
48db44f199 | ||
|
|
eb4c01260f | ||
|
|
10561e6f30 | ||
|
|
5c26387a54 | ||
|
|
8226ea87cf | ||
|
|
411c7d4f32 | ||
|
|
a2f377c621 | ||
|
|
ac0956ed6f | ||
|
|
0d02265a23 | ||
|
|
f38d974d42 | ||
|
|
a975574618 | ||
|
|
b05fa358e6 | ||
|
|
c44118ac3c | ||
|
|
886d4a6596 | ||
|
|
94e3635c0a | ||
|
|
3d03c373ff | ||
|
|
8fc11fe88f | ||
|
|
cecaa1840d | ||
|
|
2429e228a4 | ||
|
|
c8410a924e | ||
|
|
8a2ac4f1eb | ||
|
|
9553dd9ddf | ||
|
|
e63c2f54cf | ||
|
|
c71f662d55 | ||
|
|
9069f673e2 | ||
|
|
67d1b6c413 | ||
|
|
3506f73da1 | ||
|
|
d0b4e91cac | ||
|
|
ce1b9887b1 | ||
|
|
107df41d9c | ||
|
|
39f3b151e8 | ||
|
|
ccf7f62325 | ||
|
|
a8c41ac4c1 | ||
|
|
5b3b7a1fb1 | ||
|
|
9fb686fe35 | ||
|
|
93be499f26 | ||
|
|
cc72fa0786 | ||
|
|
658637dc70 | ||
|
|
b1f4604067 | ||
|
|
064f76c27b | ||
|
|
86166ccade | ||
|
|
1180843e35 | ||
|
|
26fe42776c | ||
|
|
5874711c6e | ||
|
|
12fa2452d8 | ||
|
|
a894f8e7eb | ||
|
|
410288401b | ||
|
|
67ddb567c9 | ||
|
|
3de4682193 | ||
|
|
8df9d0d7de | ||
|
|
ec6496024f | ||
|
|
447d4b0267 | ||
|
|
b523d1b1c9 | ||
|
|
464812a2c2 | ||
|
|
5e6b8e5327 | ||
|
|
24b74cc4b9 | ||
|
|
c814fd0530 | ||
|
|
1bdf8fc025 | ||
|
|
3b109abe18 | ||
|
|
cc8009621f | ||
|
|
c7e2875a4d | ||
|
|
24f2b980b7 | ||
|
|
1d86d49688 | ||
|
|
5b4f41748d | ||
|
|
29a2df8e6b | ||
|
|
8610223d03 | ||
|
|
fea0ffa5aa | ||
|
|
e7ccbc2f18 | ||
|
|
92df5e8fec | ||
|
|
5d9a7ab240 | ||
|
|
d4fb6bf8a6 | ||
|
|
7fc7af306c | ||
|
|
c4e2b73193 | ||
|
|
96dfb89b01 | ||
|
|
daaa008713 | ||
|
|
2d660a1252 | ||
|
|
83080cc005 | ||
|
|
7c913b239a | ||
|
|
a7d1b0fc52 | ||
|
|
ab84f1632f | ||
|
|
8ef77d8664 | ||
|
|
fe18b05f08 | ||
|
|
84e0190eee | ||
|
|
bc6ae849b3 | ||
|
|
002f137134 | ||
|
|
0bc5f24863 | ||
|
|
4700accbff | ||
|
|
d356e255e0 | ||
|
|
89ad40db41 | ||
|
|
199ba0a170 | ||
|
|
293021c3dd | ||
|
|
a32f1d699b | ||
|
|
deaad6e547 | ||
|
|
0bf84ba2b6 | ||
|
|
38479ee9ff | ||
|
|
ac302eb77d | ||
|
|
27cb0c9090 | ||
|
|
6af74d1ba6 | ||
|
|
80f48cceb4 | ||
|
|
f93883aa20 | ||
|
|
4123934b46 | ||
|
|
2f1df973a6 | ||
|
|
e4472b322b | ||
|
|
76ebda7faf | ||
|
|
94472dd7e5 | ||
|
|
37dd6ec8a3 | ||
|
|
41d87f5c9d | ||
|
|
40f1ab31f5 | ||
|
|
2ae41fa83f | ||
|
|
529af4984c | ||
|
|
d73f977b7a | ||
|
|
afd754e384 | ||
|
|
ea389e7045 | ||
|
|
d9b0c42f5f | ||
|
|
982b8d89b7 | ||
|
|
26df6c7657 | ||
|
|
43f8adf1a5 | ||
|
|
7e978c77b4 | ||
|
|
ecc048bc12 | ||
|
|
593d302f0b | ||
|
|
249126f429 | ||
|
|
96d5e6e50e | ||
|
|
e9071e9871 | ||
|
|
9c9c4cbc3e | ||
|
|
573a7b97c6 | ||
|
|
4598758419 | ||
|
|
7dc4429c9c | ||
|
|
5192ffe5b3 | ||
|
|
3607e3d012 | ||
|
|
e3a3c6d58f | ||
|
|
e5bc38d856 | ||
|
|
b79ac4f0ac | ||
|
|
c84fb5577b | ||
|
|
14e86bde07 | ||
|
|
9571ec7c72 | ||
|
|
e1b5ddb050 | ||
|
|
34519a5ecb | ||
|
|
4cb4c608d0 | ||
|
|
2eec853e9e | ||
|
|
2942eda8e0 | ||
|
|
73b54139d6 | ||
|
|
0f59bb7a99 | ||
|
|
76d0222a83 | ||
|
|
158947f5e5 | ||
|
|
8989b6c4d4 | ||
|
|
57e28e5a73 | ||
|
|
e7480ad29e | ||
|
|
b9244130ef | ||
|
|
9f340861ad | ||
|
|
b16263ebd7 | ||
|
|
5322dd942e | ||
|
|
9a16eaf9ba | ||
|
|
5b2711bbd3 | ||
|
|
132faeae34 | ||
|
|
c517f1c483 | ||
|
|
fd811df414 | ||
|
|
b6c6253bfc | ||
|
|
7bbf32dc0e | ||
|
|
2963004991 | ||
|
|
229ed6dad9 | ||
|
|
37c8560542 | ||
|
|
1a8f172186 | ||
|
|
52126b8fae | ||
|
|
58f9860ba7 | ||
|
|
e3fb817a21 | ||
|
|
e1148e6bdc | ||
|
|
c0fd10e793 | ||
|
|
cac55beb4f | ||
|
|
ce65eb8736 | ||
|
|
f9a56b9a9b | ||
|
|
daed4dcc94 | ||
|
|
a24ee93f23 | ||
|
|
3a24aa5b6d | ||
|
|
a78f7b1e6a | ||
|
|
83318c36aa | ||
|
|
9dd2b71d04 | ||
|
|
6cefde622c | ||
|
|
21b16c1c77 | ||
|
|
9f3103e891 | ||
|
|
8990f97b45 | ||
|
|
ca8ecb1df1 | ||
|
|
e794fa74da | ||
|
|
8451fc36ca | ||
|
|
b0797d329c | ||
|
|
feb1ecbfcd | ||
|
|
45972c23d4 | ||
|
|
a3989095af | ||
|
|
b2c773996d | ||
|
|
caecb2297f | ||
|
|
5259caacae | ||
|
|
01d8c7b769 | ||
|
|
6e0142fe3a | ||
|
|
70c8042c99 | ||
|
|
1053545870 | ||
|
|
9e38161400 | ||
|
|
0d50131d5e | ||
|
|
60ba7cab93 | ||
|
|
ecb68aa5d2 | ||
|
|
86f19cb5d3 | ||
|
|
9a18963364 | ||
|
|
2612ceee37 | ||
|
|
69b72e4a8e | ||
|
|
3314d5c8db | ||
|
|
b11da288d2 | ||
|
|
df7fe19bbe | ||
|
|
fd2cd5f28c | ||
|
|
3716187fc3 | ||
|
|
ec4cf55566 | ||
|
|
03966624ba | ||
|
|
d95f4d68a3 | ||
|
|
1d61541951 | ||
|
|
2574cb0dea | ||
|
|
71f9674835 | ||
|
|
49e2a8633e | ||
|
|
f0940d82dc | ||
|
|
8f60f3aef9 | ||
|
|
800bc01112 | ||
|
|
ac3c04357c | ||
|
|
c31499a411 | ||
|
|
1ae6c82558 | ||
|
|
d2d7deb4ec | ||
|
|
06f13e79b1 | ||
|
|
1c4ab7fafc | ||
|
|
a0ad2d5849 | ||
|
|
2a3819a696 | ||
|
|
0129346eda | ||
|
|
6f8f12f762 | ||
|
|
5041ebe5b2 | ||
|
|
961767e2dd | ||
|
|
d46e12e280 | ||
|
|
5a5188a453 | ||
|
|
58ce19d2c2 | ||
|
|
54df0c9b3a | ||
|
|
7d72300c36 | ||
|
|
e690317e3a | ||
|
|
572caeaa39 | ||
|
|
43cb5a0d54 | ||
|
|
d96b2642bc | ||
|
|
e7ee90a937 | ||
|
|
ec886203fc | ||
|
|
da2c87ce0d | ||
|
|
4792e21416 | ||
|
|
95e509753e | ||
|
|
22ed5048a2 |
@@ -43,6 +43,8 @@ variables:
|
||||
value: ansible_collections/community/general
|
||||
- name: coverageBranches
|
||||
value: main
|
||||
- name: pipelinesCoverage
|
||||
value: coverage
|
||||
- name: entryPoint
|
||||
value: tests/utils/shippable/shippable.sh
|
||||
- name: fetchDepth
|
||||
@@ -70,6 +72,7 @@ stages:
|
||||
- test: 2
|
||||
- test: 3
|
||||
- test: 4
|
||||
- test: extra
|
||||
- stage: Sanity_2_18
|
||||
displayName: Sanity 2.18
|
||||
dependsOn: []
|
||||
@@ -169,10 +172,10 @@ stages:
|
||||
parameters:
|
||||
testFormat: devel/{0}
|
||||
targets:
|
||||
- name: Alpine 3.21
|
||||
test: alpine/3.21
|
||||
# - name: Fedora 41
|
||||
# test: fedora/41
|
||||
- name: Alpine 3.20
|
||||
test: alpine/3.20
|
||||
# - name: Fedora 40
|
||||
# test: fedora/40
|
||||
- name: Ubuntu 22.04
|
||||
test: ubuntu/22.04
|
||||
- name: Ubuntu 24.04
|
||||
@@ -187,14 +190,14 @@ stages:
|
||||
parameters:
|
||||
testFormat: devel/{0}
|
||||
targets:
|
||||
- name: macOS 15.3
|
||||
test: macos/15.3
|
||||
- name: RHEL 9.5
|
||||
test: rhel/9.5
|
||||
- name: FreeBSD 14.2
|
||||
test: freebsd/14.2
|
||||
- name: FreeBSD 13.5
|
||||
test: freebsd/13.5
|
||||
- name: macOS 14.3
|
||||
test: macos/14.3
|
||||
- name: RHEL 9.4
|
||||
test: rhel/9.4
|
||||
- name: FreeBSD 14.1
|
||||
test: freebsd/14.1
|
||||
- name: FreeBSD 13.4
|
||||
test: freebsd/13.4
|
||||
groups:
|
||||
- 1
|
||||
- 2
|
||||
@@ -207,12 +210,8 @@ stages:
|
||||
parameters:
|
||||
testFormat: 2.18/{0}
|
||||
targets:
|
||||
- name: macOS 14.3
|
||||
test: macos/14.3
|
||||
- name: RHEL 9.4
|
||||
test: rhel/9.4
|
||||
- name: FreeBSD 14.1
|
||||
test: freebsd/14.1
|
||||
groups:
|
||||
- 1
|
||||
- 2
|
||||
@@ -229,6 +228,8 @@ stages:
|
||||
test: freebsd/13.3
|
||||
- name: RHEL 9.3
|
||||
test: rhel/9.3
|
||||
- name: FreeBSD 14.0
|
||||
test: freebsd/14.0
|
||||
groups:
|
||||
- 1
|
||||
- 2
|
||||
@@ -265,10 +266,10 @@ stages:
|
||||
parameters:
|
||||
testFormat: devel/linux/{0}
|
||||
targets:
|
||||
- name: Fedora 41
|
||||
test: fedora41
|
||||
- name: Alpine 3.21
|
||||
test: alpine321
|
||||
- name: Fedora 40
|
||||
test: fedora40
|
||||
- name: Alpine 3.20
|
||||
test: alpine320
|
||||
- name: Ubuntu 22.04
|
||||
test: ubuntu2204
|
||||
- name: Ubuntu 24.04
|
||||
@@ -285,10 +286,6 @@ stages:
|
||||
parameters:
|
||||
testFormat: 2.18/linux/{0}
|
||||
targets:
|
||||
- name: Fedora 40
|
||||
test: fedora40
|
||||
- name: Alpine 3.20
|
||||
test: alpine320
|
||||
- name: Ubuntu 24.04
|
||||
test: ubuntu2404
|
||||
groups:
|
||||
|
||||
@@ -28,6 +28,16 @@ jobs:
|
||||
- bash: .azure-pipelines/scripts/report-coverage.sh
|
||||
displayName: Generate Coverage Report
|
||||
condition: gt(variables.coverageFileCount, 0)
|
||||
- task: PublishCodeCoverageResults@1
|
||||
inputs:
|
||||
codeCoverageTool: Cobertura
|
||||
# Azure Pipelines only accepts a single coverage data file.
|
||||
# That means only Python or PowerShell coverage can be uploaded, but not both.
|
||||
# Set the "pipelinesCoverage" variable to determine which type is uploaded.
|
||||
# Use "coverage" for Python and "coverage-powershell" for PowerShell.
|
||||
summaryFileLocation: "$(outputPath)/reports/$(pipelinesCoverage).xml"
|
||||
displayName: Publish to Azure Pipelines
|
||||
condition: gt(variables.coverageFileCount, 0)
|
||||
- bash: .azure-pipelines/scripts/publish-codecov.py "$(outputPath)"
|
||||
displayName: Publish to codecov.io
|
||||
condition: gt(variables.coverageFileCount, 0)
|
||||
|
||||
48
.github/BOTMETA.yml
vendored
48
.github/BOTMETA.yml
vendored
@@ -61,7 +61,6 @@ files:
|
||||
$callbacks/elastic.py:
|
||||
keywords: apm observability
|
||||
maintainers: v1v
|
||||
$callbacks/hipchat.py: {}
|
||||
$callbacks/jabber.py: {}
|
||||
$callbacks/log_plays.py: {}
|
||||
$callbacks/loganalytics.py:
|
||||
@@ -136,6 +135,8 @@ files:
|
||||
$doc_fragments/xenserver.py:
|
||||
labels: xenserver
|
||||
maintainers: bvitnik
|
||||
$filters/accumulate.py:
|
||||
maintainers: VannTen
|
||||
$filters/counter.py:
|
||||
maintainers: keilr
|
||||
$filters/crc32.py:
|
||||
@@ -212,6 +213,8 @@ files:
|
||||
maintainers: opoplawski
|
||||
$inventories/gitlab_runners.py:
|
||||
maintainers: morph027
|
||||
$inventories/iocage.py:
|
||||
maintainers: vbotka
|
||||
$inventories/icinga2.py:
|
||||
maintainers: BongoEADGC6
|
||||
$inventories/linode.py:
|
||||
@@ -308,8 +311,12 @@ files:
|
||||
maintainers: delineaKrehl tylerezimmerman
|
||||
$module_utils/:
|
||||
labels: module_utils
|
||||
$module_utils/android_sdkmanager.py:
|
||||
maintainers: shamilovstas
|
||||
$module_utils/btrfs.py:
|
||||
maintainers: gnfzdz
|
||||
$module_utils/cmd_runner_fmt.py:
|
||||
maintainers: russoz
|
||||
$module_utils/cmd_runner.py:
|
||||
maintainers: russoz
|
||||
$module_utils/deps.py:
|
||||
@@ -417,6 +424,8 @@ files:
|
||||
ignore: DavidWittman jiuka
|
||||
labels: alternatives
|
||||
maintainers: mulby
|
||||
$modules/android_sdk.py:
|
||||
maintainers: shamilovstas
|
||||
$modules/ansible_galaxy_install.py:
|
||||
maintainers: russoz
|
||||
$modules/apache2_mod_proxy.py:
|
||||
@@ -447,7 +456,7 @@ files:
|
||||
$modules/bearychat.py:
|
||||
maintainers: tonyseek
|
||||
$modules/bigpanda.py:
|
||||
ignore: hkariti
|
||||
maintainers: hkariti
|
||||
$modules/bitbucket_:
|
||||
maintainers: catcombo
|
||||
$modules/bootc_manage.py:
|
||||
@@ -505,6 +514,8 @@ files:
|
||||
ignore: skornehl
|
||||
$modules/dconf.py:
|
||||
maintainers: azaghal
|
||||
$modules/decompress.py:
|
||||
maintainers: shamilovstas
|
||||
$modules/deploy_helper.py:
|
||||
maintainers: ramondelafuente
|
||||
$modules/dimensiondata_network.py:
|
||||
@@ -761,6 +772,8 @@ files:
|
||||
maintainers: sermilrod
|
||||
$modules/jenkins_job_info.py:
|
||||
maintainers: stpierre
|
||||
$modules/jenkins_node.py:
|
||||
maintainers: phyrwork
|
||||
$modules/jenkins_plugin.py:
|
||||
maintainers: jtyr
|
||||
$modules/jenkins_script.py:
|
||||
@@ -797,6 +810,8 @@ files:
|
||||
maintainers: fynncfchen johncant
|
||||
$modules/keycloak_clientsecret_regenerate.py:
|
||||
maintainers: fynncfchen johncant
|
||||
$modules/keycloak_component.py:
|
||||
maintainers: fivetide
|
||||
$modules/keycloak_group.py:
|
||||
maintainers: adamgoossens
|
||||
$modules/keycloak_identity_provider.py:
|
||||
@@ -829,6 +844,8 @@ files:
|
||||
maintainers: ahussey-redhat
|
||||
$modules/kibana_plugin.py:
|
||||
maintainers: barryib
|
||||
$modules/krb_ticket.py:
|
||||
maintainers: abakanovskii
|
||||
$modules/launchd.py:
|
||||
maintainers: martinm82
|
||||
$modules/layman.py:
|
||||
@@ -839,6 +856,8 @@ files:
|
||||
maintainers: drybjed jtyr noles
|
||||
$modules/ldap_entry.py:
|
||||
maintainers: jtyr
|
||||
$modules/ldap_inc.py:
|
||||
maintainers: pduveau
|
||||
$modules/ldap_passwd.py:
|
||||
maintainers: KellerFuchs jtyr
|
||||
$modules/ldap_search.py:
|
||||
@@ -1110,6 +1129,8 @@ files:
|
||||
$modules/proxmox_kvm.py:
|
||||
ignore: skvidal
|
||||
maintainers: helldorado krauthosting
|
||||
$modules/proxmox_backup.py:
|
||||
maintainers: IamLunchbox
|
||||
$modules/proxmox_nic.py:
|
||||
maintainers: Kogelvis krauthosting
|
||||
$modules/proxmox_node_info.py:
|
||||
@@ -1159,12 +1180,6 @@ files:
|
||||
keywords: kvm libvirt proxmox qemu
|
||||
labels: rhevm virt
|
||||
maintainers: $team_virt TimothyVandenbrande
|
||||
$modules/rhn_channel.py:
|
||||
labels: rhn_channel
|
||||
maintainers: vincentvdk alikins $team_rhn
|
||||
$modules/rhn_register.py:
|
||||
labels: rhn_register
|
||||
maintainers: jlaska $team_rhn
|
||||
$modules/rhsm_release.py:
|
||||
maintainers: seandst $team_rhsm
|
||||
$modules/rhsm_repository.py:
|
||||
@@ -1328,6 +1343,10 @@ files:
|
||||
maintainers: precurse
|
||||
$modules/sysrc.py:
|
||||
maintainers: dlundgren
|
||||
$modules/systemd_creds_decrypt.py:
|
||||
maintainers: konstruktoid
|
||||
$modules/systemd_creds_encrypt.py:
|
||||
maintainers: konstruktoid
|
||||
$modules/sysupgrade.py:
|
||||
maintainers: precurse
|
||||
$modules/taiga_issue.py:
|
||||
@@ -1359,19 +1378,16 @@ files:
|
||||
keywords: sophos utm
|
||||
maintainers: $team_e_spirit
|
||||
$modules/utm_ca_host_key_cert.py:
|
||||
ignore: stearz
|
||||
maintainers: $team_e_spirit
|
||||
maintainers: stearz
|
||||
$modules/utm_ca_host_key_cert_info.py:
|
||||
ignore: stearz
|
||||
maintainers: $team_e_spirit
|
||||
maintainers: stearz
|
||||
$modules/utm_network_interface_address.py:
|
||||
maintainers: steamx
|
||||
$modules/utm_network_interface_address_info.py:
|
||||
maintainers: steamx
|
||||
$modules/utm_proxy_auth_profile.py:
|
||||
keywords: sophos utm
|
||||
ignore: stearz
|
||||
maintainers: $team_e_spirit
|
||||
maintainers: $team_e_spirit stearz
|
||||
$modules/utm_proxy_exception.py:
|
||||
keywords: sophos utm
|
||||
maintainers: $team_e_spirit RickS-C137
|
||||
@@ -1447,6 +1463,9 @@ files:
|
||||
maintainers: $team_suse
|
||||
$plugin_utils/ansible_type.py:
|
||||
maintainers: vbotka
|
||||
$modules/zypper_repository_info.py:
|
||||
labels: zypper
|
||||
maintainers: $team_suse TobiasZeuch181
|
||||
$plugin_utils/keys_filter.py:
|
||||
maintainers: vbotka
|
||||
$plugin_utils/unsafe.py:
|
||||
@@ -1555,7 +1574,6 @@ macros:
|
||||
team_oracle: manojmeda mross22 nalsaber
|
||||
team_purestorage: bannaych dnix101 genegr lionmax opslounge raekins sdodsley sile16
|
||||
team_redfish: mraineri tomasg2012 xmadsen renxulei rajeevkallur bhavya06 jyundt
|
||||
team_rhn: FlossWare alikins barnabycourt vritant
|
||||
team_rhsm: cnsnyder ptoscano
|
||||
team_scaleway: remyleone abarbare
|
||||
team_solaris: bcoca fishman jasperla jpdasma mator scathatheworm troy2914 xen0l
|
||||
|
||||
81
.github/workflows/ansible-test.yml
vendored
81
.github/workflows/ansible-test.yml
vendored
@@ -29,8 +29,6 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
ansible:
|
||||
- '2.13'
|
||||
- '2.14'
|
||||
- '2.15'
|
||||
# Ansible-test on various stable branches does not yet work well with cgroups v2.
|
||||
# Since ubuntu-latest now uses Ubuntu 22.04, we need to fall back to the ubuntu-20.04
|
||||
@@ -47,8 +45,6 @@ jobs:
|
||||
coverage: ${{ github.event_name == 'schedule' && 'always' || 'never' }}
|
||||
pull-request-change-detection: 'true'
|
||||
testing-type: sanity
|
||||
pre-test-cmd: >-
|
||||
git clone --depth=1 --single-branch https://github.com/ansible-collections/community.internal_test_tools.git ../../community/internal_test_tools
|
||||
|
||||
units:
|
||||
# Ansible-test on various stable branches does not yet work well with cgroups v2.
|
||||
@@ -69,16 +65,8 @@ jobs:
|
||||
exclude:
|
||||
- ansible: ''
|
||||
include:
|
||||
- ansible: '2.13'
|
||||
- ansible: '2.15'
|
||||
python: '2.7'
|
||||
- ansible: '2.13'
|
||||
python: '3.8'
|
||||
- ansible: '2.13'
|
||||
python: '2.7'
|
||||
- ansible: '2.13'
|
||||
python: '3.8'
|
||||
- ansible: '2.14'
|
||||
python: '3.9'
|
||||
- ansible: '2.15'
|
||||
python: '3.5'
|
||||
- ansible: '2.15'
|
||||
@@ -123,57 +111,19 @@ jobs:
|
||||
exclude:
|
||||
- ansible: ''
|
||||
include:
|
||||
# 2.13
|
||||
- ansible: '2.13'
|
||||
docker: fedora35
|
||||
python: ''
|
||||
target: azp/posix/1/
|
||||
- ansible: '2.13'
|
||||
docker: fedora35
|
||||
python: ''
|
||||
target: azp/posix/2/
|
||||
- ansible: '2.13'
|
||||
docker: fedora35
|
||||
python: ''
|
||||
target: azp/posix/3/
|
||||
- ansible: '2.13'
|
||||
docker: opensuse15py2
|
||||
python: ''
|
||||
target: azp/posix/1/
|
||||
- ansible: '2.13'
|
||||
docker: opensuse15py2
|
||||
python: ''
|
||||
target: azp/posix/2/
|
||||
- ansible: '2.13'
|
||||
docker: opensuse15py2
|
||||
python: ''
|
||||
target: azp/posix/3/
|
||||
- ansible: '2.13'
|
||||
docker: alpine3
|
||||
python: ''
|
||||
target: azp/posix/1/
|
||||
- ansible: '2.13'
|
||||
docker: alpine3
|
||||
python: ''
|
||||
target: azp/posix/2/
|
||||
- ansible: '2.13'
|
||||
docker: alpine3
|
||||
python: ''
|
||||
target: azp/posix/3/
|
||||
# 2.14
|
||||
- ansible: '2.14'
|
||||
docker: alpine3
|
||||
python: ''
|
||||
target: azp/posix/1/
|
||||
- ansible: '2.14'
|
||||
docker: alpine3
|
||||
python: ''
|
||||
target: azp/posix/2/
|
||||
- ansible: '2.14'
|
||||
docker: alpine3
|
||||
python: ''
|
||||
target: azp/posix/3/
|
||||
# 2.15
|
||||
- ansible: '2.15'
|
||||
docker: alpine3
|
||||
python: ''
|
||||
target: azp/posix/1/
|
||||
- ansible: '2.15'
|
||||
docker: alpine3
|
||||
python: ''
|
||||
target: azp/posix/2/
|
||||
- ansible: '2.15'
|
||||
docker: alpine3
|
||||
python: ''
|
||||
target: azp/posix/3/
|
||||
- ansible: '2.15'
|
||||
docker: fedora37
|
||||
python: ''
|
||||
@@ -214,15 +164,12 @@ jobs:
|
||||
integration-continue-on-error: 'false'
|
||||
integration-diff: 'false'
|
||||
integration-retry-on-error: 'true'
|
||||
# TODO: remove "--branch stable-2" from community.crypto install once we're only using ansible-core 2.17 or newer!
|
||||
pre-test-cmd: >-
|
||||
mkdir -p ../../ansible
|
||||
;
|
||||
git clone --depth=1 --single-branch https://github.com/ansible-collections/ansible.posix.git ../../ansible/posix
|
||||
;
|
||||
git clone --depth=1 --single-branch --branch stable-2 https://github.com/ansible-collections/community.crypto.git ../../community/crypto
|
||||
;
|
||||
git clone --depth=1 --single-branch https://github.com/ansible-collections/community.docker.git ../../community/docker
|
||||
git clone --depth=1 --single-branch https://github.com/ansible-collections/community.crypto.git ../../community/crypto
|
||||
;
|
||||
git clone --depth=1 --single-branch https://github.com/ansible-collections/community.internal_test_tools.git ../../community/internal_test_tools
|
||||
pull-request-change-detection: 'true'
|
||||
|
||||
20
.github/workflows/import-galaxy.yml
vendored
Normal file
20
.github/workflows/import-galaxy.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
# Copyright (c) Ansible Project
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
name: import-galaxy
|
||||
'on':
|
||||
# Run CI against all pushes (direct commits, also merged PRs) to main, and all Pull Requests
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- stable-*
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
import-galaxy:
|
||||
permissions:
|
||||
contents: read
|
||||
name: Test to import built collection artifact with Galaxy importer
|
||||
uses: ansible-community/github-action-test-galaxy-import/.github/workflows/test-galaxy-import.yml@main
|
||||
28
.github/workflows/nox.yml
vendored
28
.github/workflows/nox.yml
vendored
@@ -1,28 +0,0 @@
|
||||
---
|
||||
# Copyright (c) Ansible Project
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
name: nox
|
||||
'on':
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- stable-*
|
||||
pull_request:
|
||||
# Run CI once per day (at 08:00 UTC)
|
||||
schedule:
|
||||
- cron: '0 8 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
nox:
|
||||
runs-on: ubuntu-latest
|
||||
name: "Run extra sanity tests"
|
||||
steps:
|
||||
- name: Check out collection
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Run nox
|
||||
uses: ansible-community/antsibull-nox@main
|
||||
35
.github/workflows/reuse.yml
vendored
Normal file
35
.github/workflows/reuse.yml
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
---
|
||||
# Copyright (c) Ansible Project
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
name: Verify REUSE
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- stable-*
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
branches:
|
||||
- main
|
||||
- stable-*
|
||||
# Run CI once per day (at 07:30 UTC)
|
||||
schedule:
|
||||
- cron: '30 7 * * *'
|
||||
|
||||
jobs:
|
||||
check:
|
||||
permissions:
|
||||
contents: read
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
ref: ${{ github.event.pull_request.head.sha || '' }}
|
||||
|
||||
- name: REUSE Compliance Check
|
||||
uses: fsfe/reuse-action@v5
|
||||
5
.reuse/dep5
Normal file
5
.reuse/dep5
Normal file
@@ -0,0 +1,5 @@
|
||||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
|
||||
Files: changelogs/fragments/*
|
||||
Copyright: Ansible Project
|
||||
License: GPL-3.0-or-later
|
||||
1334
CHANGELOG.md
1334
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
1212
CHANGELOG.rst
1212
CHANGELOG.rst
File diff suppressed because it is too large
Load Diff
@@ -44,49 +44,7 @@ If you want to test a PR locally, refer to [our testing guide](https://github.co
|
||||
|
||||
If you find any inconsistencies or places in this document which can be improved, feel free to raise an issue or pull request to fix it.
|
||||
|
||||
## Run sanity or unit locally (with antsibull-nox)
|
||||
|
||||
The easiest way to run sanity and unit tests locally is to use [antsibull-nox](https://ansible.readthedocs.io/projects/antsibull-nox/).
|
||||
(If you have [nox](https://nox.thea.codes/en/stable/) installed, it will automatically install antsibull-nox in a virtual environment for you.)
|
||||
|
||||
### Sanity tests
|
||||
|
||||
The following commands show how to run ansible-test sanity tests:
|
||||
|
||||
```.bash
|
||||
# Run basic sanity tests for all files in the collection:
|
||||
nox -Re ansible-test-sanity-devel
|
||||
|
||||
# Run basic sanity tests for the given files and directories:
|
||||
nox -Re ansible-test-sanity-devel -- plugins/modules/system/pids.py tests/integration/targets/pids/
|
||||
|
||||
# Run all other sanity tests for all files in the collection:
|
||||
nox -R
|
||||
```
|
||||
|
||||
If you replace `-Re` with `-e`, respectively. leave `-R` away, then the virtual environments will be re-created. The `-R` re-uses them (if they already exist).
|
||||
|
||||
### Unit tests
|
||||
|
||||
The following commands show how to run unit tests:
|
||||
|
||||
```.bash
|
||||
# Run all unit tests:
|
||||
nox -Re ansible-test-units-devel
|
||||
|
||||
# Run all unit tests for one Python version (a lot faster):
|
||||
nox -Re ansible-test-units-devel -- --python 3.13
|
||||
|
||||
# Run a specific unit test (for the nmcli module) for one Python version:
|
||||
nox -Re ansible-test-units-devel -- --python 3.13 tests/unit/plugins/modules/net_tools/test_nmcli.py
|
||||
```
|
||||
|
||||
If you replace `-Re` with `-e`, then the virtual environments will be re-created. The `-R` re-uses them (if they already exist).
|
||||
|
||||
## Run basic sanity, unit or integration tests locally (with ansible-test)
|
||||
|
||||
Instead of using antsibull-nox, you can also run sanity and unit tests with ansible-test directly.
|
||||
This also allows you to run integration tests.
|
||||
## 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:
|
||||
|
||||
@@ -98,27 +56,20 @@ 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+.
|
||||
|
||||
### Basic sanity tests
|
||||
### Sanity tests
|
||||
|
||||
The following commands show how to run basic sanity tests:
|
||||
The following commands show how to run sanity tests:
|
||||
|
||||
```.bash
|
||||
# Run basic sanity tests for all files in the collection:
|
||||
# Run sanity tests for all files in the collection:
|
||||
ansible-test sanity --docker -v
|
||||
|
||||
# Run basic sanity tests for the given files and directories:
|
||||
# Run sanity tests for the given files and directories:
|
||||
ansible-test sanity --docker -v plugins/modules/system/pids.py tests/integration/targets/pids/
|
||||
```
|
||||
|
||||
### Unit tests
|
||||
|
||||
Note that for running unit tests, you need to install required collections in the same folder structure that `community.general` is checked out in.
|
||||
Right now, you need to install [`community.internal_test_tools`](https://github.com/ansible-collections/community.internal_test_tools).
|
||||
If you want to use the latest version from GitHub, you can run:
|
||||
```
|
||||
git clone https://github.com/ansible-collections/community.internal_test_tools.git ~/dev/ansible_collections/community/internal_test_tools
|
||||
```
|
||||
|
||||
The following commands show how to run unit tests:
|
||||
|
||||
```.bash
|
||||
@@ -134,16 +85,6 @@ ansible-test units --docker -v --python 3.8 tests/unit/plugins/modules/net_tools
|
||||
|
||||
### Integration tests
|
||||
|
||||
Note that for running integration tests, you need to install required collections in the same folder structure that `community.general` is checked out in.
|
||||
Right now, depending on the test, you need to install [`ansible.posix`](https://github.com/ansible-collections/ansible.posix), [`community.crypto`](https://github.com/ansible-collections/community.crypto), and [`community.docker`](https://github.com/ansible-collections/community.docker):
|
||||
If you want to use the latest versions from GitHub, you can run:
|
||||
```
|
||||
mkdir -p ~/dev/ansible_collections/ansible
|
||||
git clone https://github.com/ansible-collections/ansible.posix.git ~/dev/ansible_collections/ansible/posix
|
||||
git clone https://github.com/ansible-collections/community.crypto.git ~/dev/ansible_collections/community/crypto
|
||||
git clone https://github.com/ansible-collections/community.docker.git ~/dev/ansible_collections/community/docker
|
||||
```
|
||||
|
||||
The following commands show how to run integration tests:
|
||||
|
||||
#### In Docker
|
||||
@@ -151,8 +92,8 @@ The following commands show how to run integration tests:
|
||||
Integration tests on Docker have the following parameters:
|
||||
- `image_name` (required): The name of the Docker image. To get the list of supported Docker images, run
|
||||
`ansible-test integration --help` and look for _target docker images_.
|
||||
- `test_name` (optional): The name of the integration test.
|
||||
For modules, this equals the short name of the module; for example, `pacman` in case of `community.general.pacman`.
|
||||
- `test_name` (optional): The name of the integration test.
|
||||
For modules, this equals the short name of the module; for example, `pacman` in case of `community.general.pacman`.
|
||||
For plugins, the plugin type is added before the plugin's short name, for example `callback_yaml` for the `community.general.yaml` callback.
|
||||
```.bash
|
||||
# Test all plugins/modules on fedora40
|
||||
|
||||
16
README.md
16
README.md
@@ -6,10 +6,8 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# Community General Collection
|
||||
|
||||
[](https://docs.ansible.com/ansible/latest/collections/community/general/)
|
||||
[](https://dev.azure.com/ansible/community.general/_build?definitionId=31)
|
||||
[](https://github.com/ansible-collections/community.general/actions)
|
||||
[](https://github.com/ansible-collections/community.general/actions)
|
||||
[](https://dev.azure.com/ansible/community.general/_build?definitionId=31)
|
||||
[](https://github.com/ansible-collections/community.general/actions)
|
||||
[](https://codecov.io/gh/ansible-collections/community.general)
|
||||
[](https://api.reuse.software/info/github.com/ansible-collections/community.general)
|
||||
|
||||
@@ -39,7 +37,7 @@ For more information about communication, see the [Ansible communication guide](
|
||||
|
||||
## Tested with Ansible
|
||||
|
||||
Tested with the current ansible-core 2.13, ansible-core 2.14, ansible-core 2.15, ansible-core 2.16, ansible-core 2.17, ansible-core 2.18 releases and the current development version of ansible-core. Ansible-core versions before 2.13.0 are not supported. This includes all ansible-base 2.10 and Ansible 2.9 releases.
|
||||
Tested with the current ansible-core 2.15, ansible-core 2.16, ansible-core 2.17, ansible-core 2.18 releases and the current development version of ansible-core. Ansible-core versions before 2.15.0 are not supported. This includes all ansible-base 2.10 and Ansible 2.9 releases.
|
||||
|
||||
## External requirements
|
||||
|
||||
@@ -118,7 +116,7 @@ See the [Releasing guidelines](https://github.com/ansible/community-docs/blob/ma
|
||||
|
||||
## Release notes
|
||||
|
||||
See the [changelog](https://github.com/ansible-collections/community.general/blob/stable-9/CHANGELOG.md).
|
||||
See the [changelog](https://github.com/ansible-collections/community.general/blob/stable-10/CHANGELOG.md).
|
||||
|
||||
## Roadmap
|
||||
|
||||
@@ -137,8 +135,8 @@ See [this issue](https://github.com/ansible-collections/community.general/issues
|
||||
|
||||
This collection is primarily licensed and distributed as a whole under the GNU General Public License v3.0 or later.
|
||||
|
||||
See [LICENSES/GPL-3.0-or-later.txt](https://github.com/ansible-collections/community.general/blob/stable-9/COPYING) for the full text.
|
||||
See [LICENSES/GPL-3.0-or-later.txt](https://github.com/ansible-collections/community.general/blob/stable-10/COPYING) for the full text.
|
||||
|
||||
Parts of the collection are licensed under the [BSD 2-Clause license](https://github.com/ansible-collections/community.general/blob/stable-9/LICENSES/BSD-2-Clause.txt), the [MIT license](https://github.com/ansible-collections/community.general/blob/stable-9/LICENSES/MIT.txt), and the [PSF 2.0 license](https://github.com/ansible-collections/community.general/blob/stable-9/LICENSES/PSF-2.0.txt).
|
||||
Parts of the collection are licensed under the [BSD 2-Clause license](https://github.com/ansible-collections/community.general/blob/stable-10/LICENSES/BSD-2-Clause.txt), the [MIT license](https://github.com/ansible-collections/community.general/blob/stable-10/LICENSES/MIT.txt), and the [PSF 2.0 license](https://github.com/ansible-collections/community.general/blob/stable-10/LICENSES/PSF-2.0.txt).
|
||||
|
||||
All files have a machine readable `SDPX-License-Identifier:` comment denoting its respective license(s) or an equivalent entry in an accompanying `.license` file. Only changelog fragments (which will not be part of a release) are covered by a blanket statement in `REUSE.toml`. This conforms to the [REUSE specification](https://reuse.software/spec/).
|
||||
All files have a machine readable `SDPX-License-Identifier:` comment denoting its respective license(s) or an equivalent entry in an accompanying `.license` file. Only changelog fragments (which will not be part of a release) are covered by a blanket statement in `.reuse/dep5`. This conforms to the [REUSE specification](https://reuse.software/spec/).
|
||||
|
||||
11
REUSE.toml
11
REUSE.toml
@@ -1,11 +0,0 @@
|
||||
# Copyright (c) Ansible Project
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
version = 1
|
||||
|
||||
[[annotations]]
|
||||
path = "changelogs/fragments/**"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "Ansible Project"
|
||||
SPDX-License-Identifier = "GPL-3.0-or-later"
|
||||
@@ -1,61 +0,0 @@
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
# SPDX-FileCopyrightText: 2025 Felix Fontein <felix@fontein.de>
|
||||
|
||||
[collection_sources]
|
||||
"ansible.posix" = "git+https://github.com/ansible-collections/ansible.posix.git,main"
|
||||
"community.crypto" = "git+https://github.com/ansible-collections/community.crypto.git,main"
|
||||
"community.docker" = "git+https://github.com/ansible-collections/community.docker.git,main"
|
||||
"community.internal_test_tools" = "git+https://github.com/ansible-collections/community.internal_test_tools.git,main"
|
||||
|
||||
[collection_sources_per_ansible.'2.13']
|
||||
"community.crypto" = "git+https://github.com/ansible-collections/community.crypto.git,stable-2"
|
||||
|
||||
[collection_sources_per_ansible.'2.14']
|
||||
"community.crypto" = "git+https://github.com/ansible-collections/community.crypto.git,stable-2"
|
||||
|
||||
[collection_sources_per_ansible.'2.15']
|
||||
# community.crypto's main branch needs ansible-core >= 2.17
|
||||
"community.crypto" = "git+https://github.com/ansible-collections/community.crypto.git,stable-2"
|
||||
|
||||
[collection_sources_per_ansible.'2.16']
|
||||
# community.crypto's main branch needs ansible-core >= 2.17
|
||||
"community.crypto" = "git+https://github.com/ansible-collections/community.crypto.git,stable-2"
|
||||
|
||||
[sessions]
|
||||
|
||||
[sessions.docs_check]
|
||||
validate_collection_refs="all"
|
||||
|
||||
[sessions.license_check]
|
||||
|
||||
[sessions.extra_checks]
|
||||
run_no_unwanted_files = true
|
||||
no_unwanted_files_module_extensions = [".py"]
|
||||
no_unwanted_files_yaml_extensions = [".yml"]
|
||||
run_action_groups = true
|
||||
|
||||
[[sessions.extra_checks.action_groups_config]]
|
||||
name = "consul"
|
||||
pattern = "^consul_.*$"
|
||||
exclusions = [
|
||||
"consul_acl",
|
||||
"consul_acl_bootstrap",
|
||||
"consul_kv",
|
||||
]
|
||||
doc_fragment = "community.general.consul.actiongroup_consul"
|
||||
|
||||
[[sessions.extra_checks.action_groups_config]]
|
||||
name = "proxmox"
|
||||
pattern = "^proxmox(_.*)?$"
|
||||
exclusions = []
|
||||
doc_fragment = "community.general.proxmox.actiongroup_proxmox"
|
||||
|
||||
[sessions.build_import_check]
|
||||
run_galaxy_importer = true
|
||||
|
||||
[sessions.ansible_test_sanity]
|
||||
include_devel = true
|
||||
|
||||
[sessions.ansible_test_units]
|
||||
include_devel = true
|
||||
File diff suppressed because it is too large
Load Diff
@@ -65,7 +65,7 @@ All three statements are equivalent and give:
|
||||
|
||||
.. note:: Be aware that in most cases, filter calls without any argument require ``flatten=true``, otherwise the input is returned as result. The reason for this is, that the input is considered as a variable argument and is wrapped by an additional outer list. ``flatten=true`` ensures that this list is removed before the input is processed by the filter logic.
|
||||
|
||||
The filters :ansplugin:`community.general.lists_difference#filter` or :ansplugin:`community.general.lists_symmetric_difference#filter` can be used in the same way as the filters in the examples above. They calculate the difference or the symmetric difference between two or more lists and preserve the item order.
|
||||
The filters ansplugin:`community.general.lists_difference#filter` or :ansplugin:`community.general.lists_symmetric_difference#filter` can be used in the same way as the filters in the examples above. They calculate the difference or the symmetric difference between two or more lists and preserve the item order.
|
||||
|
||||
For example, the symmetric difference of ``A``, ``B`` and ``C`` may be written as:
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ To get a hash map with all ports and names of a cluster:
|
||||
var: item
|
||||
loop: "{{ domain_definition | community.general.json_query(server_name_cluster1_query) }}"
|
||||
vars:
|
||||
server_name_cluster1_query: "domain.server[?cluster=='cluster1'].{name: name, port: port}"
|
||||
server_name_cluster1_query: "domain.server[?cluster=='cluster2'].{name: name, port: port}"
|
||||
|
||||
To extract ports from all clusters with name starting with 'server1':
|
||||
|
||||
|
||||
@@ -346,6 +346,8 @@ However, you can set output variables specifically for that exception, if you so
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.module_helper import ModuleHelperException
|
||||
|
||||
def __init_module__(self):
|
||||
if not complex_validation():
|
||||
self.do_raise("Validation failed!")
|
||||
@@ -354,11 +356,16 @@ However, you can set output variables specifically for that exception, if you so
|
||||
awesomeness = calculate_awesomeness()
|
||||
if awesomeness > 1000:
|
||||
self.do_raise("Over awesome, I cannot handle it!", update_output={"awesomeness": awesomeness})
|
||||
# which is just a convenience shortcut for
|
||||
raise ModuleHelperException("...", update_output={...})
|
||||
|
||||
All exceptions derived from ``Exception`` are captured and translated into a ``fail_json()`` call.
|
||||
However, if you do want to call ``self.module.fail_json()`` yourself it will work,
|
||||
just keep in mind that there will be no automatic handling of output variables in that case.
|
||||
|
||||
Behind the curtains, all ``do_raise()`` does is to raise a ``ModuleHelperException``.
|
||||
If you want to create specialized error handling for your code, the best way is to extend that clas and raise it when needed.
|
||||
|
||||
.. _ansible_collections.community.general.docsite.guide_modulehelper.statemh:
|
||||
|
||||
StateModuleHelper
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
namespace: community
|
||||
name: general
|
||||
version: 9.5.8
|
||||
version: 10.2.0
|
||||
readme: README.md
|
||||
authors:
|
||||
- Ansible (https://github.com/ansible)
|
||||
|
||||
103
meta/runtime.yml
103
meta/runtime.yml
@@ -3,7 +3,7 @@
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
requires_ansible: '>=2.13.0'
|
||||
requires_ansible: '>=2.15.0'
|
||||
action_groups:
|
||||
consul:
|
||||
- consul_agent_check
|
||||
@@ -16,6 +16,7 @@ action_groups:
|
||||
- consul_token
|
||||
proxmox:
|
||||
- proxmox
|
||||
- proxmox_backup
|
||||
- proxmox_disk
|
||||
- proxmox_domain_info
|
||||
- proxmox_group_info
|
||||
@@ -31,6 +32,34 @@ action_groups:
|
||||
- proxmox_template
|
||||
- proxmox_user_info
|
||||
- proxmox_vm_info
|
||||
keycloak:
|
||||
- keycloak_authentication
|
||||
- keycloak_authentication_required_actions
|
||||
- keycloak_authz_authorization_scope
|
||||
- keycloak_authz_custom_policy
|
||||
- keycloak_authz_permission
|
||||
- keycloak_authz_permission_info
|
||||
- keycloak_client
|
||||
- keycloak_client_rolemapping
|
||||
- keycloak_client_rolescope
|
||||
- keycloak_clientscope
|
||||
- keycloak_clientscope_type
|
||||
- keycloak_clientsecret_info
|
||||
- keycloak_clientsecret_regenerate
|
||||
- keycloak_clienttemplate
|
||||
- keycloak_component
|
||||
- keycloak_component_info
|
||||
- keycloak_group
|
||||
- keycloak_identity_provider
|
||||
- keycloak_realm
|
||||
- keycloak_realm_key
|
||||
- keycloak_realm_keys_metadata_info
|
||||
- keycloak_realm_rolemapping
|
||||
- keycloak_role
|
||||
- keycloak_user
|
||||
- keycloak_user_federation
|
||||
- keycloak_user_rolemapping
|
||||
- keycloak_userprofile
|
||||
plugin_routing:
|
||||
callback:
|
||||
actionable:
|
||||
@@ -44,7 +73,7 @@ plugin_routing:
|
||||
warning_text: Use the 'default' callback plugin with 'display_skipped_hosts
|
||||
= no' option.
|
||||
hipchat:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 10.0.0
|
||||
warning_text: The hipchat service has been discontinued and the self-hosted variant has been End of Life since 2020.
|
||||
osx_say:
|
||||
@@ -54,6 +83,10 @@ plugin_routing:
|
||||
removal_version: 2.0.0
|
||||
warning_text: Use the 'default' callback plugin with 'display_failed_stderr
|
||||
= yes' option.
|
||||
yaml:
|
||||
deprecation:
|
||||
removal_version: 13.0.0
|
||||
warning_text: The plugin has been superseded by the the option `result_format=yaml` in callback plugin ansible.builtin.default from ansible-core 2.13 onwards.
|
||||
connection:
|
||||
docker:
|
||||
redirect: community.docker.docker
|
||||
@@ -71,10 +104,26 @@ plugin_routing:
|
||||
nios_next_network:
|
||||
redirect: infoblox.nios_modules.nios_next_network
|
||||
modules:
|
||||
consul_acl:
|
||||
atomic_container:
|
||||
deprecation:
|
||||
removal_version: 13.0.0
|
||||
warning_text: Poject Atomic was sunset by the end of 2019.
|
||||
atomic_host:
|
||||
deprecation:
|
||||
removal_version: 13.0.0
|
||||
warning_text: Poject Atomic was sunset by the end of 2019.
|
||||
atomic_image:
|
||||
deprecation:
|
||||
removal_version: 13.0.0
|
||||
warning_text: Poject Atomic was sunset by the end of 2019.
|
||||
consul_acl:
|
||||
tombstone:
|
||||
removal_version: 10.0.0
|
||||
warning_text: Use community.general.consul_token and/or community.general.consul_policy instead.
|
||||
facter:
|
||||
deprecation:
|
||||
removal_version: 12.0.0
|
||||
warning_text: Use community.general.facter_facts instead.
|
||||
hipchat:
|
||||
deprecation:
|
||||
removal_version: 11.0.0
|
||||
@@ -184,15 +233,35 @@ plugin_routing:
|
||||
removal_version: 9.0.0
|
||||
warning_text: This module relied on the deprecated package pyrax.
|
||||
rhn_channel:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 10.0.0
|
||||
warning_text: RHN is EOL, please contact the community.general maintainers
|
||||
if still using this; see the module documentation for more details.
|
||||
rhn_register:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 10.0.0
|
||||
warning_text: RHN is EOL, please contact the community.general maintainers
|
||||
if still using this; see the module documentation for more details.
|
||||
sensu_check:
|
||||
deprecation:
|
||||
removal_version: 13.0.0
|
||||
warning_text: Sensu Core and Sensu Enterprise products have been End of Life since 2019/20.
|
||||
sensu_client:
|
||||
deprecation:
|
||||
removal_version: 13.0.0
|
||||
warning_text: Sensu Core and Sensu Enterprise products have been End of Life since 2019/20.
|
||||
sensu_handler:
|
||||
deprecation:
|
||||
removal_version: 13.0.0
|
||||
warning_text: Sensu Core and Sensu Enterprise products have been End of Life since 2019/20.
|
||||
sensu_silence:
|
||||
deprecation:
|
||||
removal_version: 13.0.0
|
||||
warning_text: Sensu Core and Sensu Enterprise products have been End of Life since 2019/20.
|
||||
sensu_subscription:
|
||||
deprecation:
|
||||
removal_version: 13.0.0
|
||||
warning_text: Sensu Core and Sensu Enterprise products have been End of Life since 2019/20.
|
||||
stackdriver:
|
||||
tombstone:
|
||||
removal_version: 9.0.0
|
||||
@@ -779,11 +848,6 @@ plugin_routing:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.xenserver_guest_info instead.
|
||||
doc_fragments:
|
||||
rackspace:
|
||||
tombstone:
|
||||
removal_version: 9.0.0
|
||||
warning_text: This doc fragment was used by rax modules, that relied on the deprecated
|
||||
package pyrax.
|
||||
_gcp:
|
||||
redirect: community.google._gcp
|
||||
docker:
|
||||
@@ -798,11 +862,16 @@ plugin_routing:
|
||||
redirect: infoblox.nios_modules.nios
|
||||
postgresql:
|
||||
redirect: community.postgresql.postgresql
|
||||
module_utils:
|
||||
rax:
|
||||
purestorage:
|
||||
deprecation:
|
||||
removal_version: 12.0.0
|
||||
warning_text: The modules for purestorage were removed in community.general 3.0.0, this document fragment was left behind.
|
||||
rackspace:
|
||||
tombstone:
|
||||
removal_version: 9.0.0
|
||||
warning_text: This module util relied on the deprecated package pyrax.
|
||||
warning_text: This doc fragment was used by rax modules, that relied on the deprecated
|
||||
package pyrax.
|
||||
module_utils:
|
||||
docker.common:
|
||||
redirect: community.docker.common
|
||||
docker.swarm:
|
||||
@@ -821,6 +890,14 @@ plugin_routing:
|
||||
redirect: infoblox.nios_modules.api
|
||||
postgresql:
|
||||
redirect: community.postgresql.postgresql
|
||||
pure:
|
||||
deprecation:
|
||||
removal_version: 12.0.0
|
||||
warning_text: The modules for purestorage were removed in community.general 3.0.0, this module util was left behind.
|
||||
rax:
|
||||
tombstone:
|
||||
removal_version: 9.0.0
|
||||
warning_text: This module util relied on the deprecated package pyrax.
|
||||
remote_management.dellemc.dellemc_idrac:
|
||||
redirect: dellemc.openmanage.dellemc_idrac
|
||||
remote_management.dellemc.ome:
|
||||
|
||||
38
noxfile.py
38
noxfile.py
@@ -1,38 +0,0 @@
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
# SPDX-FileCopyrightText: 2025 Felix Fontein <felix@fontein.de>
|
||||
|
||||
# /// script
|
||||
# dependencies = ["nox>=2025.02.09", "antsibull-nox"]
|
||||
# ///
|
||||
|
||||
import sys
|
||||
|
||||
import nox
|
||||
|
||||
|
||||
try:
|
||||
import antsibull_nox
|
||||
except ImportError:
|
||||
print("You need to install antsibull-nox in the same Python environment as nox.")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
antsibull_nox.load_antsibull_nox_toml()
|
||||
|
||||
|
||||
@nox.session(name="aliases", python=False, default=True)
|
||||
def aliases(session: nox.Session) -> None:
|
||||
session.run("python", "tests/sanity/extra/aliases.py")
|
||||
|
||||
|
||||
@nox.session(name="botmeta", default=True)
|
||||
def botmeta(session: nox.Session) -> None:
|
||||
session.install("PyYAML", "voluptuous")
|
||||
session.run("python", "tests/sanity/extra/botmeta.py")
|
||||
|
||||
|
||||
# Allow to run the noxfile with `python noxfile.py`, `pipx run noxfile.py`, or similar.
|
||||
# Requires nox >= 2025.02.09
|
||||
if __name__ == "__main__":
|
||||
nox.main()
|
||||
@@ -22,25 +22,33 @@ class ActionModule(ActionBase):
|
||||
_VALID_ARGS = frozenset(('path', 'state', 'table', 'noflush', 'counters', 'modprobe', 'ip_version', 'wait'))
|
||||
DEFAULT_SUDOABLE = True
|
||||
|
||||
MSG_ERROR__ASYNC_AND_POLL_NOT_ZERO = (
|
||||
"This module doesn't support async>0 and poll>0 when its 'state' param "
|
||||
"is set to 'restored'. To enable its rollback feature (that needs the "
|
||||
"module to run asynchronously on the remote), please set task attribute "
|
||||
"'poll' (=%s) to 0, and 'async' (=%s) to a value >2 and not greater than "
|
||||
"'ansible_timeout' (=%s) (recommended).")
|
||||
MSG_WARNING__NO_ASYNC_IS_NO_ROLLBACK = (
|
||||
"Attempts to restore iptables state without rollback in case of mistake "
|
||||
"may lead the ansible controller to loose access to the hosts and never "
|
||||
"regain it before fixing firewall rules through a serial console, or any "
|
||||
"other way except SSH. Please set task attribute 'poll' (=%s) to 0, and "
|
||||
"'async' (=%s) to a value >2 and not greater than 'ansible_timeout' (=%s) "
|
||||
"(recommended).")
|
||||
MSG_WARNING__ASYNC_GREATER_THAN_TIMEOUT = (
|
||||
"You attempt to restore iptables state with rollback in case of mistake, "
|
||||
"but with settings that will lead this rollback to happen AFTER that the "
|
||||
"controller will reach its own timeout. Please set task attribute 'poll' "
|
||||
"(=%s) to 0, and 'async' (=%s) to a value >2 and not greater than "
|
||||
"'ansible_timeout' (=%s) (recommended).")
|
||||
@staticmethod
|
||||
def msg_error__async_and_poll_not_zero(task_poll, task_async, max_timeout):
|
||||
return (
|
||||
"This module doesn't support async>0 and poll>0 when its 'state' param "
|
||||
"is set to 'restored'. To enable its rollback feature (that needs the "
|
||||
"module to run asynchronously on the remote), please set task attribute "
|
||||
f"'poll' (={task_poll}) to 0, and 'async' (={task_async}) to a value >2 and not greater than "
|
||||
f"'ansible_timeout' (={max_timeout}) (recommended).")
|
||||
|
||||
@staticmethod
|
||||
def msg_warning__no_async_is_no_rollback(task_poll, task_async, max_timeout):
|
||||
return (
|
||||
"Attempts to restore iptables state without rollback in case of mistake "
|
||||
"may lead the ansible controller to loose access to the hosts and never "
|
||||
"regain it before fixing firewall rules through a serial console, or any "
|
||||
f"other way except SSH. Please set task attribute 'poll' (={task_poll}) to 0, and "
|
||||
f"'async' (={task_async}) to a value >2 and not greater than 'ansible_timeout' (={max_timeout}) "
|
||||
"(recommended).")
|
||||
|
||||
@staticmethod
|
||||
def msg_warning__async_greater_than_timeout(task_poll, task_async, max_timeout):
|
||||
return (
|
||||
"You attempt to restore iptables state with rollback in case of mistake, "
|
||||
"but with settings that will lead this rollback to happen AFTER that the "
|
||||
"controller will reach its own timeout. Please set task attribute 'poll' "
|
||||
f"(={task_poll}) to 0, and 'async' (={task_async}) to a value >2 and not greater than "
|
||||
f"'ansible_timeout' (={max_timeout}) (recommended).")
|
||||
|
||||
def _async_result(self, async_status_args, task_vars, timeout):
|
||||
'''
|
||||
@@ -95,18 +103,18 @@ class ActionModule(ActionBase):
|
||||
if module_args.get('state', None) == 'restored':
|
||||
if not wrap_async:
|
||||
if not check_mode:
|
||||
display.warning(self.MSG_WARNING__NO_ASYNC_IS_NO_ROLLBACK % (
|
||||
display.warning(self.msg_error__async_and_poll_not_zero(
|
||||
task_poll,
|
||||
task_async,
|
||||
max_timeout))
|
||||
elif task_poll:
|
||||
raise AnsibleActionFail(self.MSG_ERROR__ASYNC_AND_POLL_NOT_ZERO % (
|
||||
raise AnsibleActionFail(self.msg_warning__no_async_is_no_rollback(
|
||||
task_poll,
|
||||
task_async,
|
||||
max_timeout))
|
||||
else:
|
||||
if task_async > max_timeout and not check_mode:
|
||||
display.warning(self.MSG_WARNING__ASYNC_GREATER_THAN_TIMEOUT % (
|
||||
display.warning(self.msg_warning__async_greater_than_timeout(
|
||||
task_poll,
|
||||
task_async,
|
||||
max_timeout))
|
||||
@@ -119,10 +127,10 @@ class ActionModule(ActionBase):
|
||||
# remote and local sides (if not the same, make the loop
|
||||
# longer on the controller); and set a backup file path.
|
||||
module_args['_timeout'] = task_async
|
||||
module_args['_back'] = '%s/iptables.state' % async_dir
|
||||
module_args['_back'] = f'{async_dir}/iptables.state'
|
||||
async_status_args = dict(mode='status')
|
||||
confirm_cmd = 'rm -f %s' % module_args['_back']
|
||||
starter_cmd = 'touch %s.starter' % module_args['_back']
|
||||
confirm_cmd = f"rm -f {module_args['_back']}"
|
||||
starter_cmd = f"touch {module_args['_back']}.starter"
|
||||
remaining_time = max(task_async, max_timeout)
|
||||
|
||||
# do work!
|
||||
|
||||
@@ -18,6 +18,10 @@ from ansible.utils.display import Display
|
||||
display = Display()
|
||||
|
||||
|
||||
def fmt(mapping, key):
|
||||
return to_native(mapping[key]).strip()
|
||||
|
||||
|
||||
class TimedOutException(Exception):
|
||||
pass
|
||||
|
||||
@@ -84,31 +88,26 @@ class ActionModule(ActionBase):
|
||||
def get_distribution(self, task_vars):
|
||||
# FIXME: only execute the module if we don't already have the facts we need
|
||||
distribution = {}
|
||||
display.debug('{action}: running setup module to get distribution'.format(action=self._task.action))
|
||||
display.debug(f'{self._task.action}: running setup module to get distribution')
|
||||
module_output = self._execute_module(
|
||||
task_vars=task_vars,
|
||||
module_name='ansible.legacy.setup',
|
||||
module_args={'gather_subset': 'min'})
|
||||
try:
|
||||
if module_output.get('failed', False):
|
||||
raise AnsibleError('Failed to determine system distribution. {0}, {1}'.format(
|
||||
to_native(module_output['module_stdout']).strip(),
|
||||
to_native(module_output['module_stderr']).strip()))
|
||||
raise AnsibleError(f"Failed to determine system distribution. {fmt(module_output, 'module_stdout')}, {fmt(module_output, 'module_stderr')}")
|
||||
distribution['name'] = module_output['ansible_facts']['ansible_distribution'].lower()
|
||||
distribution['version'] = to_text(
|
||||
module_output['ansible_facts']['ansible_distribution_version'].split('.')[0])
|
||||
distribution['family'] = to_text(module_output['ansible_facts']['ansible_os_family'].lower())
|
||||
display.debug("{action}: distribution: {dist}".format(action=self._task.action, dist=distribution))
|
||||
display.debug(f"{self._task.action}: distribution: {distribution}")
|
||||
return distribution
|
||||
except KeyError as ke:
|
||||
raise AnsibleError('Failed to get distribution information. Missing "{0}" in output.'.format(ke.args[0]))
|
||||
raise AnsibleError(f'Failed to get distribution information. Missing "{ke.args[0]}" in output.')
|
||||
|
||||
def get_shutdown_command(self, task_vars, distribution):
|
||||
def find_command(command, find_search_paths):
|
||||
display.debug('{action}: running find module looking in {paths} to get path for "{command}"'.format(
|
||||
action=self._task.action,
|
||||
command=command,
|
||||
paths=find_search_paths))
|
||||
display.debug(f'{self._task.action}: running find module looking in {find_search_paths} to get path for "{command}"')
|
||||
find_result = self._execute_module(
|
||||
task_vars=task_vars,
|
||||
# prevent collection search by calling with ansible.legacy (still allows library/ override of find)
|
||||
@@ -130,42 +129,37 @@ class ActionModule(ActionBase):
|
||||
if is_string(search_paths):
|
||||
search_paths = [search_paths]
|
||||
|
||||
# Error if we didn't get a list
|
||||
err_msg = "'search_paths' must be a string or flat list of strings, got {0}"
|
||||
try:
|
||||
incorrect_type = any(not is_string(x) for x in search_paths)
|
||||
if not isinstance(search_paths, list) or incorrect_type:
|
||||
raise TypeError
|
||||
except TypeError:
|
||||
raise AnsibleError(err_msg.format(search_paths))
|
||||
# Error if we didn't get a list
|
||||
err_msg = f"'search_paths' must be a string or flat list of strings, got {search_paths}"
|
||||
raise AnsibleError(err_msg)
|
||||
|
||||
full_path = find_command(shutdown_bin, search_paths) # find the path to the shutdown command
|
||||
if not full_path: # if we could not find the shutdown command
|
||||
display.vvv('Unable to find command "{0}" in search paths: {1}, will attempt a shutdown using systemd '
|
||||
'directly.'.format(shutdown_bin, search_paths)) # tell the user we will try with systemd
|
||||
|
||||
# tell the user we will try with systemd
|
||||
display.vvv(f'Unable to find command "{shutdown_bin}" in search paths: {search_paths}, will attempt a shutdown using systemd directly.')
|
||||
systemctl_search_paths = ['/bin', '/usr/bin']
|
||||
full_path = find_command('systemctl', systemctl_search_paths) # find the path to the systemctl command
|
||||
if not full_path: # if we couldn't find systemctl
|
||||
raise AnsibleError(
|
||||
'Could not find command "{0}" in search paths: {1} or systemctl command in search paths: {2}, unable to shutdown.'.
|
||||
format(shutdown_bin, search_paths, systemctl_search_paths)) # we give up here
|
||||
f'Could not find command "{shutdown_bin}" in search paths: {search_paths} or systemctl'
|
||||
f' command in search paths: {systemctl_search_paths}, unable to shutdown.') # we give up here
|
||||
else:
|
||||
return "{0} poweroff".format(full_path[0]) # done, since we cannot use args with systemd shutdown
|
||||
return f"{full_path[0]} poweroff" # done, since we cannot use args with systemd shutdown
|
||||
|
||||
# systemd case taken care of, here we add args to the command
|
||||
args = self._get_value_from_facts('SHUTDOWN_COMMAND_ARGS', distribution, 'DEFAULT_SHUTDOWN_COMMAND_ARGS')
|
||||
# Convert seconds to minutes. If less that 60, set it to 0.
|
||||
delay_sec = self.delay
|
||||
shutdown_message = self._task.args.get('msg', self.DEFAULT_SHUTDOWN_MESSAGE)
|
||||
return '{0} {1}'. \
|
||||
format(
|
||||
full_path[0],
|
||||
args.format(
|
||||
delay_sec=delay_sec,
|
||||
delay_min=delay_sec // 60,
|
||||
message=shutdown_message
|
||||
)
|
||||
)
|
||||
|
||||
af = args.format(delay_sec=delay_sec, delay_min=delay_sec // 60, message=shutdown_message)
|
||||
return f'{full_path[0]} {af}'
|
||||
|
||||
def perform_shutdown(self, task_vars, distribution):
|
||||
result = {}
|
||||
@@ -174,9 +168,8 @@ class ActionModule(ActionBase):
|
||||
|
||||
self.cleanup(force=True)
|
||||
try:
|
||||
display.vvv("{action}: shutting down server...".format(action=self._task.action))
|
||||
display.debug("{action}: shutting down server with command '{command}'".
|
||||
format(action=self._task.action, command=shutdown_command_exec))
|
||||
display.vvv(f"{self._task.action}: shutting down server...")
|
||||
display.debug(f"{self._task.action}: shutting down server with command '{shutdown_command_exec}'")
|
||||
if self._play_context.check_mode:
|
||||
shutdown_result['rc'] = 0
|
||||
else:
|
||||
@@ -184,16 +177,13 @@ class ActionModule(ActionBase):
|
||||
except AnsibleConnectionFailure as e:
|
||||
# If the connection is closed too quickly due to the system being shutdown, carry on
|
||||
display.debug(
|
||||
'{action}: AnsibleConnectionFailure caught and handled: {error}'.format(action=self._task.action,
|
||||
error=to_text(e)))
|
||||
f'{self._task.action}: AnsibleConnectionFailure caught and handled: {e}')
|
||||
shutdown_result['rc'] = 0
|
||||
|
||||
if shutdown_result['rc'] != 0:
|
||||
result['failed'] = True
|
||||
result['shutdown'] = False
|
||||
result['msg'] = "Shutdown command failed. Error was {stdout}, {stderr}".format(
|
||||
stdout=to_native(shutdown_result['stdout'].strip()),
|
||||
stderr=to_native(shutdown_result['stderr'].strip()))
|
||||
result['msg'] = f"Shutdown command failed. Error was {fmt(shutdown_result, 'stdout')}, {fmt(shutdown_result, 'stderr')}"
|
||||
return result
|
||||
|
||||
result['failed'] = False
|
||||
@@ -206,7 +196,7 @@ class ActionModule(ActionBase):
|
||||
|
||||
# If running with local connection, fail so we don't shutdown ourself
|
||||
if self._connection.transport == 'local' and (not self._play_context.check_mode):
|
||||
msg = 'Running {0} with local connection would shutdown the control node.'.format(self._task.action)
|
||||
msg = f'Running {self._task.action} with local connection would shutdown the control node.'
|
||||
return {'changed': False, 'elapsed': 0, 'shutdown': False, 'failed': True, 'msg': msg}
|
||||
|
||||
if task_vars is None:
|
||||
|
||||
@@ -5,86 +5,86 @@
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
name: doas
|
||||
short_description: Do As user
|
||||
DOCUMENTATION = r"""
|
||||
name: doas
|
||||
short_description: Do As user
|
||||
description:
|
||||
- This become plugins allows your remote/login user to execute commands as another user using the C(doas) utility.
|
||||
author: Ansible Core Team
|
||||
options:
|
||||
become_user:
|
||||
description: User you 'become' to execute the task.
|
||||
type: string
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_user
|
||||
- section: doas_become_plugin
|
||||
key: user
|
||||
vars:
|
||||
- name: ansible_become_user
|
||||
- name: ansible_doas_user
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_USER
|
||||
- name: ANSIBLE_DOAS_USER
|
||||
become_exe:
|
||||
description: C(doas) executable.
|
||||
type: string
|
||||
default: doas
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_exe
|
||||
- section: doas_become_plugin
|
||||
key: executable
|
||||
vars:
|
||||
- name: ansible_become_exe
|
||||
- name: ansible_doas_exe
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_EXE
|
||||
- name: ANSIBLE_DOAS_EXE
|
||||
become_flags:
|
||||
description: Options to pass to C(doas).
|
||||
type: string
|
||||
default: ''
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_flags
|
||||
- section: doas_become_plugin
|
||||
key: flags
|
||||
vars:
|
||||
- name: ansible_become_flags
|
||||
- name: ansible_doas_flags
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_FLAGS
|
||||
- name: ANSIBLE_DOAS_FLAGS
|
||||
become_pass:
|
||||
description: Password for C(doas) prompt.
|
||||
type: string
|
||||
required: false
|
||||
vars:
|
||||
- name: ansible_become_password
|
||||
- name: ansible_become_pass
|
||||
- name: ansible_doas_pass
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_PASS
|
||||
- name: ANSIBLE_DOAS_PASS
|
||||
ini:
|
||||
- section: doas_become_plugin
|
||||
key: password
|
||||
prompt_l10n:
|
||||
description:
|
||||
- This become plugins allows your remote/login user to execute commands as another user via the doas utility.
|
||||
author: Ansible Core Team
|
||||
options:
|
||||
become_user:
|
||||
description: User you 'become' to execute the task.
|
||||
type: string
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_user
|
||||
- section: doas_become_plugin
|
||||
key: user
|
||||
vars:
|
||||
- name: ansible_become_user
|
||||
- name: ansible_doas_user
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_USER
|
||||
- name: ANSIBLE_DOAS_USER
|
||||
become_exe:
|
||||
description: Doas executable.
|
||||
type: string
|
||||
default: doas
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_exe
|
||||
- section: doas_become_plugin
|
||||
key: executable
|
||||
vars:
|
||||
- name: ansible_become_exe
|
||||
- name: ansible_doas_exe
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_EXE
|
||||
- name: ANSIBLE_DOAS_EXE
|
||||
become_flags:
|
||||
description: Options to pass to doas.
|
||||
type: string
|
||||
default: ''
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_flags
|
||||
- section: doas_become_plugin
|
||||
key: flags
|
||||
vars:
|
||||
- name: ansible_become_flags
|
||||
- name: ansible_doas_flags
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_FLAGS
|
||||
- name: ANSIBLE_DOAS_FLAGS
|
||||
become_pass:
|
||||
description: Password for doas prompt.
|
||||
type: string
|
||||
required: false
|
||||
vars:
|
||||
- name: ansible_become_password
|
||||
- name: ansible_become_pass
|
||||
- name: ansible_doas_pass
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_PASS
|
||||
- name: ANSIBLE_DOAS_PASS
|
||||
ini:
|
||||
- section: doas_become_plugin
|
||||
key: password
|
||||
prompt_l10n:
|
||||
description:
|
||||
- List of localized strings to match for prompt detection.
|
||||
- If empty we will use the built in one.
|
||||
type: list
|
||||
elements: string
|
||||
default: []
|
||||
ini:
|
||||
- section: doas_become_plugin
|
||||
key: localized_prompts
|
||||
vars:
|
||||
- name: ansible_doas_prompt_l10n
|
||||
env:
|
||||
- name: ANSIBLE_DOAS_PROMPT_L10N
|
||||
'''
|
||||
- List of localized strings to match for prompt detection.
|
||||
- If empty we will use the built in one.
|
||||
type: list
|
||||
elements: string
|
||||
default: []
|
||||
ini:
|
||||
- section: doas_become_plugin
|
||||
key: localized_prompts
|
||||
vars:
|
||||
- name: ansible_doas_prompt_l10n
|
||||
env:
|
||||
- name: ANSIBLE_DOAS_PROMPT_L10N
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
@@ -125,9 +125,9 @@ class BecomeModule(BecomeBase):
|
||||
flags += ' -n'
|
||||
|
||||
become_user = self.get_option('become_user')
|
||||
user = '-u %s' % (become_user) if become_user else ''
|
||||
user = f'-u {become_user}' if become_user else ''
|
||||
|
||||
success_cmd = self._build_success_command(cmd, shell, noexe=True)
|
||||
executable = getattr(shell, 'executable', shell.SHELL_FAMILY)
|
||||
|
||||
return '%s %s %s %s -c %s' % (become_exe, flags, user, executable, success_cmd)
|
||||
return f'{become_exe} {flags} {user} {executable} -c {success_cmd}'
|
||||
|
||||
@@ -5,72 +5,72 @@
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
name: dzdo
|
||||
short_description: Centrify's Direct Authorize
|
||||
description:
|
||||
- This become plugins allows your remote/login user to execute commands as another user via the dzdo utility.
|
||||
author: Ansible Core Team
|
||||
options:
|
||||
become_user:
|
||||
description: User you 'become' to execute the task.
|
||||
type: string
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_user
|
||||
- section: dzdo_become_plugin
|
||||
key: user
|
||||
vars:
|
||||
- name: ansible_become_user
|
||||
- name: ansible_dzdo_user
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_USER
|
||||
- name: ANSIBLE_DZDO_USER
|
||||
become_exe:
|
||||
description: Dzdo executable.
|
||||
type: string
|
||||
default: dzdo
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_exe
|
||||
- section: dzdo_become_plugin
|
||||
key: executable
|
||||
vars:
|
||||
- name: ansible_become_exe
|
||||
- name: ansible_dzdo_exe
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_EXE
|
||||
- name: ANSIBLE_DZDO_EXE
|
||||
become_flags:
|
||||
description: Options to pass to dzdo.
|
||||
type: string
|
||||
default: -H -S -n
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_flags
|
||||
- section: dzdo_become_plugin
|
||||
key: flags
|
||||
vars:
|
||||
- name: ansible_become_flags
|
||||
- name: ansible_dzdo_flags
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_FLAGS
|
||||
- name: ANSIBLE_DZDO_FLAGS
|
||||
become_pass:
|
||||
description: Options to pass to dzdo.
|
||||
type: string
|
||||
required: false
|
||||
vars:
|
||||
- name: ansible_become_password
|
||||
- name: ansible_become_pass
|
||||
- name: ansible_dzdo_pass
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_PASS
|
||||
- name: ANSIBLE_DZDO_PASS
|
||||
ini:
|
||||
- section: dzdo_become_plugin
|
||||
key: password
|
||||
'''
|
||||
DOCUMENTATION = r"""
|
||||
name: dzdo
|
||||
short_description: Centrify's Direct Authorize
|
||||
description:
|
||||
- This become plugins allows your remote/login user to execute commands as another user using the C(dzdo) utility.
|
||||
author: Ansible Core Team
|
||||
options:
|
||||
become_user:
|
||||
description: User you 'become' to execute the task.
|
||||
type: string
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_user
|
||||
- section: dzdo_become_plugin
|
||||
key: user
|
||||
vars:
|
||||
- name: ansible_become_user
|
||||
- name: ansible_dzdo_user
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_USER
|
||||
- name: ANSIBLE_DZDO_USER
|
||||
become_exe:
|
||||
description: C(dzdo) executable.
|
||||
type: string
|
||||
default: dzdo
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_exe
|
||||
- section: dzdo_become_plugin
|
||||
key: executable
|
||||
vars:
|
||||
- name: ansible_become_exe
|
||||
- name: ansible_dzdo_exe
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_EXE
|
||||
- name: ANSIBLE_DZDO_EXE
|
||||
become_flags:
|
||||
description: Options to pass to C(dzdo).
|
||||
type: string
|
||||
default: -H -S -n
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_flags
|
||||
- section: dzdo_become_plugin
|
||||
key: flags
|
||||
vars:
|
||||
- name: ansible_become_flags
|
||||
- name: ansible_dzdo_flags
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_FLAGS
|
||||
- name: ANSIBLE_DZDO_FLAGS
|
||||
become_pass:
|
||||
description: Options to pass to C(dzdo).
|
||||
type: string
|
||||
required: false
|
||||
vars:
|
||||
- name: ansible_become_password
|
||||
- name: ansible_become_pass
|
||||
- name: ansible_dzdo_pass
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_PASS
|
||||
- name: ANSIBLE_DZDO_PASS
|
||||
ini:
|
||||
- section: dzdo_become_plugin
|
||||
key: password
|
||||
"""
|
||||
|
||||
from ansible.plugins.become import BecomeBase
|
||||
|
||||
@@ -92,10 +92,10 @@ class BecomeModule(BecomeBase):
|
||||
|
||||
flags = self.get_option('become_flags')
|
||||
if self.get_option('become_pass'):
|
||||
self.prompt = '[dzdo via ansible, key=%s] password:' % self._id
|
||||
flags = '%s -p "%s"' % (flags.replace('-n', ''), self.prompt)
|
||||
self.prompt = f'[dzdo via ansible, key={self._id}] password:'
|
||||
flags = f"{flags.replace('-n', '')} -p \"{self.prompt}\""
|
||||
|
||||
become_user = self.get_option('become_user')
|
||||
user = '-u %s' % (become_user) if become_user else ''
|
||||
user = f'-u {become_user}' if become_user else ''
|
||||
|
||||
return ' '.join([becomecmd, flags, user, self._build_success_command(cmd, shell)])
|
||||
return f"{becomecmd} {flags} {user} {self._build_success_command(cmd, shell)}"
|
||||
|
||||
@@ -5,87 +5,87 @@
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
name: ksu
|
||||
short_description: Kerberos substitute user
|
||||
DOCUMENTATION = r"""
|
||||
name: ksu
|
||||
short_description: Kerberos substitute user
|
||||
description:
|
||||
- This become plugins allows your remote/login user to execute commands as another user using the C(ksu) utility.
|
||||
author: Ansible Core Team
|
||||
options:
|
||||
become_user:
|
||||
description: User you 'become' to execute the task.
|
||||
type: string
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_user
|
||||
- section: ksu_become_plugin
|
||||
key: user
|
||||
vars:
|
||||
- name: ansible_become_user
|
||||
- name: ansible_ksu_user
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_USER
|
||||
- name: ANSIBLE_KSU_USER
|
||||
required: true
|
||||
become_exe:
|
||||
description: C(ksu) executable.
|
||||
type: string
|
||||
default: ksu
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_exe
|
||||
- section: ksu_become_plugin
|
||||
key: executable
|
||||
vars:
|
||||
- name: ansible_become_exe
|
||||
- name: ansible_ksu_exe
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_EXE
|
||||
- name: ANSIBLE_KSU_EXE
|
||||
become_flags:
|
||||
description: Options to pass to C(ksu).
|
||||
type: string
|
||||
default: ''
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_flags
|
||||
- section: ksu_become_plugin
|
||||
key: flags
|
||||
vars:
|
||||
- name: ansible_become_flags
|
||||
- name: ansible_ksu_flags
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_FLAGS
|
||||
- name: ANSIBLE_KSU_FLAGS
|
||||
become_pass:
|
||||
description: C(ksu) password.
|
||||
type: string
|
||||
required: false
|
||||
vars:
|
||||
- name: ansible_ksu_pass
|
||||
- name: ansible_become_pass
|
||||
- name: ansible_become_password
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_PASS
|
||||
- name: ANSIBLE_KSU_PASS
|
||||
ini:
|
||||
- section: ksu_become_plugin
|
||||
key: password
|
||||
prompt_l10n:
|
||||
description:
|
||||
- This become plugins allows your remote/login user to execute commands as another user via the ksu utility.
|
||||
author: Ansible Core Team
|
||||
options:
|
||||
become_user:
|
||||
description: User you 'become' to execute the task.
|
||||
type: string
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_user
|
||||
- section: ksu_become_plugin
|
||||
key: user
|
||||
vars:
|
||||
- name: ansible_become_user
|
||||
- name: ansible_ksu_user
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_USER
|
||||
- name: ANSIBLE_KSU_USER
|
||||
required: true
|
||||
become_exe:
|
||||
description: Su executable.
|
||||
type: string
|
||||
default: ksu
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_exe
|
||||
- section: ksu_become_plugin
|
||||
key: executable
|
||||
vars:
|
||||
- name: ansible_become_exe
|
||||
- name: ansible_ksu_exe
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_EXE
|
||||
- name: ANSIBLE_KSU_EXE
|
||||
become_flags:
|
||||
description: Options to pass to ksu.
|
||||
type: string
|
||||
default: ''
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_flags
|
||||
- section: ksu_become_plugin
|
||||
key: flags
|
||||
vars:
|
||||
- name: ansible_become_flags
|
||||
- name: ansible_ksu_flags
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_FLAGS
|
||||
- name: ANSIBLE_KSU_FLAGS
|
||||
become_pass:
|
||||
description: Ksu password.
|
||||
type: string
|
||||
required: false
|
||||
vars:
|
||||
- name: ansible_ksu_pass
|
||||
- name: ansible_become_pass
|
||||
- name: ansible_become_password
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_PASS
|
||||
- name: ANSIBLE_KSU_PASS
|
||||
ini:
|
||||
- section: ksu_become_plugin
|
||||
key: password
|
||||
prompt_l10n:
|
||||
description:
|
||||
- List of localized strings to match for prompt detection.
|
||||
- If empty we will use the built in one.
|
||||
type: list
|
||||
elements: string
|
||||
default: []
|
||||
ini:
|
||||
- section: ksu_become_plugin
|
||||
key: localized_prompts
|
||||
vars:
|
||||
- name: ansible_ksu_prompt_l10n
|
||||
env:
|
||||
- name: ANSIBLE_KSU_PROMPT_L10N
|
||||
'''
|
||||
- List of localized strings to match for prompt detection.
|
||||
- If empty we will use the built in one.
|
||||
type: list
|
||||
elements: string
|
||||
default: []
|
||||
ini:
|
||||
- section: ksu_become_plugin
|
||||
key: localized_prompts
|
||||
vars:
|
||||
- name: ansible_ksu_prompt_l10n
|
||||
env:
|
||||
- name: ANSIBLE_KSU_PROMPT_L10N
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
@@ -124,4 +124,4 @@ class BecomeModule(BecomeBase):
|
||||
|
||||
flags = self.get_option('become_flags')
|
||||
user = self.get_option('become_user')
|
||||
return '%s %s %s -e %s ' % (exe, user, flags, self._build_success_command(cmd, shell))
|
||||
return f'{exe} {user} {flags} -e {self._build_success_command(cmd, shell)} '
|
||||
|
||||
@@ -5,91 +5,90 @@
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
name: machinectl
|
||||
short_description: Systemd's machinectl privilege escalation
|
||||
description:
|
||||
- This become plugins allows your remote/login user to execute commands as another user via the machinectl utility.
|
||||
author: Ansible Core Team
|
||||
options:
|
||||
become_user:
|
||||
description: User you 'become' to execute the task.
|
||||
type: string
|
||||
default: ''
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_user
|
||||
- section: machinectl_become_plugin
|
||||
key: user
|
||||
vars:
|
||||
- name: ansible_become_user
|
||||
- name: ansible_machinectl_user
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_USER
|
||||
- name: ANSIBLE_MACHINECTL_USER
|
||||
become_exe:
|
||||
description: Machinectl executable.
|
||||
type: string
|
||||
default: machinectl
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_exe
|
||||
- section: machinectl_become_plugin
|
||||
key: executable
|
||||
vars:
|
||||
- name: ansible_become_exe
|
||||
- name: ansible_machinectl_exe
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_EXE
|
||||
- name: ANSIBLE_MACHINECTL_EXE
|
||||
become_flags:
|
||||
description: Options to pass to machinectl.
|
||||
type: string
|
||||
default: ''
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_flags
|
||||
- section: machinectl_become_plugin
|
||||
key: flags
|
||||
vars:
|
||||
- name: ansible_become_flags
|
||||
- name: ansible_machinectl_flags
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_FLAGS
|
||||
- name: ANSIBLE_MACHINECTL_FLAGS
|
||||
become_pass:
|
||||
description: Password for machinectl.
|
||||
type: string
|
||||
required: false
|
||||
vars:
|
||||
- name: ansible_become_password
|
||||
- name: ansible_become_pass
|
||||
- name: ansible_machinectl_pass
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_PASS
|
||||
- name: ANSIBLE_MACHINECTL_PASS
|
||||
ini:
|
||||
- section: machinectl_become_plugin
|
||||
key: password
|
||||
notes:
|
||||
- When not using this plugin with user V(root), it only works correctly with a polkit rule which will alter
|
||||
the behaviour of machinectl. This rule must alter the prompt behaviour to ask directly for the user credentials,
|
||||
if the user is allowed to perform the action (take a look at the examples section).
|
||||
If such a rule is not present the plugin only work if it is used in context with the root user,
|
||||
because then no further prompt will be shown by machinectl.
|
||||
'''
|
||||
DOCUMENTATION = r"""
|
||||
name: machinectl
|
||||
short_description: Systemd's machinectl privilege escalation
|
||||
description:
|
||||
- This become plugins allows your remote/login user to execute commands as another user using the C(machinectl) utility.
|
||||
author: Ansible Core Team
|
||||
options:
|
||||
become_user:
|
||||
description: User you 'become' to execute the task.
|
||||
type: string
|
||||
default: ''
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_user
|
||||
- section: machinectl_become_plugin
|
||||
key: user
|
||||
vars:
|
||||
- name: ansible_become_user
|
||||
- name: ansible_machinectl_user
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_USER
|
||||
- name: ANSIBLE_MACHINECTL_USER
|
||||
become_exe:
|
||||
description: C(machinectl) executable.
|
||||
type: string
|
||||
default: machinectl
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_exe
|
||||
- section: machinectl_become_plugin
|
||||
key: executable
|
||||
vars:
|
||||
- name: ansible_become_exe
|
||||
- name: ansible_machinectl_exe
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_EXE
|
||||
- name: ANSIBLE_MACHINECTL_EXE
|
||||
become_flags:
|
||||
description: Options to pass to C(machinectl).
|
||||
type: string
|
||||
default: ''
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_flags
|
||||
- section: machinectl_become_plugin
|
||||
key: flags
|
||||
vars:
|
||||
- name: ansible_become_flags
|
||||
- name: ansible_machinectl_flags
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_FLAGS
|
||||
- name: ANSIBLE_MACHINECTL_FLAGS
|
||||
become_pass:
|
||||
description: Password for C(machinectl).
|
||||
type: string
|
||||
required: false
|
||||
vars:
|
||||
- name: ansible_become_password
|
||||
- name: ansible_become_pass
|
||||
- name: ansible_machinectl_pass
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_PASS
|
||||
- name: ANSIBLE_MACHINECTL_PASS
|
||||
ini:
|
||||
- section: machinectl_become_plugin
|
||||
key: password
|
||||
notes:
|
||||
- When not using this plugin with user V(root), it only works correctly with a polkit rule which will alter the behaviour
|
||||
of machinectl. This rule must alter the prompt behaviour to ask directly for the user credentials, if the user is allowed
|
||||
to perform the action (take a look at the examples section). If such a rule is not present the plugin only work if it
|
||||
is used in context with the root user, because then no further prompt will be shown by machinectl.
|
||||
"""
|
||||
|
||||
EXAMPLES = r'''
|
||||
EXAMPLES = r"""
|
||||
# A polkit rule needed to use the module with a non-root user.
|
||||
# See the Notes section for details.
|
||||
/etc/polkit-1/rules.d/60-machinectl-fast-user-auth.rules: |
|
||||
/etc/polkit-1/rules.d/60-machinectl-fast-user-auth.rules: |-
|
||||
polkit.addRule(function(action, subject) {
|
||||
if(action.id == "org.freedesktop.machine1.host-shell" &&
|
||||
subject.isInGroup("wheel")) {
|
||||
return polkit.Result.AUTH_SELF_KEEP;
|
||||
}
|
||||
});
|
||||
'''
|
||||
"""
|
||||
|
||||
from re import compile as re_compile
|
||||
|
||||
@@ -123,7 +122,7 @@ class BecomeModule(BecomeBase):
|
||||
|
||||
flags = self.get_option('become_flags')
|
||||
user = self.get_option('become_user')
|
||||
return '%s -q shell %s %s@ %s' % (become, flags, user, self._build_success_command(cmd, shell))
|
||||
return f'{become} -q shell {flags} {user}@ {self._build_success_command(cmd, shell)}'
|
||||
|
||||
def check_success(self, b_output):
|
||||
b_output = self.remove_ansi_codes(b_output)
|
||||
|
||||
@@ -5,84 +5,84 @@
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
name: pbrun
|
||||
short_description: PowerBroker run
|
||||
description:
|
||||
- This become plugins allows your remote/login user to execute commands as another user via the pbrun utility.
|
||||
author: Ansible Core Team
|
||||
options:
|
||||
become_user:
|
||||
description: User you 'become' to execute the task.
|
||||
type: string
|
||||
default: ''
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_user
|
||||
- section: pbrun_become_plugin
|
||||
key: user
|
||||
vars:
|
||||
- name: ansible_become_user
|
||||
- name: ansible_pbrun_user
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_USER
|
||||
- name: ANSIBLE_PBRUN_USER
|
||||
become_exe:
|
||||
description: Sudo executable.
|
||||
type: string
|
||||
default: pbrun
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_exe
|
||||
- section: pbrun_become_plugin
|
||||
key: executable
|
||||
vars:
|
||||
- name: ansible_become_exe
|
||||
- name: ansible_pbrun_exe
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_EXE
|
||||
- name: ANSIBLE_PBRUN_EXE
|
||||
become_flags:
|
||||
description: Options to pass to pbrun.
|
||||
type: string
|
||||
default: ''
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_flags
|
||||
- section: pbrun_become_plugin
|
||||
key: flags
|
||||
vars:
|
||||
- name: ansible_become_flags
|
||||
- name: ansible_pbrun_flags
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_FLAGS
|
||||
- name: ANSIBLE_PBRUN_FLAGS
|
||||
become_pass:
|
||||
description: Password for pbrun.
|
||||
type: string
|
||||
required: false
|
||||
vars:
|
||||
- name: ansible_become_password
|
||||
- name: ansible_become_pass
|
||||
- name: ansible_pbrun_pass
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_PASS
|
||||
- name: ANSIBLE_PBRUN_PASS
|
||||
ini:
|
||||
- section: pbrun_become_plugin
|
||||
key: password
|
||||
wrap_exe:
|
||||
description: Toggle to wrap the command pbrun calls in C(shell -c) or not.
|
||||
default: false
|
||||
type: bool
|
||||
ini:
|
||||
- section: pbrun_become_plugin
|
||||
key: wrap_execution
|
||||
vars:
|
||||
- name: ansible_pbrun_wrap_execution
|
||||
env:
|
||||
- name: ANSIBLE_PBRUN_WRAP_EXECUTION
|
||||
'''
|
||||
DOCUMENTATION = r"""
|
||||
name: pbrun
|
||||
short_description: PowerBroker run
|
||||
description:
|
||||
- This become plugins allows your remote/login user to execute commands as another user using the C(pbrun) utility.
|
||||
author: Ansible Core Team
|
||||
options:
|
||||
become_user:
|
||||
description: User you 'become' to execute the task.
|
||||
type: string
|
||||
default: ''
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_user
|
||||
- section: pbrun_become_plugin
|
||||
key: user
|
||||
vars:
|
||||
- name: ansible_become_user
|
||||
- name: ansible_pbrun_user
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_USER
|
||||
- name: ANSIBLE_PBRUN_USER
|
||||
become_exe:
|
||||
description: C(pbrun) executable.
|
||||
type: string
|
||||
default: pbrun
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_exe
|
||||
- section: pbrun_become_plugin
|
||||
key: executable
|
||||
vars:
|
||||
- name: ansible_become_exe
|
||||
- name: ansible_pbrun_exe
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_EXE
|
||||
- name: ANSIBLE_PBRUN_EXE
|
||||
become_flags:
|
||||
description: Options to pass to C(pbrun).
|
||||
type: string
|
||||
default: ''
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_flags
|
||||
- section: pbrun_become_plugin
|
||||
key: flags
|
||||
vars:
|
||||
- name: ansible_become_flags
|
||||
- name: ansible_pbrun_flags
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_FLAGS
|
||||
- name: ANSIBLE_PBRUN_FLAGS
|
||||
become_pass:
|
||||
description: Password for C(pbrun).
|
||||
type: string
|
||||
required: false
|
||||
vars:
|
||||
- name: ansible_become_password
|
||||
- name: ansible_become_pass
|
||||
- name: ansible_pbrun_pass
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_PASS
|
||||
- name: ANSIBLE_PBRUN_PASS
|
||||
ini:
|
||||
- section: pbrun_become_plugin
|
||||
key: password
|
||||
wrap_exe:
|
||||
description: Toggle to wrap the command C(pbrun) calls in C(shell -c) or not.
|
||||
default: false
|
||||
type: bool
|
||||
ini:
|
||||
- section: pbrun_become_plugin
|
||||
key: wrap_execution
|
||||
vars:
|
||||
- name: ansible_pbrun_wrap_execution
|
||||
env:
|
||||
- name: ANSIBLE_PBRUN_WRAP_EXECUTION
|
||||
"""
|
||||
|
||||
from ansible.plugins.become import BecomeBase
|
||||
|
||||
@@ -103,7 +103,7 @@ class BecomeModule(BecomeBase):
|
||||
|
||||
flags = self.get_option('become_flags')
|
||||
become_user = self.get_option('become_user')
|
||||
user = '-u %s' % (become_user) if become_user else ''
|
||||
user = f'-u {become_user}' if become_user else ''
|
||||
noexe = not self.get_option('wrap_exe')
|
||||
|
||||
return ' '.join([become_exe, flags, user, self._build_success_command(cmd, shell, noexe=noexe)])
|
||||
return f"{become_exe} {flags} {user} {self._build_success_command(cmd, shell, noexe=noexe)}"
|
||||
|
||||
@@ -5,89 +5,89 @@
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
name: pfexec
|
||||
short_description: profile based execution
|
||||
DOCUMENTATION = r"""
|
||||
name: pfexec
|
||||
short_description: profile based execution
|
||||
description:
|
||||
- This become plugins allows your remote/login user to execute commands as another user using the C(pfexec) utility.
|
||||
author: Ansible Core Team
|
||||
options:
|
||||
become_user:
|
||||
description:
|
||||
- This become plugins allows your remote/login user to execute commands as another user via the pfexec utility.
|
||||
author: Ansible Core Team
|
||||
options:
|
||||
become_user:
|
||||
description:
|
||||
- User you 'become' to execute the task.
|
||||
- This plugin ignores this setting as pfexec uses it's own C(exec_attr) to figure this out,
|
||||
but it is supplied here for Ansible to make decisions needed for the task execution, like file permissions.
|
||||
type: string
|
||||
default: root
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_user
|
||||
- section: pfexec_become_plugin
|
||||
key: user
|
||||
vars:
|
||||
- name: ansible_become_user
|
||||
- name: ansible_pfexec_user
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_USER
|
||||
- name: ANSIBLE_PFEXEC_USER
|
||||
become_exe:
|
||||
description: Sudo executable.
|
||||
type: string
|
||||
default: pfexec
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_exe
|
||||
- section: pfexec_become_plugin
|
||||
key: executable
|
||||
vars:
|
||||
- name: ansible_become_exe
|
||||
- name: ansible_pfexec_exe
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_EXE
|
||||
- name: ANSIBLE_PFEXEC_EXE
|
||||
become_flags:
|
||||
description: Options to pass to pfexec.
|
||||
type: string
|
||||
default: -H -S -n
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_flags
|
||||
- section: pfexec_become_plugin
|
||||
key: flags
|
||||
vars:
|
||||
- name: ansible_become_flags
|
||||
- name: ansible_pfexec_flags
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_FLAGS
|
||||
- name: ANSIBLE_PFEXEC_FLAGS
|
||||
become_pass:
|
||||
description: pfexec password.
|
||||
type: string
|
||||
required: false
|
||||
vars:
|
||||
- name: ansible_become_password
|
||||
- name: ansible_become_pass
|
||||
- name: ansible_pfexec_pass
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_PASS
|
||||
- name: ANSIBLE_PFEXEC_PASS
|
||||
ini:
|
||||
- section: pfexec_become_plugin
|
||||
key: password
|
||||
wrap_exe:
|
||||
description: Toggle to wrap the command pfexec calls in C(shell -c) or not.
|
||||
default: false
|
||||
type: bool
|
||||
ini:
|
||||
- section: pfexec_become_plugin
|
||||
key: wrap_execution
|
||||
vars:
|
||||
- name: ansible_pfexec_wrap_execution
|
||||
env:
|
||||
- name: ANSIBLE_PFEXEC_WRAP_EXECUTION
|
||||
notes:
|
||||
- This plugin ignores O(become_user) as pfexec uses its own C(exec_attr) to figure this out.
|
||||
'''
|
||||
- User you 'become' to execute the task.
|
||||
- This plugin ignores this setting as pfexec uses its own C(exec_attr) to figure this out, but it is supplied here
|
||||
for Ansible to make decisions needed for the task execution, like file permissions.
|
||||
type: string
|
||||
default: root
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_user
|
||||
- section: pfexec_become_plugin
|
||||
key: user
|
||||
vars:
|
||||
- name: ansible_become_user
|
||||
- name: ansible_pfexec_user
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_USER
|
||||
- name: ANSIBLE_PFEXEC_USER
|
||||
become_exe:
|
||||
description: C(pfexec) executable.
|
||||
type: string
|
||||
default: pfexec
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_exe
|
||||
- section: pfexec_become_plugin
|
||||
key: executable
|
||||
vars:
|
||||
- name: ansible_become_exe
|
||||
- name: ansible_pfexec_exe
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_EXE
|
||||
- name: ANSIBLE_PFEXEC_EXE
|
||||
become_flags:
|
||||
description: Options to pass to C(pfexec).
|
||||
type: string
|
||||
default: -H -S -n
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_flags
|
||||
- section: pfexec_become_plugin
|
||||
key: flags
|
||||
vars:
|
||||
- name: ansible_become_flags
|
||||
- name: ansible_pfexec_flags
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_FLAGS
|
||||
- name: ANSIBLE_PFEXEC_FLAGS
|
||||
become_pass:
|
||||
description: C(pfexec) password.
|
||||
type: string
|
||||
required: false
|
||||
vars:
|
||||
- name: ansible_become_password
|
||||
- name: ansible_become_pass
|
||||
- name: ansible_pfexec_pass
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_PASS
|
||||
- name: ANSIBLE_PFEXEC_PASS
|
||||
ini:
|
||||
- section: pfexec_become_plugin
|
||||
key: password
|
||||
wrap_exe:
|
||||
description: Toggle to wrap the command C(pfexec) calls in C(shell -c) or not.
|
||||
default: false
|
||||
type: bool
|
||||
ini:
|
||||
- section: pfexec_become_plugin
|
||||
key: wrap_execution
|
||||
vars:
|
||||
- name: ansible_pfexec_wrap_execution
|
||||
env:
|
||||
- name: ANSIBLE_PFEXEC_WRAP_EXECUTION
|
||||
notes:
|
||||
- This plugin ignores O(become_user) as pfexec uses its own C(exec_attr) to figure this out.
|
||||
"""
|
||||
|
||||
from ansible.plugins.become import BecomeBase
|
||||
|
||||
@@ -106,4 +106,4 @@ class BecomeModule(BecomeBase):
|
||||
|
||||
flags = self.get_option('become_flags')
|
||||
noexe = not self.get_option('wrap_exe')
|
||||
return '%s %s %s' % (exe, flags, self._build_success_command(cmd, shell, noexe=noexe))
|
||||
return f'{exe} {flags} {self._build_success_command(cmd, shell, noexe=noexe)}'
|
||||
|
||||
@@ -5,60 +5,60 @@
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
name: pmrun
|
||||
short_description: Privilege Manager run
|
||||
description:
|
||||
- This become plugins allows your remote/login user to execute commands as another user via the pmrun utility.
|
||||
author: Ansible Core Team
|
||||
options:
|
||||
become_exe:
|
||||
description: Sudo executable
|
||||
type: string
|
||||
default: pmrun
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_exe
|
||||
- section: pmrun_become_plugin
|
||||
key: executable
|
||||
vars:
|
||||
- name: ansible_become_exe
|
||||
- name: ansible_pmrun_exe
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_EXE
|
||||
- name: ANSIBLE_PMRUN_EXE
|
||||
become_flags:
|
||||
description: Options to pass to pmrun.
|
||||
type: string
|
||||
default: ''
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_flags
|
||||
- section: pmrun_become_plugin
|
||||
key: flags
|
||||
vars:
|
||||
- name: ansible_become_flags
|
||||
- name: ansible_pmrun_flags
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_FLAGS
|
||||
- name: ANSIBLE_PMRUN_FLAGS
|
||||
become_pass:
|
||||
description: pmrun password.
|
||||
type: string
|
||||
required: false
|
||||
vars:
|
||||
- name: ansible_become_password
|
||||
- name: ansible_become_pass
|
||||
- name: ansible_pmrun_pass
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_PASS
|
||||
- name: ANSIBLE_PMRUN_PASS
|
||||
ini:
|
||||
- section: pmrun_become_plugin
|
||||
key: password
|
||||
notes:
|
||||
- This plugin ignores the become_user supplied and uses pmrun's own configuration to select the user.
|
||||
'''
|
||||
DOCUMENTATION = r"""
|
||||
name: pmrun
|
||||
short_description: Privilege Manager run
|
||||
description:
|
||||
- This become plugins allows your remote/login user to execute commands as another user using the C(pmrun) utility.
|
||||
author: Ansible Core Team
|
||||
options:
|
||||
become_exe:
|
||||
description: C(pmrun) executable.
|
||||
type: string
|
||||
default: pmrun
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_exe
|
||||
- section: pmrun_become_plugin
|
||||
key: executable
|
||||
vars:
|
||||
- name: ansible_become_exe
|
||||
- name: ansible_pmrun_exe
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_EXE
|
||||
- name: ANSIBLE_PMRUN_EXE
|
||||
become_flags:
|
||||
description: Options to pass to C(pmrun).
|
||||
type: string
|
||||
default: ''
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_flags
|
||||
- section: pmrun_become_plugin
|
||||
key: flags
|
||||
vars:
|
||||
- name: ansible_become_flags
|
||||
- name: ansible_pmrun_flags
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_FLAGS
|
||||
- name: ANSIBLE_PMRUN_FLAGS
|
||||
become_pass:
|
||||
description: C(pmrun) password.
|
||||
type: string
|
||||
required: false
|
||||
vars:
|
||||
- name: ansible_become_password
|
||||
- name: ansible_become_pass
|
||||
- name: ansible_pmrun_pass
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_PASS
|
||||
- name: ANSIBLE_PMRUN_PASS
|
||||
ini:
|
||||
- section: pmrun_become_plugin
|
||||
key: password
|
||||
notes:
|
||||
- This plugin ignores the C(become_user) supplied and uses C(pmrun)'s own configuration to select the user.
|
||||
"""
|
||||
|
||||
from ansible.plugins.become import BecomeBase
|
||||
from ansible.module_utils.six.moves import shlex_quote
|
||||
@@ -78,4 +78,4 @@ class BecomeModule(BecomeBase):
|
||||
become = self.get_option('become_exe')
|
||||
|
||||
flags = self.get_option('become_flags')
|
||||
return '%s %s %s' % (become, flags, shlex_quote(self._build_success_command(cmd, shell)))
|
||||
return f'{become} {flags} {shlex_quote(self._build_success_command(cmd, shell))}'
|
||||
|
||||
@@ -7,68 +7,68 @@ from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = """
|
||||
name: run0
|
||||
short_description: Systemd's run0
|
||||
description:
|
||||
- This become plugins allows your remote/login user to execute commands as another user via the C(run0) utility.
|
||||
author:
|
||||
- Thomas Sjögren (@konstruktoid)
|
||||
version_added: '9.0.0'
|
||||
options:
|
||||
become_user:
|
||||
description: User you 'become' to execute the task.
|
||||
default: root
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_user
|
||||
- section: run0_become_plugin
|
||||
key: user
|
||||
vars:
|
||||
- name: ansible_become_user
|
||||
- name: ansible_run0_user
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_USER
|
||||
- name: ANSIBLE_RUN0_USER
|
||||
type: string
|
||||
become_exe:
|
||||
description: The C(run0) executable.
|
||||
default: run0
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_exe
|
||||
- section: run0_become_plugin
|
||||
key: executable
|
||||
vars:
|
||||
- name: ansible_become_exe
|
||||
- name: ansible_run0_exe
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_EXE
|
||||
- name: ANSIBLE_RUN0_EXE
|
||||
type: string
|
||||
become_flags:
|
||||
description: Options to pass to run0.
|
||||
default: ''
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_flags
|
||||
- section: run0_become_plugin
|
||||
key: flags
|
||||
vars:
|
||||
- name: ansible_become_flags
|
||||
- name: ansible_run0_flags
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_FLAGS
|
||||
- name: ANSIBLE_RUN0_FLAGS
|
||||
type: string
|
||||
notes:
|
||||
- This plugin will only work when a polkit rule is in place.
|
||||
DOCUMENTATION = r"""
|
||||
name: run0
|
||||
short_description: Systemd's run0
|
||||
description:
|
||||
- This become plugins allows your remote/login user to execute commands as another user using the C(run0) utility.
|
||||
author:
|
||||
- Thomas Sjögren (@konstruktoid)
|
||||
version_added: '9.0.0'
|
||||
options:
|
||||
become_user:
|
||||
description: User you 'become' to execute the task.
|
||||
default: root
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_user
|
||||
- section: run0_become_plugin
|
||||
key: user
|
||||
vars:
|
||||
- name: ansible_become_user
|
||||
- name: ansible_run0_user
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_USER
|
||||
- name: ANSIBLE_RUN0_USER
|
||||
type: string
|
||||
become_exe:
|
||||
description: C(run0) executable.
|
||||
default: run0
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_exe
|
||||
- section: run0_become_plugin
|
||||
key: executable
|
||||
vars:
|
||||
- name: ansible_become_exe
|
||||
- name: ansible_run0_exe
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_EXE
|
||||
- name: ANSIBLE_RUN0_EXE
|
||||
type: string
|
||||
become_flags:
|
||||
description: Options to pass to C(run0).
|
||||
default: ''
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_flags
|
||||
- section: run0_become_plugin
|
||||
key: flags
|
||||
vars:
|
||||
- name: ansible_become_flags
|
||||
- name: ansible_run0_flags
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_FLAGS
|
||||
- name: ANSIBLE_RUN0_FLAGS
|
||||
type: string
|
||||
notes:
|
||||
- This plugin will only work when a C(polkit) rule is in place.
|
||||
"""
|
||||
|
||||
EXAMPLES = r"""
|
||||
# An example polkit rule that allows the user 'ansible' in the 'wheel' group
|
||||
# to execute commands using run0 without authentication.
|
||||
/etc/polkit-1/rules.d/60-run0-fast-user-auth.rules: |
|
||||
/etc/polkit-1/rules.d/60-run0-fast-user-auth.rules: |-
|
||||
polkit.addRule(function(action, subject) {
|
||||
if(action.id == "org.freedesktop.systemd1.manage-units" &&
|
||||
subject.isInGroup("wheel") &&
|
||||
|
||||
@@ -5,73 +5,73 @@
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
name: sesu
|
||||
short_description: CA Privileged Access Manager
|
||||
description:
|
||||
- This become plugins allows your remote/login user to execute commands as another user via the sesu utility.
|
||||
author: ansible (@nekonyuu)
|
||||
options:
|
||||
become_user:
|
||||
description: User you 'become' to execute the task.
|
||||
type: string
|
||||
default: ''
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_user
|
||||
- section: sesu_become_plugin
|
||||
key: user
|
||||
vars:
|
||||
- name: ansible_become_user
|
||||
- name: ansible_sesu_user
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_USER
|
||||
- name: ANSIBLE_SESU_USER
|
||||
become_exe:
|
||||
description: sesu executable.
|
||||
type: string
|
||||
default: sesu
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_exe
|
||||
- section: sesu_become_plugin
|
||||
key: executable
|
||||
vars:
|
||||
- name: ansible_become_exe
|
||||
- name: ansible_sesu_exe
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_EXE
|
||||
- name: ANSIBLE_SESU_EXE
|
||||
become_flags:
|
||||
description: Options to pass to sesu.
|
||||
type: string
|
||||
default: -H -S -n
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_flags
|
||||
- section: sesu_become_plugin
|
||||
key: flags
|
||||
vars:
|
||||
- name: ansible_become_flags
|
||||
- name: ansible_sesu_flags
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_FLAGS
|
||||
- name: ANSIBLE_SESU_FLAGS
|
||||
become_pass:
|
||||
description: Password to pass to sesu.
|
||||
type: string
|
||||
required: false
|
||||
vars:
|
||||
- name: ansible_become_password
|
||||
- name: ansible_become_pass
|
||||
- name: ansible_sesu_pass
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_PASS
|
||||
- name: ANSIBLE_SESU_PASS
|
||||
ini:
|
||||
- section: sesu_become_plugin
|
||||
key: password
|
||||
'''
|
||||
DOCUMENTATION = r"""
|
||||
name: sesu
|
||||
short_description: CA Privileged Access Manager
|
||||
description:
|
||||
- This become plugins allows your remote/login user to execute commands as another user using the C(sesu) utility.
|
||||
author: ansible (@nekonyuu)
|
||||
options:
|
||||
become_user:
|
||||
description: User you 'become' to execute the task.
|
||||
type: string
|
||||
default: ''
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_user
|
||||
- section: sesu_become_plugin
|
||||
key: user
|
||||
vars:
|
||||
- name: ansible_become_user
|
||||
- name: ansible_sesu_user
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_USER
|
||||
- name: ANSIBLE_SESU_USER
|
||||
become_exe:
|
||||
description: C(sesu) executable.
|
||||
type: string
|
||||
default: sesu
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_exe
|
||||
- section: sesu_become_plugin
|
||||
key: executable
|
||||
vars:
|
||||
- name: ansible_become_exe
|
||||
- name: ansible_sesu_exe
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_EXE
|
||||
- name: ANSIBLE_SESU_EXE
|
||||
become_flags:
|
||||
description: Options to pass to C(sesu).
|
||||
type: string
|
||||
default: -H -S -n
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_flags
|
||||
- section: sesu_become_plugin
|
||||
key: flags
|
||||
vars:
|
||||
- name: ansible_become_flags
|
||||
- name: ansible_sesu_flags
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_FLAGS
|
||||
- name: ANSIBLE_SESU_FLAGS
|
||||
become_pass:
|
||||
description: Password to pass to C(sesu).
|
||||
type: string
|
||||
required: false
|
||||
vars:
|
||||
- name: ansible_become_password
|
||||
- name: ansible_become_pass
|
||||
- name: ansible_sesu_pass
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_PASS
|
||||
- name: ANSIBLE_SESU_PASS
|
||||
ini:
|
||||
- section: sesu_become_plugin
|
||||
key: password
|
||||
"""
|
||||
|
||||
from ansible.plugins.become import BecomeBase
|
||||
|
||||
@@ -93,4 +93,4 @@ class BecomeModule(BecomeBase):
|
||||
|
||||
flags = self.get_option('become_flags')
|
||||
user = self.get_option('become_user')
|
||||
return '%s %s %s -c %s' % (become, flags, user, self._build_success_command(cmd, shell))
|
||||
return f'{become} {flags} {user} -c {self._build_success_command(cmd, shell)}'
|
||||
|
||||
@@ -5,74 +5,75 @@
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = """
|
||||
name: sudosu
|
||||
short_description: Run tasks using sudo su -
|
||||
DOCUMENTATION = r"""
|
||||
name: sudosu
|
||||
short_description: Run tasks using sudo su -
|
||||
description:
|
||||
- This become plugin allows your remote/login user to execute commands as another user using the C(sudo) and C(su) utilities
|
||||
combined.
|
||||
author:
|
||||
- Dag Wieers (@dagwieers)
|
||||
version_added: 2.4.0
|
||||
options:
|
||||
become_user:
|
||||
description: User you 'become' to execute the task.
|
||||
type: string
|
||||
default: root
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_user
|
||||
- section: sudo_become_plugin
|
||||
key: user
|
||||
vars:
|
||||
- name: ansible_become_user
|
||||
- name: ansible_sudo_user
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_USER
|
||||
- name: ANSIBLE_SUDO_USER
|
||||
become_flags:
|
||||
description: Options to pass to C(sudo).
|
||||
type: string
|
||||
default: -H -S -n
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_flags
|
||||
- section: sudo_become_plugin
|
||||
key: flags
|
||||
vars:
|
||||
- name: ansible_become_flags
|
||||
- name: ansible_sudo_flags
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_FLAGS
|
||||
- name: ANSIBLE_SUDO_FLAGS
|
||||
become_pass:
|
||||
description: Password to pass to C(sudo).
|
||||
type: string
|
||||
required: false
|
||||
vars:
|
||||
- name: ansible_become_password
|
||||
- name: ansible_become_pass
|
||||
- name: ansible_sudo_pass
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_PASS
|
||||
- name: ANSIBLE_SUDO_PASS
|
||||
ini:
|
||||
- section: sudo_become_plugin
|
||||
key: password
|
||||
alt_method:
|
||||
description:
|
||||
- This become plugin allows your remote/login user to execute commands as another user via the C(sudo) and C(su) utilities combined.
|
||||
author:
|
||||
- Dag Wieers (@dagwieers)
|
||||
version_added: 2.4.0
|
||||
options:
|
||||
become_user:
|
||||
description: User you 'become' to execute the task.
|
||||
type: string
|
||||
default: root
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_user
|
||||
- section: sudo_become_plugin
|
||||
key: user
|
||||
vars:
|
||||
- name: ansible_become_user
|
||||
- name: ansible_sudo_user
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_USER
|
||||
- name: ANSIBLE_SUDO_USER
|
||||
become_flags:
|
||||
description: Options to pass to C(sudo).
|
||||
type: string
|
||||
default: -H -S -n
|
||||
ini:
|
||||
- section: privilege_escalation
|
||||
key: become_flags
|
||||
- section: sudo_become_plugin
|
||||
key: flags
|
||||
vars:
|
||||
- name: ansible_become_flags
|
||||
- name: ansible_sudo_flags
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_FLAGS
|
||||
- name: ANSIBLE_SUDO_FLAGS
|
||||
become_pass:
|
||||
description: Password to pass to C(sudo).
|
||||
type: string
|
||||
required: false
|
||||
vars:
|
||||
- name: ansible_become_password
|
||||
- name: ansible_become_pass
|
||||
- name: ansible_sudo_pass
|
||||
env:
|
||||
- name: ANSIBLE_BECOME_PASS
|
||||
- name: ANSIBLE_SUDO_PASS
|
||||
ini:
|
||||
- section: sudo_become_plugin
|
||||
key: password
|
||||
alt_method:
|
||||
description:
|
||||
- Whether to use an alternative method to call C(su). Instead of running C(su -l user /path/to/shell -c command),
|
||||
it runs C(su -l user -c command).
|
||||
- Use this when the default one is not working on your system.
|
||||
required: false
|
||||
type: boolean
|
||||
ini:
|
||||
- section: community.general.sudosu
|
||||
key: alternative_method
|
||||
vars:
|
||||
- name: ansible_sudosu_alt_method
|
||||
env:
|
||||
- name: ANSIBLE_SUDOSU_ALT_METHOD
|
||||
version_added: 9.2.0
|
||||
- Whether to use an alternative method to call C(su). Instead of running C(su -l user /path/to/shell -c command), it
|
||||
runs C(su -l user -c command).
|
||||
- Use this when the default one is not working on your system.
|
||||
required: false
|
||||
type: boolean
|
||||
ini:
|
||||
- section: community.general.sudosu
|
||||
key: alternative_method
|
||||
vars:
|
||||
- name: ansible_sudosu_alt_method
|
||||
env:
|
||||
- name: ANSIBLE_SUDOSU_ALT_METHOD
|
||||
version_added: 9.2.0
|
||||
"""
|
||||
|
||||
|
||||
@@ -98,16 +99,16 @@ class BecomeModule(BecomeBase):
|
||||
flags = self.get_option('become_flags') or ''
|
||||
prompt = ''
|
||||
if self.get_option('become_pass'):
|
||||
self.prompt = '[sudo via ansible, key=%s] password:' % self._id
|
||||
self.prompt = f'[sudo via ansible, key={self._id}] password:'
|
||||
if flags: # this could be simplified, but kept as is for now for backwards string matching
|
||||
flags = flags.replace('-n', '')
|
||||
prompt = '-p "%s"' % (self.prompt)
|
||||
prompt = f'-p "{self.prompt}"'
|
||||
|
||||
user = self.get_option('become_user') or ''
|
||||
if user:
|
||||
user = '%s' % (user)
|
||||
user = f'{user}'
|
||||
|
||||
if self.get_option('alt_method'):
|
||||
return ' '.join([becomecmd, flags, prompt, "su -l", user, "-c", self._build_success_command(cmd, shell, True)])
|
||||
return f"{becomecmd} {flags} {prompt} su -l {user} -c {self._build_success_command(cmd, shell, True)}"
|
||||
else:
|
||||
return ' '.join([becomecmd, flags, prompt, 'su -l', user, self._build_success_command(cmd, shell)])
|
||||
return f"{becomecmd} {flags} {prompt} su -l {user} {self._build_success_command(cmd, shell)}"
|
||||
|
||||
2
plugins/cache/memcached.py
vendored
2
plugins/cache/memcached.py
vendored
@@ -191,7 +191,7 @@ class CacheModule(BaseCacheModule):
|
||||
self._keys = CacheModuleKeys(self._db, self._db.get(CacheModuleKeys.PREFIX) or [])
|
||||
|
||||
def _make_key(self, key):
|
||||
return "{0}{1}".format(self._prefix, key)
|
||||
return f"{self._prefix}{key}"
|
||||
|
||||
def _expire_keys(self):
|
||||
if self._timeout > 0:
|
||||
|
||||
1
plugins/cache/pickle.py
vendored
1
plugins/cache/pickle.py
vendored
@@ -57,7 +57,6 @@ class CacheModule(BaseFileCacheModule):
|
||||
"""
|
||||
A caching module backed by pickle files.
|
||||
"""
|
||||
_persistent = False # prevent unnecessary JSON serialization and key munging
|
||||
|
||||
def _load(self, filepath):
|
||||
# Pickle is a binary format
|
||||
|
||||
7
plugins/cache/redis.py
vendored
7
plugins/cache/redis.py
vendored
@@ -73,7 +73,6 @@ import time
|
||||
import json
|
||||
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.module_utils.common.text.converters import to_native
|
||||
from ansible.parsing.ajson import AnsibleJSONEncoder, AnsibleJSONDecoder
|
||||
from ansible.plugins.cache import BaseCacheModule
|
||||
from ansible.utils.display import Display
|
||||
@@ -131,7 +130,7 @@ class CacheModule(BaseCacheModule):
|
||||
connection = self._parse_connection(self.re_url_conn, uri)
|
||||
self._db = StrictRedis(*connection, **kw)
|
||||
|
||||
display.vv('Redis connection: %s' % self._db)
|
||||
display.vv(f'Redis connection: {self._db}')
|
||||
|
||||
@staticmethod
|
||||
def _parse_connection(re_patt, uri):
|
||||
@@ -164,12 +163,12 @@ class CacheModule(BaseCacheModule):
|
||||
pass # password is optional
|
||||
|
||||
sentinels = [self._parse_connection(self.re_sent_conn, shost) for shost in connections]
|
||||
display.vv('\nUsing redis sentinels: %s' % sentinels)
|
||||
display.vv(f'\nUsing redis sentinels: {sentinels}')
|
||||
scon = Sentinel(sentinels, **kw)
|
||||
try:
|
||||
return scon.master_for(self._sentinel_service_name, socket_timeout=0.2)
|
||||
except Exception as exc:
|
||||
raise AnsibleError('Could not connect to redis sentinel: %s' % to_native(exc))
|
||||
raise AnsibleError(f'Could not connect to redis sentinel: {exc}')
|
||||
|
||||
def _make_key(self, key):
|
||||
return self._prefix + key
|
||||
|
||||
@@ -115,7 +115,7 @@ class CallbackModule(CallbackBase):
|
||||
max_results = int(f.read().strip()) / 1024 / 1024
|
||||
|
||||
self._display.banner('CGROUP MEMORY RECAP')
|
||||
self._display.display('Execution Maximum: %0.2fMB\n\n' % max_results)
|
||||
self._display.display(f'Execution Maximum: {max_results:0.2f}MB\n\n')
|
||||
|
||||
for task, memory in self.task_results:
|
||||
self._display.display('%s (%s): %0.2fMB' % (task.get_name(), task._uuid, memory))
|
||||
self._display.display(f'{task.get_name()} ({task._uuid}): {memory:0.2f}MB')
|
||||
|
||||
@@ -38,15 +38,15 @@ class CallbackModule(CallbackBase):
|
||||
self.play = None
|
||||
|
||||
def v2_on_any(self, *args, **kwargs):
|
||||
self._display.display("--- play: {0} task: {1} ---".format(getattr(self.play, 'name', None), self.task))
|
||||
self._display.display(f"--- play: {getattr(self.play, 'name', None)} task: {self.task} ---")
|
||||
|
||||
self._display.display(" --- ARGS ")
|
||||
for i, a in enumerate(args):
|
||||
self._display.display(' %s: %s' % (i, a))
|
||||
self._display.display(f' {i}: {a}')
|
||||
|
||||
self._display.display(" --- KWARGS ")
|
||||
for k in kwargs:
|
||||
self._display.display(' %s: %s' % (k, kwargs[k]))
|
||||
self._display.display(f' {k}: {kwargs[k]}')
|
||||
|
||||
def v2_playbook_on_play_start(self, play):
|
||||
self.play = play
|
||||
|
||||
@@ -71,7 +71,7 @@ class CallbackModule(CallbackBase):
|
||||
if not name:
|
||||
msg = u"play"
|
||||
else:
|
||||
msg = u"PLAY [%s]" % name
|
||||
msg = f"PLAY [{name}]"
|
||||
|
||||
self._play = play
|
||||
|
||||
@@ -91,25 +91,17 @@ class CallbackModule(CallbackBase):
|
||||
for host in hosts:
|
||||
stat = stats.summarize(host)
|
||||
|
||||
self._display.display(u"%s : %s %s %s %s %s %s" % (
|
||||
hostcolor(host, stat),
|
||||
colorize(u'ok', stat['ok'], C.COLOR_OK),
|
||||
colorize(u'changed', stat['changed'], C.COLOR_CHANGED),
|
||||
colorize(u'unreachable', stat['unreachable'], C.COLOR_UNREACHABLE),
|
||||
colorize(u'failed', stat['failures'], C.COLOR_ERROR),
|
||||
colorize(u'rescued', stat['rescued'], C.COLOR_OK),
|
||||
colorize(u'ignored', stat['ignored'], C.COLOR_WARN)),
|
||||
self._display.display(
|
||||
f"{hostcolor(host, stat)} : {colorize('ok', stat['ok'], C.COLOR_OK)} {colorize('changed', stat['changed'], C.COLOR_CHANGED)} "
|
||||
f"{colorize('unreachable', stat['unreachable'], C.COLOR_UNREACHABLE)} {colorize('failed', stat['failures'], C.COLOR_ERROR)} "
|
||||
f"{colorize('rescued', stat['rescued'], C.COLOR_OK)} {colorize('ignored', stat['ignored'], C.COLOR_WARN)}",
|
||||
screen_only=True
|
||||
)
|
||||
|
||||
self._display.display(u"%s : %s %s %s %s %s %s" % (
|
||||
hostcolor(host, stat, False),
|
||||
colorize(u'ok', stat['ok'], None),
|
||||
colorize(u'changed', stat['changed'], None),
|
||||
colorize(u'unreachable', stat['unreachable'], None),
|
||||
colorize(u'failed', stat['failures'], None),
|
||||
colorize(u'rescued', stat['rescued'], None),
|
||||
colorize(u'ignored', stat['ignored'], None)),
|
||||
self._display.display(
|
||||
f"{hostcolor(host, stat, False)} : {colorize('ok', stat['ok'], None)} {colorize('changed', stat['changed'], None)} "
|
||||
f"{colorize('unreachable', stat['unreachable'], None)} {colorize('failed', stat['failures'], None)} "
|
||||
f"{colorize('rescued', stat['rescued'], None)} {colorize('ignored', stat['ignored'], None)}",
|
||||
log_only=True
|
||||
)
|
||||
|
||||
@@ -124,12 +116,14 @@ class CallbackModule(CallbackBase):
|
||||
for k in sorted(stats.custom.keys()):
|
||||
if k == '_run':
|
||||
continue
|
||||
self._display.display('\t%s: %s' % (k, self._dump_results(stats.custom[k], indent=1).replace('\n', '')))
|
||||
_custom_stats = self._dump_results(stats.custom[k], indent=1).replace('\n', '')
|
||||
self._display.display(f'\t{k}: {_custom_stats}')
|
||||
|
||||
# print per run custom stats
|
||||
if '_run' in stats.custom:
|
||||
self._display.display("", screen_only=True)
|
||||
self._display.display('\tRUN: %s' % self._dump_results(stats.custom['_run'], indent=1).replace('\n', ''))
|
||||
_custom_stats_run = self._dump_results(stats.custom['_run'], indent=1).replace('\n', '')
|
||||
self._display.display(f'\tRUN: {_custom_stats_run}')
|
||||
self._display.display("", screen_only=True)
|
||||
|
||||
def v2_playbook_on_task_start(self, task, is_conditional):
|
||||
@@ -143,13 +137,13 @@ class CallbackModule(CallbackBase):
|
||||
# that they can secure this if they feel that their stdout is insecure
|
||||
# (shoulder surfing, logging stdout straight to a file, etc).
|
||||
if not task.no_log and C.DISPLAY_ARGS_TO_STDOUT:
|
||||
args = ', '.join(('%s=%s' % a for a in task.args.items()))
|
||||
args = ' %s' % args
|
||||
self._display.banner("TASK %d/%d [%s%s]" % (self._task_counter, self._task_total, task.get_name().strip(), args))
|
||||
args = ', '.join(('{k}={v}' for k, v in task.args.items()))
|
||||
args = f' {args}'
|
||||
self._display.banner(f"TASK {self._task_counter}/{self._task_total} [{task.get_name().strip()}{args}]")
|
||||
if self._display.verbosity >= 2:
|
||||
path = task.get_path()
|
||||
if path:
|
||||
self._display.display("task path: %s" % path, color=C.COLOR_DEBUG)
|
||||
self._display.display(f"task path: {path}", color=C.COLOR_DEBUG)
|
||||
self._host_counter = self._previous_batch_total
|
||||
self._task_counter += 1
|
||||
|
||||
@@ -166,15 +160,15 @@ class CallbackModule(CallbackBase):
|
||||
return
|
||||
elif result._result.get('changed', False):
|
||||
if delegated_vars:
|
||||
msg = "changed: %d/%d [%s -> %s]" % (self._host_counter, self._host_total, result._host.get_name(), delegated_vars['ansible_host'])
|
||||
msg = f"changed: {self._host_counter}/{self._host_total} [{result._host.get_name()} -> {delegated_vars['ansible_host']}]"
|
||||
else:
|
||||
msg = "changed: %d/%d [%s]" % (self._host_counter, self._host_total, result._host.get_name())
|
||||
msg = f"changed: {self._host_counter}/{self._host_total} [{result._host.get_name()}]"
|
||||
color = C.COLOR_CHANGED
|
||||
else:
|
||||
if delegated_vars:
|
||||
msg = "ok: %d/%d [%s -> %s]" % (self._host_counter, self._host_total, result._host.get_name(), delegated_vars['ansible_host'])
|
||||
msg = f"ok: {self._host_counter}/{self._host_total} [{result._host.get_name()} -> {delegated_vars['ansible_host']}]"
|
||||
else:
|
||||
msg = "ok: %d/%d [%s]" % (self._host_counter, self._host_total, result._host.get_name())
|
||||
msg = f"ok: {self._host_counter}/{self._host_total} [{result._host.get_name()}]"
|
||||
color = C.COLOR_OK
|
||||
|
||||
self._handle_warnings(result._result)
|
||||
@@ -185,7 +179,7 @@ class CallbackModule(CallbackBase):
|
||||
self._clean_results(result._result, result._task.action)
|
||||
|
||||
if self._run_is_verbose(result):
|
||||
msg += " => %s" % (self._dump_results(result._result),)
|
||||
msg += f" => {self._dump_results(result._result)}"
|
||||
self._display.display(msg, color=color)
|
||||
|
||||
def v2_runner_on_failed(self, result, ignore_errors=False):
|
||||
@@ -206,14 +200,16 @@ class CallbackModule(CallbackBase):
|
||||
|
||||
else:
|
||||
if delegated_vars:
|
||||
self._display.display("fatal: %d/%d [%s -> %s]: FAILED! => %s" % (self._host_counter, self._host_total,
|
||||
result._host.get_name(), delegated_vars['ansible_host'],
|
||||
self._dump_results(result._result)),
|
||||
color=C.COLOR_ERROR)
|
||||
self._display.display(
|
||||
f"fatal: {self._host_counter}/{self._host_total} [{result._host.get_name()} -> "
|
||||
f"{delegated_vars['ansible_host']}]: FAILED! => {self._dump_results(result._result)}",
|
||||
color=C.COLOR_ERROR
|
||||
)
|
||||
else:
|
||||
self._display.display("fatal: %d/%d [%s]: FAILED! => %s" % (self._host_counter, self._host_total,
|
||||
result._host.get_name(), self._dump_results(result._result)),
|
||||
color=C.COLOR_ERROR)
|
||||
self._display.display(
|
||||
f"fatal: {self._host_counter}/{self._host_total} [{result._host.get_name()}]: FAILED! => {self._dump_results(result._result)}",
|
||||
color=C.COLOR_ERROR
|
||||
)
|
||||
|
||||
if ignore_errors:
|
||||
self._display.display("...ignoring", color=C.COLOR_SKIP)
|
||||
@@ -231,9 +227,9 @@ class CallbackModule(CallbackBase):
|
||||
if result._task.loop and 'results' in result._result:
|
||||
self._process_items(result)
|
||||
else:
|
||||
msg = "skipping: %d/%d [%s]" % (self._host_counter, self._host_total, result._host.get_name())
|
||||
msg = f"skipping: {self._host_counter}/{self._host_total} [{result._host.get_name()}]"
|
||||
if self._run_is_verbose(result):
|
||||
msg += " => %s" % self._dump_results(result._result)
|
||||
msg += f" => {self._dump_results(result._result)}"
|
||||
self._display.display(msg, color=C.COLOR_SKIP)
|
||||
|
||||
def v2_runner_on_unreachable(self, result):
|
||||
@@ -244,11 +240,13 @@ class CallbackModule(CallbackBase):
|
||||
|
||||
delegated_vars = result._result.get('_ansible_delegated_vars', None)
|
||||
if delegated_vars:
|
||||
self._display.display("fatal: %d/%d [%s -> %s]: UNREACHABLE! => %s" % (self._host_counter, self._host_total,
|
||||
result._host.get_name(), delegated_vars['ansible_host'],
|
||||
self._dump_results(result._result)),
|
||||
color=C.COLOR_UNREACHABLE)
|
||||
self._display.display(
|
||||
f"fatal: {self._host_counter}/{self._host_total} [{result._host.get_name()} -> "
|
||||
f"{delegated_vars['ansible_host']}]: UNREACHABLE! => {self._dump_results(result._result)}",
|
||||
color=C.COLOR_UNREACHABLE
|
||||
)
|
||||
else:
|
||||
self._display.display("fatal: %d/%d [%s]: UNREACHABLE! => %s" % (self._host_counter, self._host_total,
|
||||
result._host.get_name(), self._dump_results(result._result)),
|
||||
color=C.COLOR_UNREACHABLE)
|
||||
self._display.display(
|
||||
f"fatal: {self._host_counter}/{self._host_total} [{result._host.get_name()}]: UNREACHABLE! => {self._dump_results(result._result)}",
|
||||
color=C.COLOR_UNREACHABLE
|
||||
)
|
||||
|
||||
@@ -195,7 +195,7 @@ class CallbackModule(CallbackModule_default):
|
||||
self.disabled = True
|
||||
|
||||
def __del__(self):
|
||||
sys.stdout.write(vt100.restore + vt100.reset + '\n' + vt100.save + vt100.clearline)
|
||||
sys.stdout.write(f"{vt100.restore}{vt100.reset}\n{vt100.save}{vt100.clearline}")
|
||||
|
||||
def _add_host(self, result, status):
|
||||
name = result._host.get_name()
|
||||
@@ -243,7 +243,7 @@ class CallbackModule(CallbackModule_default):
|
||||
|
||||
def _handle_exceptions(self, result):
|
||||
if 'exception' in result:
|
||||
# Remove the exception from the result so it's not shown every time
|
||||
# Remove the exception from the result so it is not shown every time
|
||||
del result['exception']
|
||||
|
||||
if self._display.verbosity == 1:
|
||||
@@ -252,7 +252,7 @@ class CallbackModule(CallbackModule_default):
|
||||
def _display_progress(self, result=None):
|
||||
# Always rewrite the complete line
|
||||
sys.stdout.write(vt100.restore + vt100.reset + vt100.clearline + vt100.nolinewrap + vt100.underline)
|
||||
sys.stdout.write('%s %d:' % (self.type, self.count[self.type]))
|
||||
sys.stdout.write(f'{self.type} {self.count[self.type]}:')
|
||||
sys.stdout.write(vt100.reset)
|
||||
sys.stdout.flush()
|
||||
|
||||
@@ -260,7 +260,7 @@ class CallbackModule(CallbackModule_default):
|
||||
for name in self.hosts:
|
||||
sys.stdout.write(' ')
|
||||
if self.hosts[name].get('delegate', None):
|
||||
sys.stdout.write(self.hosts[name]['delegate'] + '>')
|
||||
sys.stdout.write(f"{self.hosts[name]['delegate']}>")
|
||||
sys.stdout.write(colors[self.hosts[name]['state']] + name + vt100.reset)
|
||||
sys.stdout.flush()
|
||||
|
||||
@@ -274,8 +274,8 @@ class CallbackModule(CallbackModule_default):
|
||||
if not self.shown_title:
|
||||
self.shown_title = True
|
||||
sys.stdout.write(vt100.restore + vt100.reset + vt100.clearline + vt100.underline)
|
||||
sys.stdout.write('%s %d: %s' % (self.type, self.count[self.type], self.task.get_name().strip()))
|
||||
sys.stdout.write(vt100.restore + vt100.reset + '\n' + vt100.save + vt100.clearline)
|
||||
sys.stdout.write(f'{self.type} {self.count[self.type]}: {self.task.get_name().strip()}')
|
||||
sys.stdout.write(f"{vt100.restore}{vt100.reset}\n{vt100.save}{vt100.clearline}")
|
||||
sys.stdout.flush()
|
||||
else:
|
||||
sys.stdout.write(vt100.restore + vt100.reset + vt100.clearline)
|
||||
@@ -284,7 +284,7 @@ class CallbackModule(CallbackModule_default):
|
||||
def _display_results(self, result, status):
|
||||
# Leave the previous task on screen (as it has changes/errors)
|
||||
if self._display.verbosity == 0 and self.keep:
|
||||
sys.stdout.write(vt100.restore + vt100.reset + '\n' + vt100.save + vt100.clearline)
|
||||
sys.stdout.write(f"{vt100.restore}{vt100.reset}\n{vt100.save}{vt100.clearline}")
|
||||
else:
|
||||
sys.stdout.write(vt100.restore + vt100.reset + vt100.clearline)
|
||||
self.keep = False
|
||||
@@ -309,15 +309,15 @@ class CallbackModule(CallbackModule_default):
|
||||
if result._task.loop and 'results' in result._result:
|
||||
self._process_items(result)
|
||||
else:
|
||||
sys.stdout.write(colors[status] + status + ': ')
|
||||
sys.stdout.write(f"{colors[status] + status}: ")
|
||||
|
||||
delegated_vars = result._result.get('_ansible_delegated_vars', None)
|
||||
if delegated_vars:
|
||||
sys.stdout.write(vt100.reset + result._host.get_name() + '>' + colors[status] + delegated_vars['ansible_host'])
|
||||
sys.stdout.write(f"{vt100.reset + result._host.get_name()}>{colors[status]}{delegated_vars['ansible_host']}")
|
||||
else:
|
||||
sys.stdout.write(result._host.get_name())
|
||||
|
||||
sys.stdout.write(': ' + dump + '\n')
|
||||
sys.stdout.write(f": {dump}\n")
|
||||
sys.stdout.write(vt100.reset + vt100.save + vt100.clearline)
|
||||
sys.stdout.flush()
|
||||
|
||||
@@ -327,7 +327,7 @@ class CallbackModule(CallbackModule_default):
|
||||
def v2_playbook_on_play_start(self, play):
|
||||
# Leave the previous task on screen (as it has changes/errors)
|
||||
if self._display.verbosity == 0 and self.keep:
|
||||
sys.stdout.write(vt100.restore + vt100.reset + '\n' + vt100.save + vt100.clearline + vt100.bold)
|
||||
sys.stdout.write(f"{vt100.restore}{vt100.reset}\n{vt100.save}{vt100.clearline}{vt100.bold}")
|
||||
else:
|
||||
sys.stdout.write(vt100.restore + vt100.reset + vt100.clearline + vt100.bold)
|
||||
|
||||
@@ -341,14 +341,14 @@ class CallbackModule(CallbackModule_default):
|
||||
name = play.get_name().strip()
|
||||
if not name:
|
||||
name = 'unnamed'
|
||||
sys.stdout.write('PLAY %d: %s' % (self.count['play'], name.upper()))
|
||||
sys.stdout.write(vt100.restore + vt100.reset + '\n' + vt100.save + vt100.clearline)
|
||||
sys.stdout.write(f"PLAY {self.count['play']}: {name.upper()}")
|
||||
sys.stdout.write(f"{vt100.restore}{vt100.reset}\n{vt100.save}{vt100.clearline}")
|
||||
sys.stdout.flush()
|
||||
|
||||
def v2_playbook_on_task_start(self, task, is_conditional):
|
||||
# Leave the previous task on screen (as it has changes/errors)
|
||||
if self._display.verbosity == 0 and self.keep:
|
||||
sys.stdout.write(vt100.restore + vt100.reset + '\n' + vt100.save + vt100.clearline + vt100.underline)
|
||||
sys.stdout.write(f"{vt100.restore}{vt100.reset}\n{vt100.save}{vt100.clearline}{vt100.underline}")
|
||||
else:
|
||||
# Do not clear line, since we want to retain the previous output
|
||||
sys.stdout.write(vt100.restore + vt100.reset + vt100.underline)
|
||||
@@ -365,14 +365,14 @@ class CallbackModule(CallbackModule_default):
|
||||
self.count['task'] += 1
|
||||
|
||||
# Write the next task on screen (behind the prompt is the previous output)
|
||||
sys.stdout.write('%s %d.' % (self.type, self.count[self.type]))
|
||||
sys.stdout.write(f'{self.type} {self.count[self.type]}.')
|
||||
sys.stdout.write(vt100.reset)
|
||||
sys.stdout.flush()
|
||||
|
||||
def v2_playbook_on_handler_task_start(self, task):
|
||||
# Leave the previous task on screen (as it has changes/errors)
|
||||
if self._display.verbosity == 0 and self.keep:
|
||||
sys.stdout.write(vt100.restore + vt100.reset + '\n' + vt100.save + vt100.clearline + vt100.underline)
|
||||
sys.stdout.write(f"{vt100.restore}{vt100.reset}\n{vt100.save}{vt100.clearline}{vt100.underline}")
|
||||
else:
|
||||
sys.stdout.write(vt100.restore + vt100.reset + vt100.clearline + vt100.underline)
|
||||
|
||||
@@ -388,7 +388,7 @@ class CallbackModule(CallbackModule_default):
|
||||
self.count[self.type] += 1
|
||||
|
||||
# Write the next task on screen (behind the prompt is the previous output)
|
||||
sys.stdout.write('%s %d.' % (self.type, self.count[self.type]))
|
||||
sys.stdout.write(f'{self.type} {self.count[self.type]}.')
|
||||
sys.stdout.write(vt100.reset)
|
||||
sys.stdout.flush()
|
||||
|
||||
@@ -451,13 +451,13 @@ class CallbackModule(CallbackModule_default):
|
||||
|
||||
def v2_playbook_on_no_hosts_remaining(self):
|
||||
if self._display.verbosity == 0 and self.keep:
|
||||
sys.stdout.write(vt100.restore + vt100.reset + '\n' + vt100.save + vt100.clearline)
|
||||
sys.stdout.write(f"{vt100.restore}{vt100.reset}\n{vt100.save}{vt100.clearline}")
|
||||
else:
|
||||
sys.stdout.write(vt100.restore + vt100.reset + vt100.clearline)
|
||||
self.keep = False
|
||||
|
||||
sys.stdout.write(vt100.white + vt100.redbg + 'NO MORE HOSTS LEFT')
|
||||
sys.stdout.write(vt100.restore + vt100.reset + '\n' + vt100.save + vt100.clearline)
|
||||
sys.stdout.write(f"{vt100.white + vt100.redbg}NO MORE HOSTS LEFT")
|
||||
sys.stdout.write(f"{vt100.restore}{vt100.reset}\n{vt100.save}{vt100.clearline}")
|
||||
sys.stdout.flush()
|
||||
|
||||
def v2_playbook_on_include(self, included_file):
|
||||
@@ -465,7 +465,7 @@ class CallbackModule(CallbackModule_default):
|
||||
|
||||
def v2_playbook_on_stats(self, stats):
|
||||
if self._display.verbosity == 0 and self.keep:
|
||||
sys.stdout.write(vt100.restore + vt100.reset + '\n' + vt100.save + vt100.clearline)
|
||||
sys.stdout.write(f"{vt100.restore}{vt100.reset}\n{vt100.save}{vt100.clearline}")
|
||||
else:
|
||||
sys.stdout.write(vt100.restore + vt100.reset + vt100.clearline)
|
||||
|
||||
@@ -476,22 +476,16 @@ class CallbackModule(CallbackModule_default):
|
||||
sys.stdout.write(vt100.bold + vt100.underline)
|
||||
sys.stdout.write('SUMMARY')
|
||||
|
||||
sys.stdout.write(vt100.restore + vt100.reset + '\n' + vt100.save + vt100.clearline)
|
||||
sys.stdout.write(f"{vt100.restore}{vt100.reset}\n{vt100.save}{vt100.clearline}")
|
||||
sys.stdout.flush()
|
||||
|
||||
hosts = sorted(stats.processed.keys())
|
||||
for h in hosts:
|
||||
t = stats.summarize(h)
|
||||
self._display.display(
|
||||
u"%s : %s %s %s %s %s %s" % (
|
||||
hostcolor(h, t),
|
||||
colorize(u'ok', t['ok'], C.COLOR_OK),
|
||||
colorize(u'changed', t['changed'], C.COLOR_CHANGED),
|
||||
colorize(u'unreachable', t['unreachable'], C.COLOR_UNREACHABLE),
|
||||
colorize(u'failed', t['failures'], C.COLOR_ERROR),
|
||||
colorize(u'rescued', t['rescued'], C.COLOR_OK),
|
||||
colorize(u'ignored', t['ignored'], C.COLOR_WARN),
|
||||
),
|
||||
f"{hostcolor(h, t)} : {colorize('ok', t['ok'], C.COLOR_OK)} {colorize('changed', t['changed'], C.COLOR_CHANGED)} "
|
||||
f"{colorize('unreachable', t['unreachable'], C.COLOR_UNREACHABLE)} {colorize('failed', t['failures'], C.COLOR_ERROR)} "
|
||||
f"{colorize('rescued', t['rescued'], C.COLOR_OK)} {colorize('ignored', t['ignored'], C.COLOR_WARN)}",
|
||||
screen_only=True
|
||||
)
|
||||
|
||||
|
||||
@@ -786,12 +786,6 @@ from ansible.vars.manager import VariableManager
|
||||
from ansible.plugins.callback.default import CallbackModule as Default
|
||||
from ansible.module_utils.common.text.converters import to_text
|
||||
|
||||
try:
|
||||
from ansible.template import trust_as_template # noqa: F401, pylint: disable=unused-import
|
||||
SUPPORTS_DATA_TAGGING = True
|
||||
except ImportError:
|
||||
SUPPORTS_DATA_TAGGING = False
|
||||
|
||||
|
||||
class DummyStdout(object):
|
||||
def flush(self):
|
||||
@@ -829,9 +823,9 @@ class CallbackModule(Default):
|
||||
_callback_options = ['msg', 'msg_color']
|
||||
|
||||
for option in _callback_options:
|
||||
_option_name = '%s_%s' % (_callback_type, option)
|
||||
_option_name = f'{_callback_type}_{option}'
|
||||
_option_template = variables.get(
|
||||
self.DIY_NS + "_" + _option_name,
|
||||
f"{self.DIY_NS}_{_option_name}",
|
||||
self.get_option(_option_name)
|
||||
)
|
||||
_ret.update({option: self._template(
|
||||
@@ -845,10 +839,7 @@ class CallbackModule(Default):
|
||||
return _ret
|
||||
|
||||
def _using_diy(self, spec):
|
||||
sentinel = object()
|
||||
omit = spec['vars'].get('omit', sentinel)
|
||||
# With Data Tagging, omit is sentinel
|
||||
return (spec['msg'] is not None) and (spec['msg'] != omit or omit is sentinel)
|
||||
return (spec['msg'] is not None) and (spec['msg'] != spec['vars']['omit'])
|
||||
|
||||
def _parent_has_callback(self):
|
||||
return hasattr(super(CallbackModule, self), sys._getframe(1).f_code.co_name)
|
||||
@@ -871,7 +862,7 @@ class CallbackModule(Default):
|
||||
handler=None, result=None, stats=None, remove_attr_ref_loop=True):
|
||||
def _get_value(obj, attr=None, method=None):
|
||||
if attr:
|
||||
return getattr(obj, attr, getattr(obj, "_" + attr, None))
|
||||
return getattr(obj, attr, getattr(obj, f"_{attr}", None))
|
||||
|
||||
if method:
|
||||
_method = getattr(obj, method)
|
||||
@@ -904,7 +895,7 @@ class CallbackModule(Default):
|
||||
)
|
||||
_ret.update(_all)
|
||||
|
||||
_ret.update(_ret.get(self.DIY_NS, {self.DIY_NS: {} if SUPPORTS_DATA_TAGGING else CallbackDIYDict()}))
|
||||
_ret.update(_ret.get(self.DIY_NS, {self.DIY_NS: CallbackDIYDict()}))
|
||||
|
||||
_ret[self.DIY_NS].update({'playbook': {}})
|
||||
_playbook_attributes = ['entries', 'file_name', 'basedir']
|
||||
|
||||
@@ -118,7 +118,7 @@ class TaskData:
|
||||
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)
|
||||
host.result = f'{self.host_data[host.uuid].result}\n{host.result}'
|
||||
else:
|
||||
return
|
||||
|
||||
@@ -166,7 +166,7 @@ class ElasticSource(object):
|
||||
args = None
|
||||
|
||||
if not task.no_log and not hide_task_arguments:
|
||||
args = ', '.join(('%s=%s' % a for a in task.args.items()))
|
||||
args = ', '.join((f'{k}={v}' for k, v in task.args.items()))
|
||||
|
||||
tasks_data[uuid] = TaskData(uuid, name, path, play_name, action, args)
|
||||
|
||||
@@ -225,7 +225,7 @@ class ElasticSource(object):
|
||||
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)
|
||||
name = f'[{host_data.name}] {task_data.play}: {task_data.name}'
|
||||
|
||||
message = "success"
|
||||
status = "success"
|
||||
@@ -259,7 +259,7 @@ class ElasticSource(object):
|
||||
"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))
|
||||
exception = AnsibleRuntimeError(message=f"{task_data.action}: {name} failed with error message {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):
|
||||
@@ -288,7 +288,7 @@ class ElasticSource(object):
|
||||
message = result.get('msg', 'failed')
|
||||
exception = result.get('exception')
|
||||
stderr = result.get('stderr')
|
||||
return ('message: "{0}"\nexception: "{1}"\nstderr: "{2}"').format(message, exception, stderr)
|
||||
return f"message: \"{message}\"\nexception: \"{exception}\"\nstderr: \"{stderr}\""
|
||||
|
||||
|
||||
class CallbackModule(CallbackBase):
|
||||
|
||||
@@ -1,240 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2014, Matt Martz <matt@sivel.net>
|
||||
# Copyright (c) 2017 Ansible Project
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
author: Unknown (!UNKNOWN)
|
||||
name: hipchat
|
||||
type: notification
|
||||
requirements:
|
||||
- whitelist in configuration.
|
||||
- prettytable (python lib)
|
||||
short_description: post task events to hipchat
|
||||
description:
|
||||
- This callback plugin sends status updates to a HipChat channel during playbook execution.
|
||||
- Before 2.4 only environment variables were available for configuring this plugin.
|
||||
deprecated:
|
||||
removed_in: 10.0.0
|
||||
why: The hipchat service has been discontinued and the self-hosted variant has been End of Life since 2020.
|
||||
alternative: There is none.
|
||||
options:
|
||||
token:
|
||||
description: HipChat API token for v1 or v2 API.
|
||||
type: str
|
||||
required: true
|
||||
env:
|
||||
- name: HIPCHAT_TOKEN
|
||||
ini:
|
||||
- section: callback_hipchat
|
||||
key: token
|
||||
api_version:
|
||||
description: HipChat API version, v1 or v2.
|
||||
type: str
|
||||
choices:
|
||||
- v1
|
||||
- v2
|
||||
required: false
|
||||
default: v1
|
||||
env:
|
||||
- name: HIPCHAT_API_VERSION
|
||||
ini:
|
||||
- section: callback_hipchat
|
||||
key: api_version
|
||||
room:
|
||||
description: HipChat room to post in.
|
||||
type: str
|
||||
default: ansible
|
||||
env:
|
||||
- name: HIPCHAT_ROOM
|
||||
ini:
|
||||
- section: callback_hipchat
|
||||
key: room
|
||||
from:
|
||||
description: Name to post as
|
||||
type: str
|
||||
default: ansible
|
||||
env:
|
||||
- name: HIPCHAT_FROM
|
||||
ini:
|
||||
- section: callback_hipchat
|
||||
key: from
|
||||
notify:
|
||||
description: Add notify flag to important messages
|
||||
type: bool
|
||||
default: true
|
||||
env:
|
||||
- name: HIPCHAT_NOTIFY
|
||||
ini:
|
||||
- section: callback_hipchat
|
||||
key: notify
|
||||
|
||||
'''
|
||||
|
||||
import os
|
||||
import json
|
||||
|
||||
try:
|
||||
import prettytable
|
||||
HAS_PRETTYTABLE = True
|
||||
except ImportError:
|
||||
HAS_PRETTYTABLE = False
|
||||
|
||||
from ansible.plugins.callback import CallbackBase
|
||||
from ansible.module_utils.six.moves.urllib.parse import urlencode
|
||||
from ansible.module_utils.urls import open_url
|
||||
|
||||
|
||||
class CallbackModule(CallbackBase):
|
||||
"""This is an example ansible callback plugin that sends status
|
||||
updates to a HipChat channel during playbook execution.
|
||||
"""
|
||||
|
||||
CALLBACK_VERSION = 2.0
|
||||
CALLBACK_TYPE = 'notification'
|
||||
CALLBACK_NAME = 'community.general.hipchat'
|
||||
CALLBACK_NEEDS_WHITELIST = True
|
||||
|
||||
API_V1_URL = 'https://api.hipchat.com/v1/rooms/message'
|
||||
API_V2_URL = 'https://api.hipchat.com/v2/'
|
||||
|
||||
def __init__(self):
|
||||
|
||||
super(CallbackModule, self).__init__()
|
||||
|
||||
if not HAS_PRETTYTABLE:
|
||||
self.disabled = True
|
||||
self._display.warning('The `prettytable` python module is not installed. '
|
||||
'Disabling the HipChat callback plugin.')
|
||||
self.printed_playbook = False
|
||||
self.playbook_name = None
|
||||
self.play = 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)
|
||||
|
||||
self.token = self.get_option('token')
|
||||
self.api_version = self.get_option('api_version')
|
||||
self.from_name = self.get_option('from')
|
||||
self.allow_notify = self.get_option('notify')
|
||||
self.room = self.get_option('room')
|
||||
|
||||
if self.token is None:
|
||||
self.disabled = True
|
||||
self._display.warning('HipChat token could not be loaded. The HipChat '
|
||||
'token can be provided using the `HIPCHAT_TOKEN` '
|
||||
'environment variable.')
|
||||
|
||||
# Pick the request handler.
|
||||
if self.api_version == 'v2':
|
||||
self.send_msg = self.send_msg_v2
|
||||
else:
|
||||
self.send_msg = self.send_msg_v1
|
||||
|
||||
def send_msg_v2(self, msg, msg_format='text', color='yellow', notify=False):
|
||||
"""Method for sending a message to HipChat"""
|
||||
|
||||
headers = {'Authorization': 'Bearer %s' % self.token, 'Content-Type': 'application/json'}
|
||||
|
||||
body = {}
|
||||
body['room_id'] = self.room
|
||||
body['from'] = self.from_name[:15] # max length is 15
|
||||
body['message'] = msg
|
||||
body['message_format'] = msg_format
|
||||
body['color'] = color
|
||||
body['notify'] = self.allow_notify and notify
|
||||
|
||||
data = json.dumps(body)
|
||||
url = self.API_V2_URL + "room/{room_id}/notification".format(room_id=self.room)
|
||||
try:
|
||||
response = open_url(url, data=data, headers=headers, method='POST')
|
||||
return response.read()
|
||||
except Exception as ex:
|
||||
self._display.warning('Could not submit message to hipchat: {0}'.format(ex))
|
||||
|
||||
def send_msg_v1(self, msg, msg_format='text', color='yellow', notify=False):
|
||||
"""Method for sending a message to HipChat"""
|
||||
|
||||
params = {}
|
||||
params['room_id'] = self.room
|
||||
params['from'] = self.from_name[:15] # max length is 15
|
||||
params['message'] = msg
|
||||
params['message_format'] = msg_format
|
||||
params['color'] = color
|
||||
params['notify'] = int(self.allow_notify and notify)
|
||||
|
||||
url = ('%s?auth_token=%s' % (self.API_V1_URL, self.token))
|
||||
try:
|
||||
response = open_url(url, data=urlencode(params))
|
||||
return response.read()
|
||||
except Exception as ex:
|
||||
self._display.warning('Could not submit message to hipchat: {0}'.format(ex))
|
||||
|
||||
def v2_playbook_on_play_start(self, play):
|
||||
"""Display Playbook and play start messages"""
|
||||
|
||||
self.play = play
|
||||
name = play.name
|
||||
# This block sends information about a playbook when it starts
|
||||
# The playbook object is not immediately available at
|
||||
# playbook_on_start so we grab it via the play
|
||||
#
|
||||
# Displays info about playbook being started by a person on an
|
||||
# inventory, as well as Tags, Skip Tags and Limits
|
||||
if not self.printed_playbook:
|
||||
self.playbook_name, dummy = os.path.splitext(os.path.basename(self.play.playbook.filename))
|
||||
host_list = self.play.playbook.inventory.host_list
|
||||
inventory = os.path.basename(os.path.realpath(host_list))
|
||||
self.send_msg("%s: Playbook initiated by %s against %s" %
|
||||
(self.playbook_name,
|
||||
self.play.playbook.remote_user,
|
||||
inventory), notify=True)
|
||||
self.printed_playbook = True
|
||||
subset = self.play.playbook.inventory._subset
|
||||
skip_tags = self.play.playbook.skip_tags
|
||||
self.send_msg("%s:\nTags: %s\nSkip Tags: %s\nLimit: %s" %
|
||||
(self.playbook_name,
|
||||
', '.join(self.play.playbook.only_tags),
|
||||
', '.join(skip_tags) if skip_tags else None,
|
||||
', '.join(subset) if subset else subset))
|
||||
|
||||
# This is where we actually say we are starting a play
|
||||
self.send_msg("%s: Starting play: %s" %
|
||||
(self.playbook_name, name))
|
||||
|
||||
def playbook_on_stats(self, stats):
|
||||
"""Display info about playbook statistics"""
|
||||
hosts = sorted(stats.processed.keys())
|
||||
|
||||
t = prettytable.PrettyTable(['Host', 'Ok', 'Changed', 'Unreachable',
|
||||
'Failures'])
|
||||
|
||||
failures = False
|
||||
unreachable = False
|
||||
|
||||
for h in hosts:
|
||||
s = stats.summarize(h)
|
||||
|
||||
if s['failures'] > 0:
|
||||
failures = True
|
||||
if s['unreachable'] > 0:
|
||||
unreachable = True
|
||||
|
||||
t.add_row([h] + [s[k] for k in ['ok', 'changed', 'unreachable',
|
||||
'failures']])
|
||||
|
||||
self.send_msg("%s: Playbook complete" % self.playbook_name,
|
||||
notify=True)
|
||||
|
||||
if failures or unreachable:
|
||||
color = 'red'
|
||||
self.send_msg("%s: Failures detected" % self.playbook_name,
|
||||
color=color, notify=True)
|
||||
else:
|
||||
color = 'green'
|
||||
|
||||
self.send_msg("/code %s:\n%s" % (self.playbook_name, t), color=color)
|
||||
@@ -102,7 +102,7 @@ class CallbackModule(CallbackBase):
|
||||
"""Display Playbook and play start messages"""
|
||||
self.play = play
|
||||
name = play.name
|
||||
self.send_msg("Ansible starting play: %s" % (name))
|
||||
self.send_msg(f"Ansible starting play: {name}")
|
||||
|
||||
def playbook_on_stats(self, stats):
|
||||
name = self.play
|
||||
@@ -118,7 +118,7 @@ class CallbackModule(CallbackBase):
|
||||
|
||||
if failures or unreachable:
|
||||
out = self.debug
|
||||
self.send_msg("%s: Failures detected \n%s \nHost: %s\n Failed at:\n%s" % (name, self.task, h, out))
|
||||
self.send_msg(f"{name}: Failures detected \n{self.task} \nHost: {h}\n Failed at:\n{out}")
|
||||
else:
|
||||
out = self.debug
|
||||
self.send_msg("Great! \n Playbook %s completed:\n%s \n Last task debug:\n %s" % (name, s, out))
|
||||
self.send_msg(f"Great! \n Playbook {name} completed:\n{s} \n Last task debug:\n {out}")
|
||||
|
||||
@@ -57,7 +57,10 @@ class CallbackModule(CallbackBase):
|
||||
CALLBACK_NEEDS_WHITELIST = True
|
||||
|
||||
TIME_FORMAT = "%b %d %Y %H:%M:%S"
|
||||
MSG_FORMAT = "%(now)s - %(playbook)s - %(task_name)s - %(task_action)s - %(category)s - %(data)s\n\n"
|
||||
|
||||
@staticmethod
|
||||
def _make_msg(now, playbook, task_name, task_action, category, data):
|
||||
return f"{now} - {playbook} - {task_name} - {task_action} - {category} - {data}\n\n"
|
||||
|
||||
def __init__(self):
|
||||
|
||||
@@ -82,22 +85,12 @@ class CallbackModule(CallbackBase):
|
||||
invocation = data.pop('invocation', None)
|
||||
data = json.dumps(data, cls=AnsibleJSONEncoder)
|
||||
if invocation is not None:
|
||||
data = json.dumps(invocation) + " => %s " % data
|
||||
data = f"{json.dumps(invocation)} => {data} "
|
||||
|
||||
path = os.path.join(self.log_folder, result._host.get_name())
|
||||
now = time.strftime(self.TIME_FORMAT, time.localtime())
|
||||
|
||||
msg = to_bytes(
|
||||
self.MSG_FORMAT
|
||||
% dict(
|
||||
now=now,
|
||||
playbook=self.playbook,
|
||||
task_name=result._task.name,
|
||||
task_action=result._task.action,
|
||||
category=category,
|
||||
data=data,
|
||||
)
|
||||
)
|
||||
msg = to_bytes(self._make_msg(now, self.playbook, result._task.name, result._task.action, category, data))
|
||||
with open(path, "ab") as fd:
|
||||
fd.write(msg)
|
||||
|
||||
|
||||
@@ -84,18 +84,17 @@ class AzureLogAnalyticsSource(object):
|
||||
|
||||
def __build_signature(self, date, workspace_id, shared_key, content_length):
|
||||
# Build authorisation signature for Azure log analytics API call
|
||||
sigs = "POST\n{0}\napplication/json\nx-ms-date:{1}\n/api/logs".format(
|
||||
str(content_length), date)
|
||||
sigs = f"POST\n{content_length}\napplication/json\nx-ms-date:{date}\n/api/logs"
|
||||
utf8_sigs = sigs.encode('utf-8')
|
||||
decoded_shared_key = base64.b64decode(shared_key)
|
||||
hmac_sha256_sigs = hmac.new(
|
||||
decoded_shared_key, utf8_sigs, digestmod=hashlib.sha256).digest()
|
||||
encoded_hash = base64.b64encode(hmac_sha256_sigs).decode('utf-8')
|
||||
signature = "SharedKey {0}:{1}".format(workspace_id, encoded_hash)
|
||||
signature = f"SharedKey {workspace_id}:{encoded_hash}"
|
||||
return signature
|
||||
|
||||
def __build_workspace_url(self, workspace_id):
|
||||
return "https://{0}.ods.opinsights.azure.com/api/logs?api-version=2016-04-01".format(workspace_id)
|
||||
return f"https://{workspace_id}.ods.opinsights.azure.com/api/logs?api-version=2016-04-01"
|
||||
|
||||
def __rfc1123date(self):
|
||||
return now().strftime('%a, %d %b %Y %H:%M:%S GMT')
|
||||
|
||||
@@ -73,7 +73,7 @@ except ImportError:
|
||||
|
||||
# Getting MAC Address of system:
|
||||
def get_mac():
|
||||
mac = "%012x" % getnode()
|
||||
mac = f"{getnode():012x}"
|
||||
return ":".join(map(lambda index: mac[index:index + 2], range(int(len(mac) / 2))))
|
||||
|
||||
|
||||
@@ -161,7 +161,7 @@ class CallbackModule(CallbackBase):
|
||||
if ninvalidKeys > 0:
|
||||
for key in invalidKeys:
|
||||
del meta[key]
|
||||
meta['__errors'] = 'These keys have been sanitized: ' + ', '.join(invalidKeys)
|
||||
meta['__errors'] = f"These keys have been sanitized: {', '.join(invalidKeys)}"
|
||||
return meta
|
||||
|
||||
def sanitizeJSON(self, data):
|
||||
|
||||
@@ -133,7 +133,7 @@ class PlainTextSocketAppender(object):
|
||||
# Error message displayed when an incorrect Token has been detected
|
||||
self.INVALID_TOKEN = "\n\nIt appears the LOGENTRIES_TOKEN parameter you entered is incorrect!\n\n"
|
||||
# Unicode Line separator character \u2028
|
||||
self.LINE_SEP = u'\u2028'
|
||||
self.LINE_SEP = '\u2028'
|
||||
|
||||
self._display = display
|
||||
self._conn = None
|
||||
@@ -151,7 +151,7 @@ class PlainTextSocketAppender(object):
|
||||
self.open_connection()
|
||||
return
|
||||
except Exception as e:
|
||||
self._display.vvvv(u"Unable to connect to Logentries: %s" % to_text(e))
|
||||
self._display.vvvv(f"Unable to connect to Logentries: {e}")
|
||||
|
||||
root_delay *= 2
|
||||
if root_delay > self.MAX_DELAY:
|
||||
@@ -160,7 +160,7 @@ class PlainTextSocketAppender(object):
|
||||
wait_for = root_delay + random.uniform(0, root_delay)
|
||||
|
||||
try:
|
||||
self._display.vvvv("sleeping %s before retry" % wait_for)
|
||||
self._display.vvvv(f"sleeping {wait_for} before retry")
|
||||
time.sleep(wait_for)
|
||||
except KeyboardInterrupt:
|
||||
raise
|
||||
@@ -173,8 +173,8 @@ class PlainTextSocketAppender(object):
|
||||
# Replace newlines with Unicode line separator
|
||||
# for multi-line events
|
||||
data = to_text(data, errors='surrogate_or_strict')
|
||||
multiline = data.replace(u'\n', self.LINE_SEP)
|
||||
multiline += u"\n"
|
||||
multiline = data.replace('\n', self.LINE_SEP)
|
||||
multiline += "\n"
|
||||
# Send data, reconnect if needed
|
||||
while True:
|
||||
try:
|
||||
@@ -247,7 +247,7 @@ class CallbackModule(CallbackBase):
|
||||
self.use_tls = self.get_option('use_tls')
|
||||
self.flatten = self.get_option('flatten')
|
||||
except KeyError as e:
|
||||
self._display.warning(u"Missing option for Logentries callback plugin: %s" % to_text(e))
|
||||
self._display.warning(f"Missing option for Logentries callback plugin: {e}")
|
||||
self.disabled = True
|
||||
|
||||
try:
|
||||
@@ -266,10 +266,10 @@ class CallbackModule(CallbackBase):
|
||||
|
||||
if not self.disabled:
|
||||
if self.use_tls:
|
||||
self._display.vvvv("Connecting to %s:%s with TLS" % (self.api_url, self.api_tls_port))
|
||||
self._display.vvvv(f"Connecting to {self.api_url}:{self.api_tls_port} with TLS")
|
||||
self._appender = TLSSocketAppender(display=self._display, LE_API=self.api_url, LE_TLS_PORT=self.api_tls_port)
|
||||
else:
|
||||
self._display.vvvv("Connecting to %s:%s" % (self.api_url, self.api_port))
|
||||
self._display.vvvv(f"Connecting to {self.api_url}:{self.api_port}")
|
||||
self._appender = PlainTextSocketAppender(display=self._display, LE_API=self.api_url, LE_PORT=self.api_port)
|
||||
self._appender.reopen_connection()
|
||||
|
||||
@@ -282,7 +282,7 @@ class CallbackModule(CallbackBase):
|
||||
|
||||
def emit(self, record):
|
||||
msg = record.rstrip('\n')
|
||||
msg = "{0} {1}".format(self.token, msg)
|
||||
msg = f"{self.token} {msg}"
|
||||
self._appender.put(msg)
|
||||
self._display.vvvv("Sent event to logentries")
|
||||
|
||||
|
||||
@@ -134,14 +134,14 @@ class CallbackModule(CallbackBase):
|
||||
if self.bcc:
|
||||
bcc_addresses = email.utils.getaddresses(self.bcc)
|
||||
|
||||
content = 'Date: %s\n' % email.utils.formatdate()
|
||||
content += 'From: %s\n' % email.utils.formataddr(sender_address)
|
||||
content = f'Date: {email.utils.formatdate()}\n'
|
||||
content += f'From: {email.utils.formataddr(sender_address)}\n'
|
||||
if self.to:
|
||||
content += 'To: %s\n' % ', '.join([email.utils.formataddr(pair) for pair in to_addresses])
|
||||
content += f"To: {', '.join([email.utils.formataddr(pair) for pair in to_addresses])}\n"
|
||||
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(domain=self.get_option('message_id_domain'))
|
||||
content += 'Subject: %s\n\n' % subject.strip()
|
||||
content += f"Cc: {', '.join([email.utils.formataddr(pair) for pair in cc_addresses])}\n"
|
||||
content += f"Message-ID: {email.utils.make_msgid(domain=self.get_option('message_id_domain'))}\n"
|
||||
content += f'Subject: {subject.strip()}\n\n'
|
||||
content += body
|
||||
|
||||
addresses = to_addresses
|
||||
@@ -158,23 +158,22 @@ class CallbackModule(CallbackBase):
|
||||
smtp.quit()
|
||||
|
||||
def subject_msg(self, multiline, failtype, linenr):
|
||||
return '%s: %s' % (failtype, multiline.strip('\r\n').splitlines()[linenr])
|
||||
msg = multiline.strip('\r\n').splitlines()[linenr]
|
||||
return f'{failtype}: {msg}'
|
||||
|
||||
def indent(self, multiline, indent=8):
|
||||
return re.sub('^', ' ' * indent, multiline, flags=re.MULTILINE)
|
||||
|
||||
def body_blob(self, multiline, texttype):
|
||||
''' Turn some text output in a well-indented block for sending in a mail body '''
|
||||
intro = 'with the following %s:\n\n' % texttype
|
||||
blob = ''
|
||||
for line in multiline.strip('\r\n').splitlines():
|
||||
blob += '%s\n' % line
|
||||
return intro + self.indent(blob) + '\n'
|
||||
intro = f'with the following {texttype}:\n\n'
|
||||
blob = "\n".join(multiline.strip('\r\n').splitlines())
|
||||
return f"{intro}{self.indent(blob)}\n"
|
||||
|
||||
def mail_result(self, result, failtype):
|
||||
host = result._host.get_name()
|
||||
if not self.sender:
|
||||
self.sender = '"Ansible: %s" <root>' % host
|
||||
self.sender = f'"Ansible: {host}" <root>'
|
||||
|
||||
# Add subject
|
||||
if self.itembody:
|
||||
@@ -190,31 +189,32 @@ class CallbackModule(CallbackBase):
|
||||
elif result._result.get('exception'): # Unrelated exceptions are added to output :-/
|
||||
subject = self.subject_msg(result._result['exception'], failtype, -1)
|
||||
else:
|
||||
subject = '%s: %s' % (failtype, result._task.name or result._task.action)
|
||||
subject = f'{failtype}: {result._task.name or result._task.action}'
|
||||
|
||||
# Make playbook name visible (e.g. in Outlook/Gmail condensed view)
|
||||
body = 'Playbook: %s\n' % os.path.basename(self.playbook._file_name)
|
||||
body = f'Playbook: {os.path.basename(self.playbook._file_name)}\n'
|
||||
if result._task.name:
|
||||
body += 'Task: %s\n' % result._task.name
|
||||
body += 'Module: %s\n' % result._task.action
|
||||
body += 'Host: %s\n' % host
|
||||
body += f'Task: {result._task.name}\n'
|
||||
body += f'Module: {result._task.action}\n'
|
||||
body += f'Host: {host}\n'
|
||||
body += '\n'
|
||||
|
||||
# Add task information (as much as possible)
|
||||
body += 'The following task failed:\n\n'
|
||||
if 'invocation' in result._result:
|
||||
body += self.indent('%s: %s\n' % (result._task.action, json.dumps(result._result['invocation']['module_args'], indent=4)))
|
||||
body += self.indent(f"{result._task.action}: {json.dumps(result._result['invocation']['module_args'], indent=4)}\n")
|
||||
elif result._task.name:
|
||||
body += self.indent('%s (%s)\n' % (result._task.name, result._task.action))
|
||||
body += self.indent(f'{result._task.name} ({result._task.action})\n')
|
||||
else:
|
||||
body += self.indent('%s\n' % result._task.action)
|
||||
body += self.indent(f'{result._task.action}\n')
|
||||
body += '\n'
|
||||
|
||||
# Add item / message
|
||||
if self.itembody:
|
||||
body += self.itembody
|
||||
elif result._result.get('failed_when_result') is True:
|
||||
body += "due to the following condition:\n\n" + self.indent('failed_when:\n- ' + '\n- '.join(result._task.failed_when)) + '\n\n'
|
||||
fail_cond = self.indent('failed_when:\n- ' + '\n- '.join(result._task.failed_when))
|
||||
body += f"due to the following condition:\n\n{fail_cond}\n\n"
|
||||
elif result._result.get('msg'):
|
||||
body += self.body_blob(result._result['msg'], 'message')
|
||||
|
||||
@@ -227,13 +227,13 @@ class CallbackModule(CallbackBase):
|
||||
body += self.body_blob(result._result['exception'], 'exception')
|
||||
if result._result.get('warnings'):
|
||||
for i in range(len(result._result.get('warnings'))):
|
||||
body += self.body_blob(result._result['warnings'][i], 'exception %d' % (i + 1))
|
||||
body += self.body_blob(result._result['warnings'][i], f'exception {i + 1}')
|
||||
if result._result.get('deprecations'):
|
||||
for i in range(len(result._result.get('deprecations'))):
|
||||
body += self.body_blob(result._result['deprecations'][i], 'exception %d' % (i + 1))
|
||||
body += self.body_blob(result._result['deprecations'][i], f'exception {i + 1}')
|
||||
|
||||
body += 'and a complete dump of the error:\n\n'
|
||||
body += self.indent('%s: %s' % (failtype, json.dumps(result._result, cls=AnsibleJSONEncoder, indent=4)))
|
||||
body += self.indent(f'{failtype}: {json.dumps(result._result, cls=AnsibleJSONEncoder, indent=4)}')
|
||||
|
||||
self.mail(subject=subject, body=body)
|
||||
|
||||
@@ -256,4 +256,4 @@ class CallbackModule(CallbackBase):
|
||||
def v2_runner_item_on_failed(self, result):
|
||||
# Pass item information to task failure
|
||||
self.itemsubject = result._result['msg']
|
||||
self.itembody += self.body_blob(json.dumps(result._result, cls=AnsibleJSONEncoder, indent=4), "failed item dump '%(item)s'" % result._result)
|
||||
self.itembody += self.body_blob(json.dumps(result._result, cls=AnsibleJSONEncoder, indent=4), f"failed item dump '{result._result['item']}'")
|
||||
|
||||
@@ -132,10 +132,10 @@ class CallbackModule(CallbackBase):
|
||||
xmldata = "<?xml version='1.0'?>\n"
|
||||
xmldata += "<checkresults>\n"
|
||||
xmldata += "<checkresult type='service'>\n"
|
||||
xmldata += "<hostname>%s</hostname>\n" % self.hostname
|
||||
xmldata += "<servicename>%s</servicename>\n" % self.servicename
|
||||
xmldata += "<state>%d</state>\n" % state
|
||||
xmldata += "<output>%s</output>\n" % msg
|
||||
xmldata += f"<hostname>{self.hostname}</hostname>\n"
|
||||
xmldata += f"<servicename>{self.servicename}</servicename>\n"
|
||||
xmldata += f"<state>{state}</state>\n"
|
||||
xmldata += f"<output>{msg}</output>\n"
|
||||
xmldata += "</checkresult>\n"
|
||||
xmldata += "</checkresults>\n"
|
||||
|
||||
@@ -152,7 +152,7 @@ class CallbackModule(CallbackBase):
|
||||
validate_certs=self.validate_nrdp_certs)
|
||||
return response.read()
|
||||
except Exception as ex:
|
||||
self._display.warning("NRDP callback cannot send result {0}".format(ex))
|
||||
self._display.warning(f"NRDP callback cannot send result {ex}")
|
||||
|
||||
def v2_playbook_on_play_start(self, play):
|
||||
'''
|
||||
@@ -170,17 +170,16 @@ class CallbackModule(CallbackBase):
|
||||
critical = warning = 0
|
||||
for host in hosts:
|
||||
stat = stats.summarize(host)
|
||||
gstats += "'%s_ok'=%d '%s_changed'=%d \
|
||||
'%s_unreachable'=%d '%s_failed'=%d " % \
|
||||
(host, stat['ok'], host, stat['changed'],
|
||||
host, stat['unreachable'], host, stat['failures'])
|
||||
gstats += (
|
||||
f"'{host}_ok'={stat['ok']} '{host}_changed'={stat['changed']} '{host}_unreachable'={stat['unreachable']} '{host}_failed'={stat['failures']} "
|
||||
)
|
||||
# Critical when failed tasks or unreachable host
|
||||
critical += stat['failures']
|
||||
critical += stat['unreachable']
|
||||
# Warning when changed tasks
|
||||
warning += stat['changed']
|
||||
|
||||
msg = "%s | %s" % (name, gstats)
|
||||
msg = f"{name} | {gstats}"
|
||||
if critical:
|
||||
# Send Critical
|
||||
self._send_nrdp(self.CRITICAL, msg)
|
||||
|
||||
@@ -137,9 +137,8 @@ import getpass
|
||||
import json
|
||||
import os
|
||||
import socket
|
||||
import sys
|
||||
import time
|
||||
import uuid
|
||||
from time import time_ns
|
||||
|
||||
from collections import OrderedDict
|
||||
from os.path import basename
|
||||
@@ -165,31 +164,12 @@ try:
|
||||
from opentelemetry.sdk.trace.export.in_memory_span_exporter import (
|
||||
InMemorySpanExporter
|
||||
)
|
||||
# Support for opentelemetry-api <= 1.12
|
||||
try:
|
||||
from opentelemetry.util._time import _time_ns
|
||||
except ImportError as imp_exc:
|
||||
OTEL_LIBRARY_TIME_NS_ERROR = imp_exc
|
||||
else:
|
||||
OTEL_LIBRARY_TIME_NS_ERROR = None
|
||||
|
||||
except ImportError as imp_exc:
|
||||
OTEL_LIBRARY_IMPORT_ERROR = imp_exc
|
||||
OTEL_LIBRARY_TIME_NS_ERROR = imp_exc
|
||||
else:
|
||||
OTEL_LIBRARY_IMPORT_ERROR = None
|
||||
|
||||
|
||||
if sys.version_info >= (3, 7):
|
||||
time_ns = time.time_ns
|
||||
elif not OTEL_LIBRARY_TIME_NS_ERROR:
|
||||
time_ns = _time_ns
|
||||
else:
|
||||
def time_ns():
|
||||
# Support versions older than 3.7 with opentelemetry-api > 1.12
|
||||
return int(time.time() * 1e9)
|
||||
|
||||
|
||||
class TaskData:
|
||||
"""
|
||||
Data about an individual task.
|
||||
@@ -210,7 +190,7 @@ class TaskData:
|
||||
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)
|
||||
host.result = f'{self.host_data[host.uuid].result}\n{host.result}'
|
||||
else:
|
||||
return
|
||||
|
||||
@@ -348,7 +328,7 @@ class OpenTelemetrySource(object):
|
||||
def update_span_data(self, task_data, host_data, span, disable_logs, disable_attributes_in_logs):
|
||||
""" update the span with the given TaskData and HostData """
|
||||
|
||||
name = '[%s] %s: %s' % (host_data.name, task_data.play, task_data.name)
|
||||
name = f'[{host_data.name}] {task_data.play}: {task_data.name}'
|
||||
|
||||
message = 'success'
|
||||
res = {}
|
||||
@@ -471,7 +451,7 @@ class OpenTelemetrySource(object):
|
||||
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))
|
||||
return f"{action}({result.get('item', 'none')}) - {OpenTelemetrySource.get_error_message(result)}"
|
||||
|
||||
@staticmethod
|
||||
def _last_line(text):
|
||||
@@ -483,14 +463,14 @@ class OpenTelemetrySource(object):
|
||||
message = result.get('msg', 'failed')
|
||||
exception = result.get('exception')
|
||||
stderr = result.get('stderr')
|
||||
return ('message: "{0}"\nexception: "{1}"\nstderr: "{2}"').format(message, exception, stderr)
|
||||
return f"message: \"{message}\"\nexception: \"{exception}\"\nstderr: \"{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)
|
||||
message = f"{action}({result.get('item', 'none')}) - {OpenTelemetrySource.enrich_error_message(result)}\n{message}"
|
||||
return message
|
||||
|
||||
|
||||
@@ -536,8 +516,9 @@ class CallbackModule(CallbackBase):
|
||||
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._display.warning(
|
||||
f"The `enable_from_environment` option has been set and {environment_variable} is not enabled. Disabling the `opentelemetry` callback plugin."
|
||||
)
|
||||
|
||||
self.hide_task_arguments = self.get_option('hide_task_arguments')
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ class CallbackModule(CallbackBase):
|
||||
self.synthesizer = get_bin_path('say')
|
||||
if platform.system() != 'Darwin':
|
||||
# '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())
|
||||
self._display.warning(f"'say' executable found but system is '{platform.system()}': ignoring voice parameter")
|
||||
else:
|
||||
self.FAILED_VOICE = 'Zarvox'
|
||||
self.REGULAR_VOICE = 'Trinoids'
|
||||
@@ -69,7 +69,7 @@ class CallbackModule(CallbackBase):
|
||||
# ansible will not call any callback if disabled is set to True
|
||||
if not self.synthesizer:
|
||||
self.disabled = True
|
||||
self._display.warning("Unable to find either 'say' or 'espeak' executable, plugin %s disabled" % os.path.basename(__file__))
|
||||
self._display.warning(f"Unable to find either 'say' or 'espeak' executable, plugin {os.path.basename(__file__)} disabled")
|
||||
|
||||
def say(self, msg, voice):
|
||||
cmd = [self.synthesizer, msg]
|
||||
@@ -78,7 +78,7 @@ class CallbackModule(CallbackBase):
|
||||
subprocess.call(cmd)
|
||||
|
||||
def runner_on_failed(self, host, res, ignore_errors=False):
|
||||
self.say("Failure on host %s" % host, self.FAILED_VOICE)
|
||||
self.say(f"Failure on host {host}", self.FAILED_VOICE)
|
||||
|
||||
def runner_on_ok(self, host, res):
|
||||
self.say("pew", self.LASER_VOICE)
|
||||
@@ -87,13 +87,13 @@ class CallbackModule(CallbackBase):
|
||||
self.say("pew", self.LASER_VOICE)
|
||||
|
||||
def runner_on_unreachable(self, host, res):
|
||||
self.say("Failure on host %s" % host, self.FAILED_VOICE)
|
||||
self.say(f"Failure on host {host}", self.FAILED_VOICE)
|
||||
|
||||
def runner_on_async_ok(self, host, res, jid):
|
||||
self.say("pew", self.LASER_VOICE)
|
||||
|
||||
def runner_on_async_failed(self, host, res, jid):
|
||||
self.say("Failure on host %s" % host, self.FAILED_VOICE)
|
||||
self.say(f"Failure on host {host}", self.FAILED_VOICE)
|
||||
|
||||
def playbook_on_start(self):
|
||||
self.say("Running Playbook", self.REGULAR_VOICE)
|
||||
@@ -103,15 +103,15 @@ class CallbackModule(CallbackBase):
|
||||
|
||||
def playbook_on_task_start(self, name, is_conditional):
|
||||
if not is_conditional:
|
||||
self.say("Starting task: %s" % name, self.REGULAR_VOICE)
|
||||
self.say(f"Starting task: {name}", self.REGULAR_VOICE)
|
||||
else:
|
||||
self.say("Notifying task: %s" % name, self.REGULAR_VOICE)
|
||||
self.say(f"Notifying task: {name}", self.REGULAR_VOICE)
|
||||
|
||||
def playbook_on_setup(self):
|
||||
self.say("Gathering facts", self.REGULAR_VOICE)
|
||||
|
||||
def playbook_on_play_start(self, name):
|
||||
self.say("Starting play: %s" % name, self.HAPPY_VOICE)
|
||||
self.say(f"Starting play: {name}", self.HAPPY_VOICE)
|
||||
|
||||
def playbook_on_stats(self, stats):
|
||||
self.say("Play complete", self.HAPPY_VOICE)
|
||||
|
||||
@@ -48,13 +48,13 @@ from ansible.module_utils.common.text.converters import to_text
|
||||
DONT_COLORIZE = False
|
||||
COLORS = {
|
||||
'normal': '\033[0m',
|
||||
'ok': '\033[{0}m'.format(C.COLOR_CODES[C.COLOR_OK]),
|
||||
'ok': f'\x1b[{C.COLOR_CODES[C.COLOR_OK]}m',
|
||||
'bold': '\033[1m',
|
||||
'not_so_bold': '\033[1m\033[34m',
|
||||
'changed': '\033[{0}m'.format(C.COLOR_CODES[C.COLOR_CHANGED]),
|
||||
'failed': '\033[{0}m'.format(C.COLOR_CODES[C.COLOR_ERROR]),
|
||||
'changed': f'\x1b[{C.COLOR_CODES[C.COLOR_CHANGED]}m',
|
||||
'failed': f'\x1b[{C.COLOR_CODES[C.COLOR_ERROR]}m',
|
||||
'endc': '\033[0m',
|
||||
'skipped': '\033[{0}m'.format(C.COLOR_CODES[C.COLOR_SKIP]),
|
||||
'skipped': f'\x1b[{C.COLOR_CODES[C.COLOR_SKIP]}m',
|
||||
}
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ def colorize(msg, color):
|
||||
if DONT_COLORIZE:
|
||||
return msg
|
||||
else:
|
||||
return '{0}{1}{2}'.format(COLORS[color], msg, COLORS['endc'])
|
||||
return f"{COLORS[color]}{msg}{COLORS['endc']}"
|
||||
|
||||
|
||||
class CallbackModule(CallbackBase):
|
||||
@@ -106,15 +106,15 @@ class CallbackModule(CallbackBase):
|
||||
line_length = 120
|
||||
if self.last_skipped:
|
||||
print()
|
||||
line = "# {0} ".format(task_name)
|
||||
msg = colorize("{0}{1}".format(line, '*' * (line_length - len(line))), 'bold')
|
||||
line = f"# {task_name} "
|
||||
msg = colorize(f"{line}{'*' * (line_length - len(line))}", 'bold')
|
||||
print(msg)
|
||||
|
||||
def _indent_text(self, text, indent_level):
|
||||
lines = text.splitlines()
|
||||
result_lines = []
|
||||
for l in lines:
|
||||
result_lines.append("{0}{1}".format(' ' * indent_level, l))
|
||||
result_lines.append(f"{' ' * indent_level}{l}")
|
||||
return '\n'.join(result_lines)
|
||||
|
||||
def _print_diff(self, diff, indent_level):
|
||||
@@ -147,19 +147,19 @@ class CallbackModule(CallbackBase):
|
||||
change_string = colorize('FAILED!!!', color)
|
||||
else:
|
||||
color = 'changed' if changed else 'ok'
|
||||
change_string = colorize("changed={0}".format(changed), color)
|
||||
change_string = colorize(f"changed={changed}", color)
|
||||
|
||||
msg = colorize(msg, color)
|
||||
|
||||
line_length = 120
|
||||
spaces = ' ' * (40 - len(name) - indent_level)
|
||||
line = "{0} * {1}{2}- {3}".format(' ' * indent_level, name, spaces, change_string)
|
||||
line = f"{' ' * indent_level} * {name}{spaces}- {change_string}"
|
||||
|
||||
if len(msg) < 50:
|
||||
line += ' -- {0}'.format(msg)
|
||||
print("{0} {1}---------".format(line, '-' * (line_length - len(line))))
|
||||
line += f' -- {msg}'
|
||||
print(f"{line} {'-' * (line_length - len(line))}---------")
|
||||
else:
|
||||
print("{0} {1}".format(line, '-' * (line_length - len(line))))
|
||||
print(f"{line} {'-' * (line_length - len(line))}")
|
||||
print(self._indent_text(msg, indent_level + 4))
|
||||
|
||||
if diff:
|
||||
@@ -239,8 +239,10 @@ class CallbackModule(CallbackBase):
|
||||
else:
|
||||
color = 'ok'
|
||||
|
||||
msg = '{0} : ok={1}\tchanged={2}\tfailed={3}\tunreachable={4}\trescued={5}\tignored={6}'.format(
|
||||
host, s['ok'], s['changed'], s['failures'], s['unreachable'], s['rescued'], s['ignored'])
|
||||
msg = (
|
||||
f"{host} : ok={s['ok']}\tchanged={s['changed']}\tfailed={s['failures']}\tunreachable="
|
||||
f"{s['unreachable']}\trescued={s['rescued']}\tignored={s['ignored']}"
|
||||
)
|
||||
print(colorize(msg, color))
|
||||
|
||||
def v2_runner_on_skipped(self, result, **kwargs):
|
||||
@@ -252,17 +254,15 @@ class CallbackModule(CallbackBase):
|
||||
line_length = 120
|
||||
spaces = ' ' * (31 - len(result._host.name) - 4)
|
||||
|
||||
line = " * {0}{1}- {2}".format(colorize(result._host.name, 'not_so_bold'),
|
||||
spaces,
|
||||
colorize("skipped", 'skipped'),)
|
||||
line = f" * {colorize(result._host.name, 'not_so_bold')}{spaces}- {colorize('skipped', 'skipped')}"
|
||||
|
||||
reason = result._result.get('skipped_reason', '') or \
|
||||
result._result.get('skip_reason', '')
|
||||
if len(reason) < 50:
|
||||
line += ' -- {0}'.format(reason)
|
||||
print("{0} {1}---------".format(line, '-' * (line_length - len(line))))
|
||||
line += f' -- {reason}'
|
||||
print(f"{line} {'-' * (line_length - len(line))}---------")
|
||||
else:
|
||||
print("{0} {1}".format(line, '-' * (line_length - len(line))))
|
||||
print(f"{line} {'-' * (line_length - len(line))}")
|
||||
print(self._indent_text(reason, 8))
|
||||
print(reason)
|
||||
|
||||
|
||||
@@ -62,7 +62,6 @@ import os
|
||||
import uuid
|
||||
|
||||
from ansible import context
|
||||
from ansible.module_utils.common.text.converters import to_text
|
||||
from ansible.module_utils.urls import open_url
|
||||
from ansible.plugins.callback import CallbackBase
|
||||
|
||||
@@ -138,14 +137,13 @@ class CallbackModule(CallbackBase):
|
||||
headers=headers)
|
||||
return response.read()
|
||||
except Exception as e:
|
||||
self._display.warning(u'Could not submit message to Slack: %s' %
|
||||
to_text(e))
|
||||
self._display.warning(f'Could not submit message to Slack: {e}')
|
||||
|
||||
def v2_playbook_on_start(self, playbook):
|
||||
self.playbook_name = os.path.basename(playbook._file_name)
|
||||
|
||||
title = [
|
||||
'*Playbook initiated* (_%s_)' % self.guid
|
||||
f'*Playbook initiated* (_{self.guid}_)'
|
||||
]
|
||||
|
||||
invocation_items = []
|
||||
@@ -156,23 +154,23 @@ class CallbackModule(CallbackBase):
|
||||
subset = context.CLIARGS['subset']
|
||||
inventory = [os.path.abspath(i) for i in context.CLIARGS['inventory']]
|
||||
|
||||
invocation_items.append('Inventory: %s' % ', '.join(inventory))
|
||||
invocation_items.append(f"Inventory: {', '.join(inventory)}")
|
||||
if tags and tags != ['all']:
|
||||
invocation_items.append('Tags: %s' % ', '.join(tags))
|
||||
invocation_items.append(f"Tags: {', '.join(tags)}")
|
||||
if skip_tags:
|
||||
invocation_items.append('Skip Tags: %s' % ', '.join(skip_tags))
|
||||
invocation_items.append(f"Skip Tags: {', '.join(skip_tags)}")
|
||||
if subset:
|
||||
invocation_items.append('Limit: %s' % subset)
|
||||
invocation_items.append(f'Limit: {subset}')
|
||||
if extra_vars:
|
||||
invocation_items.append('Extra Vars: %s' %
|
||||
' '.join(extra_vars))
|
||||
invocation_items.append(f"Extra Vars: {' '.join(extra_vars)}")
|
||||
|
||||
title.append('by *%s*' % context.CLIARGS['remote_user'])
|
||||
title.append(f"by *{context.CLIARGS['remote_user']}*")
|
||||
|
||||
title.append('\n\n*%s*' % self.playbook_name)
|
||||
title.append(f'\n\n*{self.playbook_name}*')
|
||||
msg_items = [' '.join(title)]
|
||||
if invocation_items:
|
||||
msg_items.append('```\n%s\n```' % '\n'.join(invocation_items))
|
||||
_inv_item = '\n'.join(invocation_items)
|
||||
msg_items.append(f'```\n{_inv_item}\n```')
|
||||
|
||||
msg = '\n'.join(msg_items)
|
||||
|
||||
@@ -192,8 +190,8 @@ class CallbackModule(CallbackBase):
|
||||
def v2_playbook_on_play_start(self, play):
|
||||
"""Display Play start messages"""
|
||||
|
||||
name = play.name or 'Play name not specified (%s)' % play._uuid
|
||||
msg = '*Starting play* (_%s_)\n\n*%s*' % (self.guid, name)
|
||||
name = play.name or f'Play name not specified ({play._uuid})'
|
||||
msg = f'*Starting play* (_{self.guid}_)\n\n*{name}*'
|
||||
attachments = [
|
||||
{
|
||||
'fallback': msg,
|
||||
@@ -228,7 +226,7 @@ class CallbackModule(CallbackBase):
|
||||
|
||||
attachments = []
|
||||
msg_items = [
|
||||
'*Playbook Complete* (_%s_)' % self.guid
|
||||
f'*Playbook Complete* (_{self.guid}_)'
|
||||
]
|
||||
if failures or unreachable:
|
||||
color = 'danger'
|
||||
@@ -237,7 +235,7 @@ class CallbackModule(CallbackBase):
|
||||
color = 'good'
|
||||
msg_items.append('\n*Success!*')
|
||||
|
||||
msg_items.append('```\n%s\n```' % t)
|
||||
msg_items.append(f'```\n{t}\n```')
|
||||
|
||||
msg = '\n'.join(msg_items)
|
||||
|
||||
|
||||
@@ -153,15 +153,14 @@ class SplunkHTTPCollectorSource(object):
|
||||
data['ansible_result'] = result._result
|
||||
|
||||
# This wraps the json payload in and outer json event needed by Splunk
|
||||
jsondata = json.dumps(data, cls=AnsibleJSONEncoder, sort_keys=True)
|
||||
jsondata = '{"event":' + jsondata + "}"
|
||||
jsondata = json.dumps({"event": data}, cls=AnsibleJSONEncoder, sort_keys=True)
|
||||
|
||||
open_url(
|
||||
url,
|
||||
jsondata,
|
||||
headers={
|
||||
'Content-type': 'application/json',
|
||||
'Authorization': 'Splunk ' + authtoken
|
||||
'Authorization': f"Splunk {authtoken}"
|
||||
},
|
||||
method='POST',
|
||||
validate_certs=validate_certs
|
||||
|
||||
@@ -84,7 +84,7 @@ def banner(self, msg, color=None, cows=True):
|
||||
msg = to_text(msg)
|
||||
if self.b_cowsay and cows:
|
||||
try:
|
||||
self.banner_cowsay("%s @ %s" % (msg, timestamp))
|
||||
self.banner_cowsay(f"{msg} @ {timestamp}")
|
||||
return
|
||||
except OSError:
|
||||
self.warning("somebody cleverly deleted cowsay or something during the PB run. heh.")
|
||||
@@ -97,7 +97,7 @@ def banner(self, msg, color=None, cows=True):
|
||||
if star_len <= 3:
|
||||
star_len = 3
|
||||
stars = "*" * star_len
|
||||
self.display("\n%s %s %s" % (msg, stars, timestamp), color=color)
|
||||
self.display(f"\n{msg} {stars} {timestamp}", color=color)
|
||||
|
||||
|
||||
class CallbackModule(Default):
|
||||
|
||||
@@ -67,24 +67,24 @@ class CallbackModule(CallbackModule_default):
|
||||
|
||||
def _process_result_output(self, result, msg):
|
||||
task_host = result._host.get_name()
|
||||
task_result = "%s %s" % (task_host, msg)
|
||||
task_result = f"{task_host} {msg}"
|
||||
|
||||
if self._run_is_verbose(result):
|
||||
task_result = "%s %s: %s" % (task_host, msg, self._dump_results(result._result, indent=4))
|
||||
task_result = f"{task_host} {msg}: {self._dump_results(result._result, indent=4)}"
|
||||
return task_result
|
||||
|
||||
if self.delegated_vars:
|
||||
task_delegate_host = self.delegated_vars['ansible_host']
|
||||
task_result = "%s -> %s %s" % (task_host, task_delegate_host, msg)
|
||||
task_result = f"{task_host} -> {task_delegate_host} {msg}"
|
||||
|
||||
if result._result.get('msg') and result._result.get('msg') != "All items completed":
|
||||
task_result += " | msg: " + to_text(result._result.get('msg'))
|
||||
task_result += f" | msg: {to_text(result._result.get('msg'))}"
|
||||
|
||||
if result._result.get('stdout'):
|
||||
task_result += " | stdout: " + result._result.get('stdout')
|
||||
task_result += f" | stdout: {result._result.get('stdout')}"
|
||||
|
||||
if result._result.get('stderr'):
|
||||
task_result += " | stderr: " + result._result.get('stderr')
|
||||
task_result += f" | stderr: {result._result.get('stderr')}"
|
||||
|
||||
return task_result
|
||||
|
||||
@@ -92,30 +92,30 @@ class CallbackModule(CallbackModule_default):
|
||||
self._get_task_display_name(task)
|
||||
if self.task_display_name is not None:
|
||||
if task.check_mode and self.get_option('check_mode_markers'):
|
||||
self._display.display("%s (check mode)..." % self.task_display_name)
|
||||
self._display.display(f"{self.task_display_name} (check mode)...")
|
||||
else:
|
||||
self._display.display("%s..." % self.task_display_name)
|
||||
self._display.display(f"{self.task_display_name}...")
|
||||
|
||||
def v2_playbook_on_handler_task_start(self, task):
|
||||
self._get_task_display_name(task)
|
||||
if self.task_display_name is not None:
|
||||
if task.check_mode and self.get_option('check_mode_markers'):
|
||||
self._display.display("%s (via handler in check mode)... " % self.task_display_name)
|
||||
self._display.display(f"{self.task_display_name} (via handler in check mode)... ")
|
||||
else:
|
||||
self._display.display("%s (via handler)... " % self.task_display_name)
|
||||
self._display.display(f"{self.task_display_name} (via handler)... ")
|
||||
|
||||
def v2_playbook_on_play_start(self, play):
|
||||
name = play.get_name().strip()
|
||||
if play.check_mode and self.get_option('check_mode_markers'):
|
||||
if name and play.hosts:
|
||||
msg = u"\n- %s (in check mode) on hosts: %s -" % (name, ",".join(play.hosts))
|
||||
msg = f"\n- {name} (in check mode) on hosts: {','.join(play.hosts)} -"
|
||||
else:
|
||||
msg = u"- check mode -"
|
||||
msg = "- check mode -"
|
||||
else:
|
||||
if name and play.hosts:
|
||||
msg = u"\n- %s on hosts: %s -" % (name, ",".join(play.hosts))
|
||||
msg = f"\n- {name} on hosts: {','.join(play.hosts)} -"
|
||||
else:
|
||||
msg = u"---"
|
||||
msg = "---"
|
||||
|
||||
self._display.display(msg)
|
||||
|
||||
@@ -126,7 +126,7 @@ class CallbackModule(CallbackModule_default):
|
||||
msg = "skipped"
|
||||
|
||||
task_result = self._process_result_output(result, msg)
|
||||
self._display.display(" " + task_result, display_color)
|
||||
self._display.display(f" {task_result}", display_color)
|
||||
else:
|
||||
return
|
||||
|
||||
@@ -136,10 +136,10 @@ class CallbackModule(CallbackModule_default):
|
||||
msg = "failed"
|
||||
item_value = self._get_item_label(result._result)
|
||||
if item_value:
|
||||
msg += " | item: %s" % (item_value,)
|
||||
msg += f" | item: {item_value}"
|
||||
|
||||
task_result = self._process_result_output(result, msg)
|
||||
self._display.display(" " + task_result, display_color, stderr=self.get_option('display_failed_stderr'))
|
||||
self._display.display(f" {task_result}", display_color, stderr=self.get_option('display_failed_stderr'))
|
||||
|
||||
def v2_runner_on_ok(self, result, msg="ok", display_color=C.COLOR_OK):
|
||||
self._preprocess_result(result)
|
||||
@@ -149,13 +149,13 @@ class CallbackModule(CallbackModule_default):
|
||||
msg = "done"
|
||||
item_value = self._get_item_label(result._result)
|
||||
if item_value:
|
||||
msg += " | item: %s" % (item_value,)
|
||||
msg += f" | item: {item_value}"
|
||||
display_color = C.COLOR_CHANGED
|
||||
task_result = self._process_result_output(result, msg)
|
||||
self._display.display(" " + task_result, display_color)
|
||||
self._display.display(f" {task_result}", display_color)
|
||||
elif self.get_option('display_ok_hosts'):
|
||||
task_result = self._process_result_output(result, msg)
|
||||
self._display.display(" " + task_result, display_color)
|
||||
self._display.display(f" {task_result}", display_color)
|
||||
|
||||
def v2_runner_item_on_skipped(self, result):
|
||||
self.v2_runner_on_skipped(result)
|
||||
@@ -173,7 +173,7 @@ class CallbackModule(CallbackModule_default):
|
||||
display_color = C.COLOR_UNREACHABLE
|
||||
task_result = self._process_result_output(result, msg)
|
||||
|
||||
self._display.display(" " + task_result, display_color, stderr=self.get_option('display_failed_stderr'))
|
||||
self._display.display(f" {task_result}", display_color, stderr=self.get_option('display_failed_stderr'))
|
||||
|
||||
def v2_on_file_diff(self, result):
|
||||
if result._task.loop and 'results' in result._result:
|
||||
@@ -195,25 +195,17 @@ class CallbackModule(CallbackModule_default):
|
||||
# TODO how else can we display these?
|
||||
t = stats.summarize(h)
|
||||
|
||||
self._display.display(u" %s : %s %s %s %s %s %s" % (
|
||||
hostcolor(h, t),
|
||||
colorize(u'ok', t['ok'], C.COLOR_OK),
|
||||
colorize(u'changed', t['changed'], C.COLOR_CHANGED),
|
||||
colorize(u'unreachable', t['unreachable'], C.COLOR_UNREACHABLE),
|
||||
colorize(u'failed', t['failures'], C.COLOR_ERROR),
|
||||
colorize(u'rescued', t['rescued'], C.COLOR_OK),
|
||||
colorize(u'ignored', t['ignored'], C.COLOR_WARN)),
|
||||
self._display.display(
|
||||
f" {hostcolor(h, t)} : {colorize('ok', t['ok'], C.COLOR_OK)} {colorize('changed', t['changed'], C.COLOR_CHANGED)} "
|
||||
f"{colorize('unreachable', t['unreachable'], C.COLOR_UNREACHABLE)} {colorize('failed', t['failures'], C.COLOR_ERROR)} "
|
||||
f"{colorize('rescued', t['rescued'], C.COLOR_OK)} {colorize('ignored', t['ignored'], C.COLOR_WARN)}",
|
||||
screen_only=True
|
||||
)
|
||||
|
||||
self._display.display(u" %s : %s %s %s %s %s %s" % (
|
||||
hostcolor(h, t, False),
|
||||
colorize(u'ok', t['ok'], None),
|
||||
colorize(u'changed', t['changed'], None),
|
||||
colorize(u'unreachable', t['unreachable'], None),
|
||||
colorize(u'failed', t['failures'], None),
|
||||
colorize(u'rescued', t['rescued'], None),
|
||||
colorize(u'ignored', t['ignored'], None)),
|
||||
self._display.display(
|
||||
f" {hostcolor(h, t, False)} : {colorize('ok', t['ok'], None)} {colorize('changed', t['changed'], None)} "
|
||||
f"{colorize('unreachable', t['unreachable'], None)} {colorize('failed', t['failures'], None)} {colorize('rescued', t['rescued'], None)} "
|
||||
f"{colorize('ignored', t['ignored'], None)}",
|
||||
log_only=True
|
||||
)
|
||||
if stats.custom and self.get_option('show_custom_stats'):
|
||||
@@ -223,12 +215,14 @@ class CallbackModule(CallbackModule_default):
|
||||
for k in sorted(stats.custom.keys()):
|
||||
if k == '_run':
|
||||
continue
|
||||
self._display.display('\t%s: %s' % (k, self._dump_results(stats.custom[k], indent=1).replace('\n', '')))
|
||||
stat_val = self._dump_results(stats.custom[k], indent=1).replace('\n', '')
|
||||
self._display.display(f'\t{k}: {stat_val}')
|
||||
|
||||
# print per run custom stats
|
||||
if '_run' in stats.custom:
|
||||
self._display.display("", screen_only=True)
|
||||
self._display.display('\tRUN: %s' % self._dump_results(stats.custom['_run'], indent=1).replace('\n', ''))
|
||||
stat_val_run = self._dump_results(stats.custom['_run'], indent=1).replace('\n', '')
|
||||
self._display.display(f'\tRUN: {stat_val_run}')
|
||||
self._display.display("", screen_only=True)
|
||||
|
||||
def v2_playbook_on_no_hosts_matched(self):
|
||||
@@ -239,23 +233,23 @@ class CallbackModule(CallbackModule_default):
|
||||
|
||||
def v2_playbook_on_start(self, playbook):
|
||||
if context.CLIARGS['check'] and self.get_option('check_mode_markers'):
|
||||
self._display.display("Executing playbook %s in check mode" % basename(playbook._file_name))
|
||||
self._display.display(f"Executing playbook {basename(playbook._file_name)} in check mode")
|
||||
else:
|
||||
self._display.display("Executing playbook %s" % basename(playbook._file_name))
|
||||
self._display.display(f"Executing playbook {basename(playbook._file_name)}")
|
||||
|
||||
# show CLI arguments
|
||||
if self._display.verbosity > 3:
|
||||
if context.CLIARGS.get('args'):
|
||||
self._display.display('Positional arguments: %s' % ' '.join(context.CLIARGS['args']),
|
||||
self._display.display(f"Positional arguments: {' '.join(context.CLIARGS['args'])}",
|
||||
color=C.COLOR_VERBOSE, screen_only=True)
|
||||
|
||||
for argument in (a for a in context.CLIARGS if a != 'args'):
|
||||
val = context.CLIARGS[argument]
|
||||
if val:
|
||||
self._display.vvvv('%s: %s' % (argument, val))
|
||||
self._display.vvvv(f'{argument}: {val}')
|
||||
|
||||
def v2_runner_retry(self, result):
|
||||
msg = " Retrying... (%d of %d)" % (result._result['attempts'], result._result['retries'])
|
||||
msg = f" Retrying... ({result._result['attempts']} of {result._result['retries']})"
|
||||
if self._run_is_verbose(result):
|
||||
msg += "Result was: %s" % self._dump_results(result._result)
|
||||
msg += f"Result was: {self._dump_results(result._result)}"
|
||||
self._display.display(msg, color=C.COLOR_DEBUG)
|
||||
|
||||
@@ -12,6 +12,10 @@ author: Unknown (!UNKNOWN)
|
||||
name: yaml
|
||||
type: stdout
|
||||
short_description: YAML-ized Ansible screen output
|
||||
deprecated:
|
||||
removed_in: 13.0.0
|
||||
why: Starting in ansible-core 2.13, the P(ansible.builtin.default#callback) callback has support for printing output in YAML format.
|
||||
alternative: Use O(ansible.builtin.default#callback:result_format=yaml).
|
||||
description:
|
||||
- Ansible output that can be quite a bit easier to read than the default JSON formatting.
|
||||
extends_documentation_fragment:
|
||||
@@ -43,83 +47,35 @@ from ansible.plugins.callback.default import CallbackModule as Default
|
||||
# from http://stackoverflow.com/a/15423007/115478
|
||||
def should_use_block(value):
|
||||
"""Returns true if string should be in block format"""
|
||||
for c in u"\u000a\u000d\u001c\u001d\u001e\u0085\u2028\u2029":
|
||||
for c in "\u000a\u000d\u001c\u001d\u001e\u0085\u2028\u2029":
|
||||
if c in value:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
try:
|
||||
class MyDumper(AnsibleDumper): # pylint: disable=inherit-non-class
|
||||
def represent_scalar(self, tag, value, style=None):
|
||||
"""Uses block style for multi-line strings"""
|
||||
if style is None:
|
||||
if should_use_block(value):
|
||||
style = '|'
|
||||
# we care more about readable than accuracy, so...
|
||||
# ...no trailing space
|
||||
value = value.rstrip()
|
||||
# ...and non-printable characters
|
||||
value = ''.join(x for x in value if x in string.printable or ord(x) >= 0xA0)
|
||||
# ...tabs prevent blocks from expanding
|
||||
value = value.expandtabs()
|
||||
# ...and odd bits of whitespace
|
||||
value = re.sub(r'[\x0b\x0c\r]', '', value)
|
||||
# ...as does trailing space
|
||||
value = re.sub(r' +\n', '\n', value)
|
||||
else:
|
||||
style = self.default_style
|
||||
node = yaml.representer.ScalarNode(tag, value, style=style)
|
||||
if self.alias_key is not None:
|
||||
self.represented_objects[self.alias_key] = node
|
||||
return node
|
||||
except: # noqa: E722, pylint: disable=bare-except
|
||||
# This happens with Data Tagging, see https://github.com/ansible/ansible/issues/84781
|
||||
# Until there is a better solution we'll resort to using ansible-core internals.
|
||||
from ansible._internal._yaml import _dumper
|
||||
import typing as t
|
||||
|
||||
class MyDumper(_dumper._BaseDumper):
|
||||
# This code is mostly taken from ansible._internal._yaml._dumper
|
||||
@classmethod
|
||||
def _register_representers(cls) -> None:
|
||||
cls.add_multi_representer(_dumper.AnsibleTaggedObject, cls.represent_ansible_tagged_object)
|
||||
cls.add_multi_representer(_dumper.Tripwire, cls.represent_tripwire)
|
||||
cls.add_multi_representer(_dumper.c.Mapping, _dumper.SafeRepresenter.represent_dict)
|
||||
cls.add_multi_representer(_dumper.c.Sequence, _dumper.SafeRepresenter.represent_list)
|
||||
|
||||
def represent_ansible_tagged_object(self, data):
|
||||
if ciphertext := _dumper.VaultHelper.get_ciphertext(data, with_tags=False):
|
||||
return self.represent_scalar('!vault', ciphertext, style='|')
|
||||
|
||||
return self.represent_data(_dumper.AnsibleTagHelper.as_native_type(data)) # automatically decrypts encrypted strings
|
||||
|
||||
def represent_tripwire(self, data: _dumper.Tripwire) -> t.NoReturn:
|
||||
data.trip()
|
||||
|
||||
# The following function is the same as in the try/except
|
||||
def represent_scalar(self, tag, value, style=None):
|
||||
"""Uses block style for multi-line strings"""
|
||||
if style is None:
|
||||
if should_use_block(value):
|
||||
style = '|'
|
||||
# we care more about readable than accuracy, so...
|
||||
# ...no trailing space
|
||||
value = value.rstrip()
|
||||
# ...and non-printable characters
|
||||
value = ''.join(x for x in value if x in string.printable or ord(x) >= 0xA0)
|
||||
# ...tabs prevent blocks from expanding
|
||||
value = value.expandtabs()
|
||||
# ...and odd bits of whitespace
|
||||
value = re.sub(r'[\x0b\x0c\r]', '', value)
|
||||
# ...as does trailing space
|
||||
value = re.sub(r' +\n', '\n', value)
|
||||
else:
|
||||
style = self.default_style
|
||||
node = yaml.representer.ScalarNode(tag, value, style=style)
|
||||
if self.alias_key is not None:
|
||||
self.represented_objects[self.alias_key] = node
|
||||
return node
|
||||
class MyDumper(AnsibleDumper):
|
||||
def represent_scalar(self, tag, value, style=None):
|
||||
"""Uses block style for multi-line strings"""
|
||||
if style is None:
|
||||
if should_use_block(value):
|
||||
style = '|'
|
||||
# we care more about readable than accuracy, so...
|
||||
# ...no trailing space
|
||||
value = value.rstrip()
|
||||
# ...and non-printable characters
|
||||
value = ''.join(x for x in value if x in string.printable or ord(x) >= 0xA0)
|
||||
# ...tabs prevent blocks from expanding
|
||||
value = value.expandtabs()
|
||||
# ...and odd bits of whitespace
|
||||
value = re.sub(r'[\x0b\x0c\r]', '', value)
|
||||
# ...as does trailing space
|
||||
value = re.sub(r' +\n', '\n', value)
|
||||
else:
|
||||
style = self.default_style
|
||||
node = yaml.representer.ScalarNode(tag, value, style=style)
|
||||
if self.alias_key is not None:
|
||||
self.represented_objects[self.alias_key] = node
|
||||
return node
|
||||
|
||||
|
||||
class CallbackModule(Default):
|
||||
@@ -159,11 +115,11 @@ class CallbackModule(Default):
|
||||
|
||||
# put changed and skipped into a header line
|
||||
if 'changed' in abridged_result:
|
||||
dumped += 'changed=' + str(abridged_result['changed']).lower() + ' '
|
||||
dumped += f"changed={str(abridged_result['changed']).lower()} "
|
||||
del abridged_result['changed']
|
||||
|
||||
if 'skipped' in abridged_result:
|
||||
dumped += 'skipped=' + str(abridged_result['skipped']).lower() + ' '
|
||||
dumped += f"skipped={str(abridged_result['skipped']).lower()} "
|
||||
del abridged_result['skipped']
|
||||
|
||||
# if we already have stdout, we don't need stdout_lines
|
||||
|
||||
@@ -81,7 +81,7 @@ from ansible.errors import AnsibleError
|
||||
from ansible.module_utils.basic import is_executable
|
||||
from ansible.module_utils.common.process import get_bin_path
|
||||
from ansible.module_utils.six.moves import shlex_quote
|
||||
from ansible.module_utils.common.text.converters import to_bytes, to_native
|
||||
from ansible.module_utils.common.text.converters import to_bytes
|
||||
from ansible.plugins.connection import ConnectionBase, BUFSIZE
|
||||
from ansible.utils.display import Display
|
||||
|
||||
@@ -107,15 +107,15 @@ class Connection(ConnectionBase):
|
||||
|
||||
# do some trivial checks for ensuring 'host' is actually a chroot'able dir
|
||||
if not os.path.isdir(self.chroot):
|
||||
raise AnsibleError("%s is not a directory" % self.chroot)
|
||||
raise AnsibleError(f"{self.chroot} is not a directory")
|
||||
|
||||
chrootsh = os.path.join(self.chroot, 'bin/sh')
|
||||
# Want to check for a usable bourne shell inside the chroot.
|
||||
# is_executable() == True is sufficient. For symlinks it
|
||||
# gets really complicated really fast. So we punt on finding that
|
||||
# out. As long as it's a symlink we assume that it will work
|
||||
# out. As long as it is a symlink we assume that it will work
|
||||
if not (is_executable(chrootsh) or (os.path.lexists(chrootsh) and os.path.islink(chrootsh))):
|
||||
raise AnsibleError("%s does not look like a chrootable dir (/bin/sh missing)" % self.chroot)
|
||||
raise AnsibleError(f"{self.chroot} does not look like a chrootable dir (/bin/sh missing)")
|
||||
|
||||
def _connect(self):
|
||||
""" connect to the chroot """
|
||||
@@ -130,7 +130,7 @@ class Connection(ConnectionBase):
|
||||
try:
|
||||
self.chroot_cmd = get_bin_path(self.get_option('chroot_exe'))
|
||||
except ValueError as e:
|
||||
raise AnsibleError(to_native(e))
|
||||
raise AnsibleError(str(e))
|
||||
|
||||
super(Connection, self)._connect()
|
||||
if not self._connected:
|
||||
@@ -148,7 +148,7 @@ class Connection(ConnectionBase):
|
||||
executable = self.get_option('executable')
|
||||
local_cmd = [self.chroot_cmd, self.chroot, executable, '-c', cmd]
|
||||
|
||||
display.vvv("EXEC %s" % local_cmd, host=self.chroot)
|
||||
display.vvv(f"EXEC {local_cmd}", host=self.chroot)
|
||||
local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]
|
||||
p = subprocess.Popen(local_cmd, shell=False, stdin=stdin,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
@@ -173,7 +173,7 @@ class Connection(ConnectionBase):
|
||||
exist in any given chroot. So for now we're choosing "/" instead.
|
||||
This also happens to be the former default.
|
||||
|
||||
Can revisit using $HOME instead if it's a problem
|
||||
Can revisit using $HOME instead if it is a problem
|
||||
"""
|
||||
if not remote_path.startswith(os.path.sep):
|
||||
remote_path = os.path.join(os.path.sep, remote_path)
|
||||
@@ -182,7 +182,7 @@ class Connection(ConnectionBase):
|
||||
def put_file(self, in_path, out_path):
|
||||
""" transfer a file from local to chroot """
|
||||
super(Connection, self).put_file(in_path, out_path)
|
||||
display.vvv("PUT %s TO %s" % (in_path, out_path), host=self.chroot)
|
||||
display.vvv(f"PUT {in_path} TO {out_path}", host=self.chroot)
|
||||
|
||||
out_path = shlex_quote(self._prefix_login_path(out_path))
|
||||
try:
|
||||
@@ -192,27 +192,27 @@ class Connection(ConnectionBase):
|
||||
else:
|
||||
count = ''
|
||||
try:
|
||||
p = self._buffered_exec_command('dd of=%s bs=%s%s' % (out_path, BUFSIZE, count), stdin=in_file)
|
||||
p = self._buffered_exec_command(f'dd of={out_path} bs={BUFSIZE}{count}', stdin=in_file)
|
||||
except OSError:
|
||||
raise AnsibleError("chroot connection requires dd command in the chroot")
|
||||
try:
|
||||
stdout, stderr = p.communicate()
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
raise AnsibleError("failed to transfer file %s to %s" % (in_path, out_path))
|
||||
raise AnsibleError(f"failed to transfer file {in_path} to {out_path}")
|
||||
if p.returncode != 0:
|
||||
raise AnsibleError("failed to transfer file %s to %s:\n%s\n%s" % (in_path, out_path, stdout, stderr))
|
||||
raise AnsibleError(f"failed to transfer file {in_path} to {out_path}:\n{stdout}\n{stderr}")
|
||||
except IOError:
|
||||
raise AnsibleError("file or module does not exist at: %s" % in_path)
|
||||
raise AnsibleError(f"file or module does not exist at: {in_path}")
|
||||
|
||||
def fetch_file(self, in_path, out_path):
|
||||
""" fetch a file from chroot to local """
|
||||
super(Connection, self).fetch_file(in_path, out_path)
|
||||
display.vvv("FETCH %s TO %s" % (in_path, out_path), host=self.chroot)
|
||||
display.vvv(f"FETCH {in_path} TO {out_path}", host=self.chroot)
|
||||
|
||||
in_path = shlex_quote(self._prefix_login_path(in_path))
|
||||
try:
|
||||
p = self._buffered_exec_command('dd if=%s bs=%s' % (in_path, BUFSIZE))
|
||||
p = self._buffered_exec_command(f'dd if={in_path} bs={BUFSIZE}')
|
||||
except OSError:
|
||||
raise AnsibleError("chroot connection requires dd command in the chroot")
|
||||
|
||||
@@ -224,10 +224,10 @@ class Connection(ConnectionBase):
|
||||
chunk = p.stdout.read(BUFSIZE)
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
raise AnsibleError("failed to transfer file %s to %s" % (in_path, out_path))
|
||||
raise AnsibleError(f"failed to transfer file {in_path} to {out_path}")
|
||||
stdout, stderr = p.communicate()
|
||||
if p.returncode != 0:
|
||||
raise AnsibleError("failed to transfer file %s to %s:\n%s\n%s" % (in_path, out_path, stdout, stderr))
|
||||
raise AnsibleError(f"failed to transfer file {in_path} to {out_path}:\n{stdout}\n{stderr}")
|
||||
|
||||
def close(self):
|
||||
""" terminate the connection; nothing to do here """
|
||||
|
||||
@@ -72,7 +72,7 @@ class Connection(ConnectionBase):
|
||||
raise AnsibleError("Internal Error: this module does not support optimized module pipelining")
|
||||
|
||||
# totally ignores privilege escalation
|
||||
display.vvv("EXEC %s" % cmd, host=self.host)
|
||||
display.vvv(f"EXEC {cmd}", host=self.host)
|
||||
p = self.client.command.run(cmd)[self.host]
|
||||
return p[0], p[1], p[2]
|
||||
|
||||
@@ -87,14 +87,14 @@ class Connection(ConnectionBase):
|
||||
""" transfer a file from local to remote """
|
||||
|
||||
out_path = self._normalize_path(out_path, '/')
|
||||
display.vvv("PUT %s TO %s" % (in_path, out_path), host=self.host)
|
||||
display.vvv(f"PUT {in_path} TO {out_path}", host=self.host)
|
||||
self.client.local.copyfile.send(in_path, out_path)
|
||||
|
||||
def fetch_file(self, in_path, out_path):
|
||||
""" fetch a file from remote to local """
|
||||
|
||||
in_path = self._normalize_path(in_path, '/')
|
||||
display.vvv("FETCH %s TO %s" % (in_path, out_path), host=self.host)
|
||||
display.vvv(f"FETCH {in_path} TO {out_path}", host=self.host)
|
||||
# need to use a tmp dir due to difference of semantic for getfile
|
||||
# ( who take a # directory as destination) and fetch_file, who
|
||||
# take a file directly
|
||||
|
||||
@@ -80,7 +80,7 @@ class Connection(ConnectionBase):
|
||||
super(Connection, self)._connect()
|
||||
|
||||
if not self._connected:
|
||||
self._display.vvv(u"ESTABLISH Incus CONNECTION FOR USER: root",
|
||||
self._display.vvv("ESTABLISH Incus CONNECTION FOR USER: root",
|
||||
host=self._instance())
|
||||
self._connected = True
|
||||
|
||||
@@ -93,14 +93,14 @@ class Connection(ConnectionBase):
|
||||
""" execute a command on the Incus host """
|
||||
super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable)
|
||||
|
||||
self._display.vvv(u"EXEC {0}".format(cmd),
|
||||
self._display.vvv(f"EXEC {cmd}",
|
||||
host=self._instance())
|
||||
|
||||
local_cmd = [
|
||||
self._incus_cmd,
|
||||
"--project", self.get_option("project"),
|
||||
"exec",
|
||||
"%s:%s" % (self.get_option("remote"), self._instance()),
|
||||
f"{self.get_option('remote')}:{self._instance()}",
|
||||
"--",
|
||||
self._play_context.executable, "-c", cmd]
|
||||
|
||||
@@ -114,12 +114,10 @@ class Connection(ConnectionBase):
|
||||
stderr = to_text(stderr)
|
||||
|
||||
if stderr == "Error: Instance is not running.\n":
|
||||
raise AnsibleConnectionFailure("instance not running: %s" %
|
||||
self._instance())
|
||||
raise AnsibleConnectionFailure(f"instance not running: {self._instance()}")
|
||||
|
||||
if stderr == "Error: Instance not found\n":
|
||||
raise AnsibleConnectionFailure("instance not found: %s" %
|
||||
self._instance())
|
||||
raise AnsibleConnectionFailure(f"instance not found: {self._instance()}")
|
||||
|
||||
return process.returncode, stdout, stderr
|
||||
|
||||
@@ -127,20 +125,18 @@ class Connection(ConnectionBase):
|
||||
""" put a file from local to Incus """
|
||||
super(Connection, self).put_file(in_path, out_path)
|
||||
|
||||
self._display.vvv(u"PUT {0} TO {1}".format(in_path, out_path),
|
||||
self._display.vvv(f"PUT {in_path} TO {out_path}",
|
||||
host=self._instance())
|
||||
|
||||
if not os.path.isfile(to_bytes(in_path, errors='surrogate_or_strict')):
|
||||
raise AnsibleFileNotFound("input path is not a file: %s" % in_path)
|
||||
raise AnsibleFileNotFound(f"input path is not a file: {in_path}")
|
||||
|
||||
local_cmd = [
|
||||
self._incus_cmd,
|
||||
"--project", self.get_option("project"),
|
||||
"file", "push", "--quiet",
|
||||
in_path,
|
||||
"%s:%s/%s" % (self.get_option("remote"),
|
||||
self._instance(),
|
||||
out_path)]
|
||||
f"{self.get_option('remote')}:{self._instance()}/{out_path}"]
|
||||
|
||||
local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]
|
||||
|
||||
@@ -150,16 +146,14 @@ class Connection(ConnectionBase):
|
||||
""" fetch a file from Incus to local """
|
||||
super(Connection, self).fetch_file(in_path, out_path)
|
||||
|
||||
self._display.vvv(u"FETCH {0} TO {1}".format(in_path, out_path),
|
||||
self._display.vvv(f"FETCH {in_path} TO {out_path}",
|
||||
host=self._instance())
|
||||
|
||||
local_cmd = [
|
||||
self._incus_cmd,
|
||||
"--project", self.get_option("project"),
|
||||
"file", "pull", "--quiet",
|
||||
"%s:%s/%s" % (self.get_option("remote"),
|
||||
self._instance(),
|
||||
in_path),
|
||||
f"{self.get_option('remote')}:{self._instance()}/{in_path}",
|
||||
out_path]
|
||||
|
||||
local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]
|
||||
|
||||
@@ -55,11 +55,12 @@ class Connection(Jail):
|
||||
|
||||
jail_uuid = self.get_jail_uuid()
|
||||
|
||||
kwargs[Jail.modified_jailname_key] = 'ioc-{0}'.format(jail_uuid)
|
||||
kwargs[Jail.modified_jailname_key] = f'ioc-{jail_uuid}'
|
||||
|
||||
display.vvv(u"Jail {iocjail} has been translated to {rawjail}".format(
|
||||
iocjail=self.ioc_jail, rawjail=kwargs[Jail.modified_jailname_key]),
|
||||
host=kwargs[Jail.modified_jailname_key])
|
||||
display.vvv(
|
||||
f"Jail {self.ioc_jail} has been translated to {kwargs[Jail.modified_jailname_key]}",
|
||||
host=kwargs[Jail.modified_jailname_key]
|
||||
)
|
||||
|
||||
super(Connection, self).__init__(play_context, new_stdin, *args, **kwargs)
|
||||
|
||||
@@ -81,6 +82,6 @@ class Connection(Jail):
|
||||
p.wait()
|
||||
|
||||
if p.returncode != 0:
|
||||
raise AnsibleError(u"iocage returned an error: {0}".format(stdout))
|
||||
raise AnsibleError(f"iocage returned an error: {stdout}")
|
||||
|
||||
return stdout.strip('\n')
|
||||
|
||||
@@ -75,14 +75,14 @@ class Connection(ConnectionBase):
|
||||
self.jexec_cmd = self._search_executable('jexec')
|
||||
|
||||
if self.jail not in self.list_jails():
|
||||
raise AnsibleError("incorrect jail name %s" % self.jail)
|
||||
raise AnsibleError(f"incorrect jail name {self.jail}")
|
||||
|
||||
@staticmethod
|
||||
def _search_executable(executable):
|
||||
try:
|
||||
return get_bin_path(executable)
|
||||
except ValueError:
|
||||
raise AnsibleError("%s command not found in PATH" % executable)
|
||||
raise AnsibleError(f"{executable} command not found in PATH")
|
||||
|
||||
def list_jails(self):
|
||||
p = subprocess.Popen([self.jls_cmd, '-q', 'name'],
|
||||
@@ -97,7 +97,7 @@ class Connection(ConnectionBase):
|
||||
""" connect to the jail; nothing to do here """
|
||||
super(Connection, self)._connect()
|
||||
if not self._connected:
|
||||
display.vvv(u"ESTABLISH JAIL CONNECTION FOR USER: {0}".format(self._play_context.remote_user), host=self.jail)
|
||||
display.vvv(f"ESTABLISH JAIL CONNECTION FOR USER: {self._play_context.remote_user}", host=self.jail)
|
||||
self._connected = True
|
||||
|
||||
def _buffered_exec_command(self, cmd, stdin=subprocess.PIPE):
|
||||
@@ -115,11 +115,11 @@ class Connection(ConnectionBase):
|
||||
if self._play_context.remote_user is not None:
|
||||
local_cmd += ['-U', self._play_context.remote_user]
|
||||
# update HOME since -U does not update the jail environment
|
||||
set_env = 'HOME=~' + self._play_context.remote_user + ' '
|
||||
set_env = f"HOME=~{self._play_context.remote_user} "
|
||||
|
||||
local_cmd += [self.jail, self._play_context.executable, '-c', set_env + cmd]
|
||||
|
||||
display.vvv("EXEC %s" % (local_cmd,), host=self.jail)
|
||||
display.vvv(f"EXEC {local_cmd}", host=self.jail)
|
||||
local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]
|
||||
p = subprocess.Popen(local_cmd, shell=False, stdin=stdin,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
@@ -144,7 +144,7 @@ class Connection(ConnectionBase):
|
||||
exist in any given chroot. So for now we're choosing "/" instead.
|
||||
This also happens to be the former default.
|
||||
|
||||
Can revisit using $HOME instead if it's a problem
|
||||
Can revisit using $HOME instead if it is a problem
|
||||
"""
|
||||
if not remote_path.startswith(os.path.sep):
|
||||
remote_path = os.path.join(os.path.sep, remote_path)
|
||||
@@ -153,7 +153,7 @@ class Connection(ConnectionBase):
|
||||
def put_file(self, in_path, out_path):
|
||||
""" transfer a file from local to jail """
|
||||
super(Connection, self).put_file(in_path, out_path)
|
||||
display.vvv("PUT %s TO %s" % (in_path, out_path), host=self.jail)
|
||||
display.vvv(f"PUT {in_path} TO {out_path}", host=self.jail)
|
||||
|
||||
out_path = shlex_quote(self._prefix_login_path(out_path))
|
||||
try:
|
||||
@@ -163,27 +163,27 @@ class Connection(ConnectionBase):
|
||||
else:
|
||||
count = ''
|
||||
try:
|
||||
p = self._buffered_exec_command('dd of=%s bs=%s%s' % (out_path, BUFSIZE, count), stdin=in_file)
|
||||
p = self._buffered_exec_command(f'dd of={out_path} bs={BUFSIZE}{count}', stdin=in_file)
|
||||
except OSError:
|
||||
raise AnsibleError("jail connection requires dd command in the jail")
|
||||
try:
|
||||
stdout, stderr = p.communicate()
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
raise AnsibleError("failed to transfer file %s to %s" % (in_path, out_path))
|
||||
raise AnsibleError(f"failed to transfer file {in_path} to {out_path}")
|
||||
if p.returncode != 0:
|
||||
raise AnsibleError("failed to transfer file %s to %s:\n%s\n%s" % (in_path, out_path, to_native(stdout), to_native(stderr)))
|
||||
raise AnsibleError(f"failed to transfer file {in_path} to {out_path}:\n{to_native(stdout)}\n{to_native(stderr)}")
|
||||
except IOError:
|
||||
raise AnsibleError("file or module does not exist at: %s" % in_path)
|
||||
raise AnsibleError(f"file or module does not exist at: {in_path}")
|
||||
|
||||
def fetch_file(self, in_path, out_path):
|
||||
""" fetch a file from jail to local """
|
||||
super(Connection, self).fetch_file(in_path, out_path)
|
||||
display.vvv("FETCH %s TO %s" % (in_path, out_path), host=self.jail)
|
||||
display.vvv(f"FETCH {in_path} TO {out_path}", host=self.jail)
|
||||
|
||||
in_path = shlex_quote(self._prefix_login_path(in_path))
|
||||
try:
|
||||
p = self._buffered_exec_command('dd if=%s bs=%s' % (in_path, BUFSIZE))
|
||||
p = self._buffered_exec_command(f'dd if={in_path} bs={BUFSIZE}')
|
||||
except OSError:
|
||||
raise AnsibleError("jail connection requires dd command in the jail")
|
||||
|
||||
@@ -195,10 +195,10 @@ class Connection(ConnectionBase):
|
||||
chunk = p.stdout.read(BUFSIZE)
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
raise AnsibleError("failed to transfer file %s to %s" % (in_path, out_path))
|
||||
raise AnsibleError(f"failed to transfer file {in_path} to {out_path}")
|
||||
stdout, stderr = p.communicate()
|
||||
if p.returncode != 0:
|
||||
raise AnsibleError("failed to transfer file %s to %s:\n%s\n%s" % (in_path, out_path, to_native(stdout), to_native(stderr)))
|
||||
raise AnsibleError(f"failed to transfer file {in_path} to {out_path}:\n{to_native(stdout)}\n{to_native(stderr)}")
|
||||
|
||||
def close(self):
|
||||
""" terminate the connection; nothing to do here """
|
||||
|
||||
@@ -82,7 +82,7 @@ class Connection(ConnectionBase):
|
||||
self._display.vvv("THIS IS A LOCAL LXC DIR", host=self.container_name)
|
||||
self.container = _lxc.Container(self.container_name)
|
||||
if self.container.state == "STOPPED":
|
||||
raise errors.AnsibleError("%s is not running" % self.container_name)
|
||||
raise errors.AnsibleError(f"{self.container_name} is not running")
|
||||
|
||||
@staticmethod
|
||||
def _communicate(pid, in_data, stdin, stdout, stderr):
|
||||
@@ -144,10 +144,10 @@ class Connection(ConnectionBase):
|
||||
read_stdin, write_stdin = os.pipe()
|
||||
kwargs['stdin'] = self._set_nonblocking(read_stdin)
|
||||
|
||||
self._display.vvv("EXEC %s" % (local_cmd), host=self.container_name)
|
||||
self._display.vvv(f"EXEC {local_cmd}", host=self.container_name)
|
||||
pid = self.container.attach(_lxc.attach_run_command, local_cmd, **kwargs)
|
||||
if pid == -1:
|
||||
msg = "failed to attach to container %s" % self.container_name
|
||||
msg = f"failed to attach to container {self.container_name}"
|
||||
raise errors.AnsibleError(msg)
|
||||
|
||||
write_stdout = os.close(write_stdout)
|
||||
@@ -174,18 +174,18 @@ class Connection(ConnectionBase):
|
||||
def put_file(self, in_path, out_path):
|
||||
''' transfer a file from local to lxc '''
|
||||
super(Connection, self).put_file(in_path, out_path)
|
||||
self._display.vvv("PUT %s TO %s" % (in_path, out_path), host=self.container_name)
|
||||
self._display.vvv(f"PUT {in_path} TO {out_path}", host=self.container_name)
|
||||
in_path = to_bytes(in_path, errors='surrogate_or_strict')
|
||||
out_path = to_bytes(out_path, errors='surrogate_or_strict')
|
||||
|
||||
if not os.path.exists(in_path):
|
||||
msg = "file or module does not exist: %s" % in_path
|
||||
msg = f"file or module does not exist: {in_path}"
|
||||
raise errors.AnsibleFileNotFound(msg)
|
||||
try:
|
||||
src_file = open(in_path, "rb")
|
||||
except IOError:
|
||||
traceback.print_exc()
|
||||
raise errors.AnsibleError("failed to open input file to %s" % in_path)
|
||||
raise errors.AnsibleError(f"failed to open input file to {in_path}")
|
||||
try:
|
||||
def write_file(args):
|
||||
with open(out_path, 'wb+') as dst_file:
|
||||
@@ -194,7 +194,7 @@ class Connection(ConnectionBase):
|
||||
self.container.attach_wait(write_file, None)
|
||||
except IOError:
|
||||
traceback.print_exc()
|
||||
msg = "failed to transfer file to %s" % out_path
|
||||
msg = f"failed to transfer file to {out_path}"
|
||||
raise errors.AnsibleError(msg)
|
||||
finally:
|
||||
src_file.close()
|
||||
@@ -202,7 +202,7 @@ class Connection(ConnectionBase):
|
||||
def fetch_file(self, in_path, out_path):
|
||||
''' fetch a file from lxc to local '''
|
||||
super(Connection, self).fetch_file(in_path, out_path)
|
||||
self._display.vvv("FETCH %s TO %s" % (in_path, out_path), host=self.container_name)
|
||||
self._display.vvv(f"FETCH {in_path} TO {out_path}", host=self.container_name)
|
||||
in_path = to_bytes(in_path, errors='surrogate_or_strict')
|
||||
out_path = to_bytes(out_path, errors='surrogate_or_strict')
|
||||
|
||||
@@ -210,7 +210,7 @@ class Connection(ConnectionBase):
|
||||
dst_file = open(out_path, "wb")
|
||||
except IOError:
|
||||
traceback.print_exc()
|
||||
msg = "failed to open output file %s" % out_path
|
||||
msg = f"failed to open output file {out_path}"
|
||||
raise errors.AnsibleError(msg)
|
||||
try:
|
||||
def write_file(args):
|
||||
@@ -225,7 +225,7 @@ class Connection(ConnectionBase):
|
||||
self.container.attach_wait(write_file, None)
|
||||
except IOError:
|
||||
traceback.print_exc()
|
||||
msg = "failed to transfer file from %s to %s" % (in_path, out_path)
|
||||
msg = f"failed to transfer file from {in_path} to {out_path}"
|
||||
raise errors.AnsibleError(msg)
|
||||
finally:
|
||||
dst_file.close()
|
||||
|
||||
@@ -86,26 +86,26 @@ class Connection(ConnectionBase):
|
||||
super(Connection, self)._connect()
|
||||
|
||||
if not self._connected:
|
||||
self._display.vvv(u"ESTABLISH LXD CONNECTION FOR USER: root", host=self._host())
|
||||
self._display.vvv("ESTABLISH LXD CONNECTION FOR USER: root", host=self._host())
|
||||
self._connected = True
|
||||
|
||||
def exec_command(self, cmd, in_data=None, sudoable=True):
|
||||
""" execute a command on the lxd host """
|
||||
super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable)
|
||||
|
||||
self._display.vvv(u"EXEC {0}".format(cmd), host=self._host())
|
||||
self._display.vvv(f"EXEC {cmd}", host=self._host())
|
||||
|
||||
local_cmd = [self._lxc_cmd]
|
||||
if self.get_option("project"):
|
||||
local_cmd.extend(["--project", self.get_option("project")])
|
||||
local_cmd.extend([
|
||||
"exec",
|
||||
"%s:%s" % (self.get_option("remote"), self._host()),
|
||||
f"{self.get_option('remote')}:{self._host()}",
|
||||
"--",
|
||||
self.get_option("executable"), "-c", cmd
|
||||
])
|
||||
|
||||
self._display.vvvvv(u"EXEC {0}".format(local_cmd), host=self._host())
|
||||
self._display.vvvvv(f"EXEC {local_cmd}", host=self._host())
|
||||
|
||||
local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]
|
||||
in_data = to_bytes(in_data, errors='surrogate_or_strict', nonstring='passthru')
|
||||
@@ -116,13 +116,13 @@ class Connection(ConnectionBase):
|
||||
stdout = to_text(stdout)
|
||||
stderr = to_text(stderr)
|
||||
|
||||
self._display.vvvvv(u"EXEC lxc output: {0} {1}".format(stdout, stderr), host=self._host())
|
||||
self._display.vvvvv(f"EXEC lxc output: {stdout} {stderr}", host=self._host())
|
||||
|
||||
if "is not running" in stderr:
|
||||
raise AnsibleConnectionFailure("instance not running: %s" % self._host())
|
||||
raise AnsibleConnectionFailure(f"instance not running: {self._host()}")
|
||||
|
||||
if stderr.strip() == "Error: Instance not found" or stderr.strip() == "error: not found":
|
||||
raise AnsibleConnectionFailure("instance not found: %s" % self._host())
|
||||
raise AnsibleConnectionFailure(f"instance not found: {self._host()}")
|
||||
|
||||
return process.returncode, stdout, stderr
|
||||
|
||||
@@ -130,10 +130,10 @@ class Connection(ConnectionBase):
|
||||
""" put a file from local to lxd """
|
||||
super(Connection, self).put_file(in_path, out_path)
|
||||
|
||||
self._display.vvv(u"PUT {0} TO {1}".format(in_path, out_path), host=self._host())
|
||||
self._display.vvv(f"PUT {in_path} TO {out_path}", host=self._host())
|
||||
|
||||
if not os.path.isfile(to_bytes(in_path, errors='surrogate_or_strict')):
|
||||
raise AnsibleFileNotFound("input path is not a file: %s" % in_path)
|
||||
raise AnsibleFileNotFound(f"input path is not a file: {in_path}")
|
||||
|
||||
local_cmd = [self._lxc_cmd]
|
||||
if self.get_option("project"):
|
||||
@@ -141,7 +141,7 @@ class Connection(ConnectionBase):
|
||||
local_cmd.extend([
|
||||
"file", "push",
|
||||
in_path,
|
||||
"%s:%s/%s" % (self.get_option("remote"), self._host(), out_path)
|
||||
f"{self.get_option('remote')}:{self._host()}/{out_path}"
|
||||
])
|
||||
|
||||
local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]
|
||||
@@ -153,14 +153,14 @@ class Connection(ConnectionBase):
|
||||
""" fetch a file from lxd to local """
|
||||
super(Connection, self).fetch_file(in_path, out_path)
|
||||
|
||||
self._display.vvv(u"FETCH {0} TO {1}".format(in_path, out_path), host=self._host())
|
||||
self._display.vvv(f"FETCH {in_path} TO {out_path}", host=self._host())
|
||||
|
||||
local_cmd = [self._lxc_cmd]
|
||||
if self.get_option("project"):
|
||||
local_cmd.extend(["--project", self.get_option("project")])
|
||||
local_cmd.extend([
|
||||
"file", "pull",
|
||||
"%s:%s/%s" % (self.get_option("remote"), self._host(), in_path),
|
||||
f"{self.get_option('remote')}:{self._host()}/{in_path}",
|
||||
out_path
|
||||
])
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ class Connection(ConnectionBase):
|
||||
"""
|
||||
display.vvvv("CMD: ", cmd)
|
||||
if not cmd.endswith("\n"):
|
||||
cmd = cmd + "\n"
|
||||
cmd = f"{cmd}\n"
|
||||
local_cmd = []
|
||||
|
||||
# For dom0
|
||||
@@ -94,7 +94,7 @@ class Connection(ConnectionBase):
|
||||
|
||||
display.vvvv("Local cmd: ", local_cmd)
|
||||
|
||||
display.vvv("RUN %s" % (local_cmd,), host=self._remote_vmname)
|
||||
display.vvv(f"RUN {local_cmd}", host=self._remote_vmname)
|
||||
p = subprocess.Popen(local_cmd, shell=False, stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
|
||||
@@ -113,42 +113,42 @@ class Connection(ConnectionBase):
|
||||
"""Run specified command in a running QubesVM """
|
||||
super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable)
|
||||
|
||||
display.vvvv("CMD IS: %s" % cmd)
|
||||
display.vvvv(f"CMD IS: {cmd}")
|
||||
|
||||
rc, stdout, stderr = self._qubes(cmd)
|
||||
|
||||
display.vvvvv("STDOUT %r STDERR %r" % (stdout, stderr))
|
||||
display.vvvvv(f"STDOUT {stdout!r} STDERR {stderr!r}")
|
||||
return rc, stdout, stderr
|
||||
|
||||
def put_file(self, in_path, out_path):
|
||||
""" Place a local file located in 'in_path' inside VM at 'out_path' """
|
||||
super(Connection, self).put_file(in_path, out_path)
|
||||
display.vvv("PUT %s TO %s" % (in_path, out_path), host=self._remote_vmname)
|
||||
display.vvv(f"PUT {in_path} TO {out_path}", host=self._remote_vmname)
|
||||
|
||||
with open(in_path, "rb") as fobj:
|
||||
source_data = fobj.read()
|
||||
|
||||
retcode, dummy, dummy = self._qubes('cat > "{0}"\n'.format(out_path), source_data, "qubes.VMRootShell")
|
||||
retcode, dummy, dummy = self._qubes(f'cat > "{out_path}\"\n', source_data, "qubes.VMRootShell")
|
||||
# if qubes.VMRootShell service not supported, fallback to qubes.VMShell and
|
||||
# hope it will have appropriate permissions
|
||||
if retcode == 127:
|
||||
retcode, dummy, dummy = self._qubes('cat > "{0}"\n'.format(out_path), source_data)
|
||||
retcode, dummy, dummy = self._qubes(f'cat > "{out_path}\"\n', source_data)
|
||||
|
||||
if retcode != 0:
|
||||
raise AnsibleConnectionFailure('Failed to put_file to {0}'.format(out_path))
|
||||
raise AnsibleConnectionFailure(f'Failed to put_file to {out_path}')
|
||||
|
||||
def fetch_file(self, in_path, out_path):
|
||||
"""Obtain file specified via 'in_path' from the container and place it at 'out_path' """
|
||||
super(Connection, self).fetch_file(in_path, out_path)
|
||||
display.vvv("FETCH %s TO %s" % (in_path, out_path), host=self._remote_vmname)
|
||||
display.vvv(f"FETCH {in_path} TO {out_path}", host=self._remote_vmname)
|
||||
|
||||
# We are running in dom0
|
||||
cmd_args_list = ["qvm-run", "--pass-io", self._remote_vmname, "cat {0}".format(in_path)]
|
||||
cmd_args_list = ["qvm-run", "--pass-io", self._remote_vmname, f"cat {in_path}"]
|
||||
with open(out_path, "wb") as fobj:
|
||||
p = subprocess.Popen(cmd_args_list, shell=False, stdout=fobj)
|
||||
p.communicate()
|
||||
if p.returncode != 0:
|
||||
raise AnsibleConnectionFailure('Failed to fetch file to {0}'.format(out_path))
|
||||
raise AnsibleConnectionFailure(f'Failed to fetch file to {out_path}')
|
||||
|
||||
def close(self):
|
||||
""" Closing the connection """
|
||||
|
||||
@@ -59,11 +59,11 @@ class Connection(ConnectionBase):
|
||||
if in_data:
|
||||
raise errors.AnsibleError("Internal Error: this module does not support optimized module pipelining")
|
||||
|
||||
self._display.vvv("EXEC %s" % cmd, host=self.host)
|
||||
self._display.vvv(f"EXEC {cmd}", host=self.host)
|
||||
# need to add 'true;' to work around https://github.com/saltstack/salt/issues/28077
|
||||
res = self.client.cmd(self.host, 'cmd.exec_code_all', ['bash', 'true;' + cmd])
|
||||
res = self.client.cmd(self.host, 'cmd.exec_code_all', ['bash', f"true;{cmd}"])
|
||||
if self.host not in res:
|
||||
raise errors.AnsibleError("Minion %s didn't answer, check if salt-minion is running and the name is correct" % self.host)
|
||||
raise errors.AnsibleError(f"Minion {self.host} didn't answer, check if salt-minion is running and the name is correct")
|
||||
|
||||
p = res[self.host]
|
||||
return p['retcode'], p['stdout'], p['stderr']
|
||||
@@ -81,7 +81,7 @@ class Connection(ConnectionBase):
|
||||
super(Connection, self).put_file(in_path, out_path)
|
||||
|
||||
out_path = self._normalize_path(out_path, '/')
|
||||
self._display.vvv("PUT %s TO %s" % (in_path, out_path), host=self.host)
|
||||
self._display.vvv(f"PUT {in_path} TO {out_path}", host=self.host)
|
||||
with open(in_path, 'rb') as in_fh:
|
||||
content = in_fh.read()
|
||||
self.client.cmd(self.host, 'hashutil.base64_decodefile', [base64.b64encode(content), out_path])
|
||||
@@ -93,7 +93,7 @@ class Connection(ConnectionBase):
|
||||
super(Connection, self).fetch_file(in_path, out_path)
|
||||
|
||||
in_path = self._normalize_path(in_path, '/')
|
||||
self._display.vvv("FETCH %s TO %s" % (in_path, out_path), host=self.host)
|
||||
self._display.vvv(f"FETCH {in_path} TO {out_path}", host=self.host)
|
||||
content = self.client.cmd(self.host, 'cp.get_file_str', [in_path])[self.host]
|
||||
open(out_path, 'wb').write(content)
|
||||
|
||||
|
||||
@@ -62,14 +62,14 @@ class Connection(ConnectionBase):
|
||||
self.zlogin_cmd = to_bytes(self._search_executable('zlogin'))
|
||||
|
||||
if self.zone not in self.list_zones():
|
||||
raise AnsibleError("incorrect zone name %s" % self.zone)
|
||||
raise AnsibleError(f"incorrect zone name {self.zone}")
|
||||
|
||||
@staticmethod
|
||||
def _search_executable(executable):
|
||||
try:
|
||||
return get_bin_path(executable)
|
||||
except ValueError:
|
||||
raise AnsibleError("%s command not found in PATH" % executable)
|
||||
raise AnsibleError(f"{executable} command not found in PATH")
|
||||
|
||||
def list_zones(self):
|
||||
process = subprocess.Popen([self.zoneadm_cmd, 'list', '-ip'],
|
||||
@@ -94,7 +94,7 @@ class Connection(ConnectionBase):
|
||||
|
||||
# stdout, stderr = p.communicate()
|
||||
path = process.stdout.readlines()[0].split(':')[3]
|
||||
return path + '/root'
|
||||
return f"{path}/root"
|
||||
|
||||
def _connect(self):
|
||||
""" connect to the zone; nothing to do here """
|
||||
@@ -117,7 +117,7 @@ class Connection(ConnectionBase):
|
||||
local_cmd = [self.zlogin_cmd, self.zone, cmd]
|
||||
local_cmd = map(to_bytes, local_cmd)
|
||||
|
||||
display.vvv("EXEC %s" % (local_cmd), host=self.zone)
|
||||
display.vvv(f"EXEC {local_cmd}", host=self.zone)
|
||||
p = subprocess.Popen(local_cmd, shell=False, stdin=stdin,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
|
||||
@@ -140,7 +140,7 @@ class Connection(ConnectionBase):
|
||||
exist in any given chroot. So for now we're choosing "/" instead.
|
||||
This also happens to be the former default.
|
||||
|
||||
Can revisit using $HOME instead if it's a problem
|
||||
Can revisit using $HOME instead if it is a problem
|
||||
"""
|
||||
if not remote_path.startswith(os.path.sep):
|
||||
remote_path = os.path.join(os.path.sep, remote_path)
|
||||
@@ -149,7 +149,7 @@ class Connection(ConnectionBase):
|
||||
def put_file(self, in_path, out_path):
|
||||
""" transfer a file from local to zone """
|
||||
super(Connection, self).put_file(in_path, out_path)
|
||||
display.vvv("PUT %s TO %s" % (in_path, out_path), host=self.zone)
|
||||
display.vvv(f"PUT {in_path} TO {out_path}", host=self.zone)
|
||||
|
||||
out_path = shlex_quote(self._prefix_login_path(out_path))
|
||||
try:
|
||||
@@ -159,27 +159,27 @@ class Connection(ConnectionBase):
|
||||
else:
|
||||
count = ''
|
||||
try:
|
||||
p = self._buffered_exec_command('dd of=%s bs=%s%s' % (out_path, BUFSIZE, count), stdin=in_file)
|
||||
p = self._buffered_exec_command(f'dd of={out_path} bs={BUFSIZE}{count}', stdin=in_file)
|
||||
except OSError:
|
||||
raise AnsibleError("jail connection requires dd command in the jail")
|
||||
try:
|
||||
stdout, stderr = p.communicate()
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
raise AnsibleError("failed to transfer file %s to %s" % (in_path, out_path))
|
||||
raise AnsibleError(f"failed to transfer file {in_path} to {out_path}")
|
||||
if p.returncode != 0:
|
||||
raise AnsibleError("failed to transfer file %s to %s:\n%s\n%s" % (in_path, out_path, stdout, stderr))
|
||||
raise AnsibleError(f"failed to transfer file {in_path} to {out_path}:\n{stdout}\n{stderr}")
|
||||
except IOError:
|
||||
raise AnsibleError("file or module does not exist at: %s" % in_path)
|
||||
raise AnsibleError(f"file or module does not exist at: {in_path}")
|
||||
|
||||
def fetch_file(self, in_path, out_path):
|
||||
""" fetch a file from zone to local """
|
||||
super(Connection, self).fetch_file(in_path, out_path)
|
||||
display.vvv("FETCH %s TO %s" % (in_path, out_path), host=self.zone)
|
||||
display.vvv(f"FETCH {in_path} TO {out_path}", host=self.zone)
|
||||
|
||||
in_path = shlex_quote(self._prefix_login_path(in_path))
|
||||
try:
|
||||
p = self._buffered_exec_command('dd if=%s bs=%s' % (in_path, BUFSIZE))
|
||||
p = self._buffered_exec_command(f'dd if={in_path} bs={BUFSIZE}')
|
||||
except OSError:
|
||||
raise AnsibleError("zone connection requires dd command in the zone")
|
||||
|
||||
@@ -191,10 +191,10 @@ class Connection(ConnectionBase):
|
||||
chunk = p.stdout.read(BUFSIZE)
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
raise AnsibleError("failed to transfer file %s to %s" % (in_path, out_path))
|
||||
raise AnsibleError(f"failed to transfer file {in_path} to {out_path}")
|
||||
stdout, stderr = p.communicate()
|
||||
if p.returncode != 0:
|
||||
raise AnsibleError("failed to transfer file %s to %s:\n%s\n%s" % (in_path, out_path, stdout, stderr))
|
||||
raise AnsibleError(f"failed to transfer file {in_path} to {out_path}:\n{stdout}\n{stderr}")
|
||||
|
||||
def close(self):
|
||||
""" terminate the connection; nothing to do here """
|
||||
|
||||
@@ -11,75 +11,73 @@ __metaclass__ = type
|
||||
class ModuleDocFragment(object):
|
||||
|
||||
# Alicloud only documentation fragment
|
||||
DOCUMENTATION = r'''
|
||||
DOCUMENTATION = r"""
|
||||
options:
|
||||
alicloud_access_key:
|
||||
description:
|
||||
- Alibaba Cloud access key. If not set then the value of environment variable E(ALICLOUD_ACCESS_KEY),
|
||||
E(ALICLOUD_ACCESS_KEY_ID) will be used instead.
|
||||
- Alibaba Cloud access key. If not set then the value of environment variable E(ALICLOUD_ACCESS_KEY), E(ALICLOUD_ACCESS_KEY_ID)
|
||||
will be used instead.
|
||||
aliases: ['access_key_id', 'access_key']
|
||||
type: str
|
||||
alicloud_secret_key:
|
||||
description:
|
||||
- Alibaba Cloud secret key. If not set then the value of environment variable E(ALICLOUD_SECRET_KEY),
|
||||
E(ALICLOUD_SECRET_ACCESS_KEY) will be used instead.
|
||||
- Alibaba Cloud secret key. If not set then the value of environment variable E(ALICLOUD_SECRET_KEY), E(ALICLOUD_SECRET_ACCESS_KEY)
|
||||
will be used instead.
|
||||
aliases: ['secret_access_key', 'secret_key']
|
||||
type: str
|
||||
alicloud_region:
|
||||
description:
|
||||
- The Alibaba Cloud region to use. If not specified then the value of environment variable
|
||||
E(ALICLOUD_REGION), E(ALICLOUD_REGION_ID) will be used instead.
|
||||
- The Alibaba Cloud region to use. If not specified then the value of environment variable E(ALICLOUD_REGION), E(ALICLOUD_REGION_ID)
|
||||
will be used instead.
|
||||
aliases: ['region', 'region_id']
|
||||
required: true
|
||||
type: str
|
||||
alicloud_security_token:
|
||||
description:
|
||||
- The Alibaba Cloud security token. If not specified then the value of environment variable
|
||||
E(ALICLOUD_SECURITY_TOKEN) will be used instead.
|
||||
- The Alibaba Cloud security token. If not specified then the value of environment variable E(ALICLOUD_SECURITY_TOKEN)
|
||||
will be used instead.
|
||||
aliases: ['security_token']
|
||||
type: str
|
||||
alicloud_assume_role:
|
||||
description:
|
||||
- If provided with a role ARN, Ansible will attempt to assume this role using the supplied credentials.
|
||||
- The nested assume_role block supports C(alicloud_assume_role_arn), C(alicloud_assume_role_session_name),
|
||||
C(alicloud_assume_role_session_expiration) and C(alicloud_assume_role_policy).
|
||||
- The nested assume_role block supports C(alicloud_assume_role_arn), C(alicloud_assume_role_session_name), C(alicloud_assume_role_session_expiration)
|
||||
and C(alicloud_assume_role_policy).
|
||||
type: dict
|
||||
aliases: ['assume_role']
|
||||
alicloud_assume_role_arn:
|
||||
description:
|
||||
- The Alibaba Cloud C(role_arn). The ARN of the role to assume. If ARN is set to an empty string,
|
||||
it does not perform role switching. It supports environment variable E(ALICLOUD_ASSUME_ROLE_ARN).
|
||||
ansible will execute with provided credentials.
|
||||
- The Alibaba Cloud C(role_arn). The ARN of the role to assume. If ARN is set to an empty string, it does not perform
|
||||
role switching. It supports environment variable E(ALICLOUD_ASSUME_ROLE_ARN). ansible will execute with provided credentials.
|
||||
aliases: ['assume_role_arn']
|
||||
type: str
|
||||
alicloud_assume_role_session_name:
|
||||
description:
|
||||
- The Alibaba Cloud session_name. The session name to use when assuming the role. If omitted,
|
||||
'ansible' is passed to the AssumeRole call as session name. It supports environment variable
|
||||
E(ALICLOUD_ASSUME_ROLE_SESSION_NAME).
|
||||
- The Alibaba Cloud session_name. The session name to use when assuming the role. If omitted, 'ansible' is passed to
|
||||
the AssumeRole call as session name. It supports environment variable E(ALICLOUD_ASSUME_ROLE_SESSION_NAME).
|
||||
aliases: ['assume_role_session_name']
|
||||
type: str
|
||||
alicloud_assume_role_session_expiration:
|
||||
description:
|
||||
- The Alibaba Cloud C(session_expiration). The time after which the established session for assuming
|
||||
role expires. Valid value range 900-3600 seconds. Default to 3600 (in this case Alicloud use own default
|
||||
value). It supports environment variable E(ALICLOUD_ASSUME_ROLE_SESSION_EXPIRATION).
|
||||
- The Alibaba Cloud C(session_expiration). The time after which the established session for assuming role expires. Valid
|
||||
value range 900-3600 seconds. Default to 3600 (in this case Alicloud use own default value). It supports environment
|
||||
variable E(ALICLOUD_ASSUME_ROLE_SESSION_EXPIRATION).
|
||||
aliases: ['assume_role_session_expiration']
|
||||
type: int
|
||||
ecs_role_name:
|
||||
description:
|
||||
- The RAM Role Name attached on a ECS instance for API operations. You can retrieve this from the 'Access Control'
|
||||
section of the Alibaba Cloud console.
|
||||
- If you're running Ansible from an ECS instance with RAM Instance using RAM Role, Ansible will just access the
|
||||
metadata U(http://100.100.100.200/latest/meta-data/ram/security-credentials/<ecs_role_name>) to obtain the STS
|
||||
credential. This is a preferred approach over any other when running in ECS as you can avoid hard coding
|
||||
credentials. Instead these are leased on-the-fly by Ansible which reduces the chance of leakage.
|
||||
- The RAM Role Name attached on a ECS instance for API operations. You can retrieve this from the 'Access Control' section
|
||||
of the Alibaba Cloud console.
|
||||
- If you are running Ansible from an ECS instance with RAM Instance using RAM Role, Ansible will just access the metadata
|
||||
U(http://100.100.100.200/latest/meta-data/ram/security-credentials/<ecs_role_name>) to obtain the STS credential.
|
||||
This is a preferred approach over any other when running in ECS as you can avoid hard coding credentials. Instead
|
||||
these are leased on-the-fly by Ansible which reduces the chance of leakage.
|
||||
aliases: ['role_name']
|
||||
type: str
|
||||
profile:
|
||||
description:
|
||||
- This is the Alicloud profile name as set in the shared credentials file. It can also be sourced from the
|
||||
E(ALICLOUD_PROFILE) environment variable.
|
||||
- This is the Alicloud profile name as set in the shared credentials file. It can also be sourced from the E(ALICLOUD_PROFILE)
|
||||
environment variable.
|
||||
type: str
|
||||
shared_credentials_file:
|
||||
description:
|
||||
@@ -88,22 +86,14 @@ options:
|
||||
- If this is not set and a profile is specified, C(~/.aliyun/config.json) will be used.
|
||||
type: str
|
||||
author:
|
||||
- "He Guimin (@xiaozhu36)"
|
||||
- "He Guimin (@xiaozhu36)"
|
||||
requirements:
|
||||
- "Python >= 3.6"
|
||||
- "Python >= 3.6"
|
||||
notes:
|
||||
- If parameters are not set within the module, the following
|
||||
environment variables can be used in decreasing order of precedence
|
||||
E(ALICLOUD_ACCESS_KEY) or E(ALICLOUD_ACCESS_KEY_ID),
|
||||
E(ALICLOUD_SECRET_KEY) or E(ALICLOUD_SECRET_ACCESS_KEY),
|
||||
E(ALICLOUD_REGION) or E(ALICLOUD_REGION_ID),
|
||||
E(ALICLOUD_SECURITY_TOKEN),
|
||||
E(ALICLOUD_ECS_ROLE_NAME),
|
||||
E(ALICLOUD_SHARED_CREDENTIALS_FILE),
|
||||
E(ALICLOUD_PROFILE),
|
||||
E(ALICLOUD_ASSUME_ROLE_ARN),
|
||||
E(ALICLOUD_ASSUME_ROLE_SESSION_NAME),
|
||||
E(ALICLOUD_ASSUME_ROLE_SESSION_EXPIRATION).
|
||||
- E(ALICLOUD_REGION) or E(ALICLOUD_REGION_ID) can be typically be used to specify the
|
||||
Alicloud region, when required, but this can also be configured in the footmark config file
|
||||
'''
|
||||
- If parameters are not set within the module, the following environment variables can be used in decreasing order of precedence
|
||||
E(ALICLOUD_ACCESS_KEY) or E(ALICLOUD_ACCESS_KEY_ID), E(ALICLOUD_SECRET_KEY) or E(ALICLOUD_SECRET_ACCESS_KEY), E(ALICLOUD_REGION)
|
||||
or E(ALICLOUD_REGION_ID), E(ALICLOUD_SECURITY_TOKEN), E(ALICLOUD_ECS_ROLE_NAME), E(ALICLOUD_SHARED_CREDENTIALS_FILE),
|
||||
E(ALICLOUD_PROFILE), E(ALICLOUD_ASSUME_ROLE_ARN), E(ALICLOUD_ASSUME_ROLE_SESSION_NAME), E(ALICLOUD_ASSUME_ROLE_SESSION_EXPIRATION).
|
||||
- E(ALICLOUD_REGION) or E(ALICLOUD_REGION_ID) can be typically be used to specify the Alicloud region, when required, but
|
||||
this can also be configured in the footmark config file.
|
||||
"""
|
||||
|
||||
@@ -11,22 +11,22 @@ __metaclass__ = type
|
||||
class ModuleDocFragment(object):
|
||||
|
||||
# Standard documentation fragment
|
||||
DOCUMENTATION = r'''
|
||||
DOCUMENTATION = r"""
|
||||
options: {}
|
||||
attributes:
|
||||
check_mode:
|
||||
description: Can run in C(check_mode) and return changed status prediction without modifying target.
|
||||
diff_mode:
|
||||
description: Will return details on what has changed (or possibly needs changing in C(check_mode)), when in diff mode.
|
||||
'''
|
||||
check_mode:
|
||||
description: Can run in C(check_mode) and return changed status prediction without modifying target.
|
||||
diff_mode:
|
||||
description: Will return details on what has changed (or possibly needs changing in C(check_mode)), when in diff mode.
|
||||
"""
|
||||
|
||||
PLATFORM = r'''
|
||||
PLATFORM = r"""
|
||||
options: {}
|
||||
attributes:
|
||||
platform:
|
||||
description: Target OS/families that can be operated against.
|
||||
support: N/A
|
||||
'''
|
||||
platform:
|
||||
description: Target OS/families that can be operated against.
|
||||
support: N/A
|
||||
"""
|
||||
|
||||
# Should be used together with the standard fragment
|
||||
INFO_MODULE = r'''
|
||||
@@ -42,23 +42,23 @@ attributes:
|
||||
- This action does not modify state.
|
||||
'''
|
||||
|
||||
CONN = r'''
|
||||
CONN = r"""
|
||||
options: {}
|
||||
attributes:
|
||||
become:
|
||||
description: Is usable alongside C(become) keywords.
|
||||
connection:
|
||||
description: Uses the target's configured connection information to execute code on it.
|
||||
delegation:
|
||||
description: Can be used in conjunction with C(delegate_to) and related keywords.
|
||||
'''
|
||||
become:
|
||||
description: Is usable alongside C(become) keywords.
|
||||
connection:
|
||||
description: Uses the target's configured connection information to execute code on it.
|
||||
delegation:
|
||||
description: Can be used in conjunction with C(delegate_to) and related keywords.
|
||||
"""
|
||||
|
||||
FACTS = r'''
|
||||
FACTS = r"""
|
||||
options: {}
|
||||
attributes:
|
||||
facts:
|
||||
description: Action returns an C(ansible_facts) dictionary that will update existing host facts.
|
||||
'''
|
||||
facts:
|
||||
description: Action returns an C(ansible_facts) dictionary that will update existing host facts.
|
||||
"""
|
||||
|
||||
# Should be used together with the standard fragment and the FACTS fragment
|
||||
FACTS_MODULE = r'''
|
||||
@@ -76,18 +76,18 @@ attributes:
|
||||
support: full
|
||||
'''
|
||||
|
||||
FILES = r'''
|
||||
FILES = r"""
|
||||
options: {}
|
||||
attributes:
|
||||
safe_file_operations:
|
||||
description: Uses Ansible's strict file operation functions to ensure proper permissions and avoid data corruption.
|
||||
'''
|
||||
safe_file_operations:
|
||||
description: Uses Ansible's strict file operation functions to ensure proper permissions and avoid data corruption.
|
||||
"""
|
||||
|
||||
FLOW = r'''
|
||||
FLOW = r"""
|
||||
options: {}
|
||||
attributes:
|
||||
action:
|
||||
description: Indicates this has a corresponding action plugin so some parts of the options can be executed on the controller.
|
||||
async:
|
||||
description: Supports being used with the C(async) keyword.
|
||||
'''
|
||||
action:
|
||||
description: Indicates this has a corresponding action plugin so some parts of the options can be executed on the controller.
|
||||
async:
|
||||
description: Supports being used with the C(async) keyword.
|
||||
"""
|
||||
|
||||
@@ -10,7 +10,7 @@ __metaclass__ = type
|
||||
class ModuleDocFragment(object):
|
||||
|
||||
# Standard files documentation fragment
|
||||
DOCUMENTATION = r'''
|
||||
DOCUMENTATION = r"""
|
||||
options:
|
||||
api_url:
|
||||
description:
|
||||
@@ -29,4 +29,4 @@ options:
|
||||
- Whether or not to validate SSL certs when supplying a HTTPS endpoint.
|
||||
type: bool
|
||||
default: true
|
||||
'''
|
||||
"""
|
||||
|
||||
@@ -11,7 +11,7 @@ __metaclass__ = type
|
||||
class ModuleDocFragment(object):
|
||||
|
||||
# Standard documentation fragment
|
||||
DOCUMENTATION = r'''
|
||||
DOCUMENTATION = r"""
|
||||
options:
|
||||
client_id:
|
||||
description:
|
||||
@@ -30,7 +30,7 @@ options:
|
||||
- O(ignore:username) is an alias of O(user) since community.general 6.0.0. It was an alias of O(workspace) before.
|
||||
type: str
|
||||
version_added: 4.0.0
|
||||
aliases: [ username ]
|
||||
aliases: [username]
|
||||
password:
|
||||
description:
|
||||
- The App password.
|
||||
@@ -41,4 +41,4 @@ notes:
|
||||
- Bitbucket OAuth consumer key and secret can be obtained from Bitbucket profile -> Settings -> Access Management -> OAuth.
|
||||
- Bitbucket App password can be created from Bitbucket profile -> Personal Settings -> App passwords.
|
||||
- If both OAuth and Basic Auth credentials are passed, OAuth credentials take precedence.
|
||||
'''
|
||||
"""
|
||||
|
||||
@@ -15,7 +15,7 @@ class ModuleDocFragment:
|
||||
options:
|
||||
host:
|
||||
description:
|
||||
- Host of the consul agent, defaults to V(localhost).
|
||||
- Host of the Consul agent.
|
||||
default: localhost
|
||||
type: str
|
||||
port:
|
||||
@@ -25,18 +25,18 @@ options:
|
||||
default: 8500
|
||||
scheme:
|
||||
description:
|
||||
- The protocol scheme on which the consul agent is running.
|
||||
Defaults to V(http) and can be set to V(https) for secure connections.
|
||||
- The protocol scheme on which the Consul agent is running. Defaults to V(http) and can be set to V(https) for secure
|
||||
connections.
|
||||
default: http
|
||||
type: str
|
||||
validate_certs:
|
||||
type: bool
|
||||
description:
|
||||
- Whether to verify the TLS certificate of the consul agent.
|
||||
- Whether to verify the TLS certificate of the Consul agent.
|
||||
default: true
|
||||
ca_path:
|
||||
description:
|
||||
- The CA bundle to use for https connections
|
||||
- The CA bundle to use for https connections.
|
||||
type: str
|
||||
"""
|
||||
|
||||
|
||||
@@ -14,8 +14,7 @@ __metaclass__ = type
|
||||
class ModuleDocFragment(object):
|
||||
|
||||
# Dimension Data doc fragment
|
||||
DOCUMENTATION = r'''
|
||||
|
||||
DOCUMENTATION = r"""
|
||||
options:
|
||||
region:
|
||||
description:
|
||||
@@ -48,4 +47,4 @@ options:
|
||||
- This should only be used on private instances of the CloudControl API that use self-signed certificates.
|
||||
type: bool
|
||||
default: true
|
||||
'''
|
||||
"""
|
||||
|
||||
@@ -14,8 +14,7 @@ __metaclass__ = type
|
||||
class ModuleDocFragment(object):
|
||||
|
||||
# Dimension Data ("wait-for-completion" parameters) doc fragment
|
||||
DOCUMENTATION = r'''
|
||||
|
||||
DOCUMENTATION = r"""
|
||||
options:
|
||||
wait:
|
||||
description:
|
||||
@@ -34,4 +33,4 @@ options:
|
||||
- Only applicable if O(wait=true).
|
||||
type: int
|
||||
default: 2
|
||||
'''
|
||||
"""
|
||||
|
||||
@@ -8,7 +8,7 @@ __metaclass__ = type
|
||||
|
||||
|
||||
class ModuleDocFragment(object):
|
||||
DOCUMENTATION = r'''
|
||||
DOCUMENTATION = r"""
|
||||
options:
|
||||
venv:
|
||||
description:
|
||||
@@ -43,20 +43,19 @@ options:
|
||||
|
||||
notes:
|
||||
- The C(django-admin) command is always executed using the C(C) locale, and the option C(--no-color) is always passed.
|
||||
|
||||
seealso:
|
||||
- name: django-admin and manage.py in official Django documentation
|
||||
description: >-
|
||||
Refer to this documentation for the builtin commands and options of C(django-admin).
|
||||
Please make sure that you select the right version of Django in the version selector on that page.
|
||||
Refer to this documentation for the builtin commands and options of C(django-admin). Please make sure that you select
|
||||
the right version of Django in the version selector on that page.
|
||||
link: https://docs.djangoproject.com/en/5.0/ref/django-admin/
|
||||
'''
|
||||
"""
|
||||
|
||||
DATABASE = r'''
|
||||
DATABASE = r"""
|
||||
options:
|
||||
database:
|
||||
description:
|
||||
- Specify the database to be used.
|
||||
type: str
|
||||
default: default
|
||||
'''
|
||||
"""
|
||||
|
||||
@@ -10,15 +10,6 @@ __metaclass__ = type
|
||||
|
||||
class ModuleDocFragment(object):
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
options:
|
||||
- See respective platform section for more details
|
||||
requirements:
|
||||
- See respective platform section for more details
|
||||
notes:
|
||||
- Ansible modules are available for EMC VNX.
|
||||
'''
|
||||
|
||||
# Documentation fragment for VNX (emc_vnx)
|
||||
EMC_VNX = r'''
|
||||
options:
|
||||
|
||||
@@ -10,7 +10,7 @@ __metaclass__ = type
|
||||
class ModuleDocFragment(object):
|
||||
|
||||
# Standard files documentation fragment
|
||||
DOCUMENTATION = r'''
|
||||
DOCUMENTATION = r"""
|
||||
requirements:
|
||||
- requests (Python library U(https://pypi.org/project/requests/))
|
||||
|
||||
@@ -34,4 +34,4 @@ options:
|
||||
- The CA certificates bundle to use to verify GitLab server certificate.
|
||||
type: str
|
||||
version_added: 8.1.0
|
||||
'''
|
||||
"""
|
||||
|
||||
@@ -10,26 +10,26 @@ __metaclass__ = type
|
||||
class ModuleDocFragment(object):
|
||||
|
||||
# HPE 3PAR doc fragment
|
||||
DOCUMENTATION = '''
|
||||
DOCUMENTATION = r"""
|
||||
options:
|
||||
storage_system_ip:
|
||||
description:
|
||||
- The storage system IP address.
|
||||
type: str
|
||||
required: true
|
||||
storage_system_password:
|
||||
description:
|
||||
- The storage system password.
|
||||
type: str
|
||||
required: true
|
||||
storage_system_username:
|
||||
description:
|
||||
- The storage system user name.
|
||||
type: str
|
||||
required: true
|
||||
storage_system_ip:
|
||||
description:
|
||||
- The storage system IP address.
|
||||
type: str
|
||||
required: true
|
||||
storage_system_password:
|
||||
description:
|
||||
- The storage system password.
|
||||
type: str
|
||||
required: true
|
||||
storage_system_username:
|
||||
description:
|
||||
- The storage system user name.
|
||||
type: str
|
||||
required: true
|
||||
|
||||
requirements:
|
||||
- hpe3par_sdk >= 1.0.2. Install using C(pip install hpe3par_sdk).
|
||||
- WSAPI service should be enabled on the 3PAR storage array.
|
||||
notes:
|
||||
'''
|
||||
"""
|
||||
|
||||
@@ -10,56 +10,50 @@ __metaclass__ = type
|
||||
class ModuleDocFragment(object):
|
||||
|
||||
# HWC doc fragment.
|
||||
DOCUMENTATION = '''
|
||||
DOCUMENTATION = r"""
|
||||
options:
|
||||
identity_endpoint:
|
||||
description:
|
||||
- The Identity authentication URL.
|
||||
type: str
|
||||
required: true
|
||||
user:
|
||||
description:
|
||||
- The user name to login with.
|
||||
- Currently only user names are supported, and not user IDs.
|
||||
type: str
|
||||
required: true
|
||||
password:
|
||||
description:
|
||||
- The password to login with.
|
||||
type: str
|
||||
required: true
|
||||
domain:
|
||||
description:
|
||||
- The name of the Domain to scope to (Identity v3).
|
||||
- Currently only domain names are supported, and not domain IDs.
|
||||
type: str
|
||||
required: true
|
||||
project:
|
||||
description:
|
||||
- The name of the Tenant (Identity v2) or Project (Identity v3).
|
||||
- Currently only project names are supported, and not project IDs.
|
||||
type: str
|
||||
required: true
|
||||
region:
|
||||
description:
|
||||
- The region to which the project belongs.
|
||||
type: str
|
||||
id:
|
||||
description:
|
||||
- The ID of resource to be managed.
|
||||
type: str
|
||||
identity_endpoint:
|
||||
description:
|
||||
- The Identity authentication URL.
|
||||
type: str
|
||||
required: true
|
||||
user:
|
||||
description:
|
||||
- The user name to login with.
|
||||
- Currently only user names are supported, and not user IDs.
|
||||
type: str
|
||||
required: true
|
||||
password:
|
||||
description:
|
||||
- The password to login with.
|
||||
type: str
|
||||
required: true
|
||||
domain:
|
||||
description:
|
||||
- The name of the Domain to scope to (Identity v3).
|
||||
- Currently only domain names are supported, and not domain IDs.
|
||||
type: str
|
||||
required: true
|
||||
project:
|
||||
description:
|
||||
- The name of the Tenant (Identity v2) or Project (Identity v3).
|
||||
- Currently only project names are supported, and not project IDs.
|
||||
type: str
|
||||
required: true
|
||||
region:
|
||||
description:
|
||||
- The region to which the project belongs.
|
||||
type: str
|
||||
id:
|
||||
description:
|
||||
- The ID of resource to be managed.
|
||||
type: str
|
||||
notes:
|
||||
- For authentication, you can set identity_endpoint using the
|
||||
E(ANSIBLE_HWC_IDENTITY_ENDPOINT) environment variable.
|
||||
- For authentication, you can set user using the
|
||||
E(ANSIBLE_HWC_USER) environment variable.
|
||||
- For authentication, you can set password using the E(ANSIBLE_HWC_PASSWORD) environment
|
||||
variable.
|
||||
- For authentication, you can set domain using the E(ANSIBLE_HWC_DOMAIN) environment
|
||||
variable.
|
||||
- For authentication, you can set project using the E(ANSIBLE_HWC_PROJECT) environment
|
||||
variable.
|
||||
- For authentication, you can set identity_endpoint using the E(ANSIBLE_HWC_IDENTITY_ENDPOINT) environment variable.
|
||||
- For authentication, you can set user using the E(ANSIBLE_HWC_USER) environment variable.
|
||||
- For authentication, you can set password using the E(ANSIBLE_HWC_PASSWORD) environment variable.
|
||||
- For authentication, you can set domain using the E(ANSIBLE_HWC_DOMAIN) environment variable.
|
||||
- For authentication, you can set project using the E(ANSIBLE_HWC_PROJECT) environment variable.
|
||||
- For authentication, you can set region using the E(ANSIBLE_HWC_REGION) environment variable.
|
||||
- Environment variables values will only be used if the playbook values are
|
||||
not set.
|
||||
'''
|
||||
- Environment variables values will only be used if the playbook values are not set.
|
||||
"""
|
||||
|
||||
@@ -12,26 +12,25 @@ __metaclass__ = type
|
||||
class ModuleDocFragment(object):
|
||||
|
||||
# ibm_storage documentation fragment
|
||||
DOCUMENTATION = r'''
|
||||
DOCUMENTATION = r"""
|
||||
options:
|
||||
username:
|
||||
description:
|
||||
- Management user on the spectrum accelerate storage system.
|
||||
type: str
|
||||
required: true
|
||||
password:
|
||||
description:
|
||||
- Password for username on the spectrum accelerate storage system.
|
||||
type: str
|
||||
required: true
|
||||
endpoints:
|
||||
description:
|
||||
- The hostname or management IP of Spectrum Accelerate storage system.
|
||||
type: str
|
||||
required: true
|
||||
username:
|
||||
description:
|
||||
- Management user on the Spectrum Accelerate storage system.
|
||||
type: str
|
||||
required: true
|
||||
password:
|
||||
description:
|
||||
- Password for username on the Spectrum Accelerate storage system.
|
||||
type: str
|
||||
required: true
|
||||
endpoints:
|
||||
description:
|
||||
- The hostname or management IP of Spectrum Accelerate storage system.
|
||||
type: str
|
||||
required: true
|
||||
notes:
|
||||
- This module requires pyxcli python library.
|
||||
Use C(pip install pyxcli) in order to get pyxcli.
|
||||
- This module requires pyxcli python library. Use C(pip install pyxcli) in order to get pyxcli.
|
||||
requirements:
|
||||
- pyxcli
|
||||
'''
|
||||
"""
|
||||
|
||||
@@ -11,72 +11,72 @@ __metaclass__ = type
|
||||
|
||||
class ModuleDocFragment(object):
|
||||
# Parameters for influxdb modules
|
||||
DOCUMENTATION = r'''
|
||||
DOCUMENTATION = r"""
|
||||
options:
|
||||
hostname:
|
||||
description:
|
||||
- The hostname or IP address on which InfluxDB server is listening.
|
||||
- The hostname or IP address on which InfluxDB server is listening.
|
||||
type: str
|
||||
default: localhost
|
||||
username:
|
||||
description:
|
||||
- Username that will be used to authenticate against InfluxDB server.
|
||||
- Username that will be used to authenticate against InfluxDB server.
|
||||
type: str
|
||||
default: root
|
||||
aliases: [ login_username ]
|
||||
aliases: [login_username]
|
||||
password:
|
||||
description:
|
||||
- Password that will be used to authenticate against InfluxDB server.
|
||||
- Password that will be used to authenticate against InfluxDB server.
|
||||
type: str
|
||||
default: root
|
||||
aliases: [ login_password ]
|
||||
aliases: [login_password]
|
||||
port:
|
||||
description:
|
||||
- The port on which InfluxDB server is listening.
|
||||
- The port on which InfluxDB server is listening.
|
||||
type: int
|
||||
default: 8086
|
||||
path:
|
||||
description:
|
||||
- The path on which InfluxDB server is accessible.
|
||||
- Only available when using python-influxdb >= 5.1.0.
|
||||
- The path on which InfluxDB server is accessible.
|
||||
- Only available when using python-influxdb >= 5.1.0.
|
||||
type: str
|
||||
default: ''
|
||||
version_added: '0.2.0'
|
||||
validate_certs:
|
||||
description:
|
||||
- If set to V(false), the SSL certificates will not be validated.
|
||||
- This should only set to V(false) used on personally controlled sites using self-signed certificates.
|
||||
- If set to V(false), the SSL certificates will not be validated.
|
||||
- This should only set to V(false) used on personally controlled sites using self-signed certificates.
|
||||
type: bool
|
||||
default: true
|
||||
ssl:
|
||||
description:
|
||||
- Use https instead of http to connect to InfluxDB server.
|
||||
- Use https instead of http to connect to InfluxDB server.
|
||||
type: bool
|
||||
default: false
|
||||
timeout:
|
||||
description:
|
||||
- Number of seconds Requests will wait for client to establish a connection.
|
||||
- Number of seconds Requests will wait for client to establish a connection.
|
||||
type: int
|
||||
retries:
|
||||
description:
|
||||
- Number of retries client will try before aborting.
|
||||
- V(0) indicates try until success.
|
||||
- Only available when using python-influxdb >= 4.1.0.
|
||||
- Number of retries client will try before aborting.
|
||||
- V(0) indicates try until success.
|
||||
- Only available when using C(python-influxdb) >= 4.1.0.
|
||||
type: int
|
||||
default: 3
|
||||
use_udp:
|
||||
description:
|
||||
- Use UDP to connect to InfluxDB server.
|
||||
- Use UDP to connect to InfluxDB server.
|
||||
type: bool
|
||||
default: false
|
||||
udp_port:
|
||||
description:
|
||||
- UDP port to connect to InfluxDB server.
|
||||
- UDP port to connect to InfluxDB server.
|
||||
type: int
|
||||
default: 4444
|
||||
proxies:
|
||||
description:
|
||||
- HTTP(S) proxy to use for Requests to connect to InfluxDB server.
|
||||
- HTTP(S) proxy to use for Requests to connect to InfluxDB server.
|
||||
type: dict
|
||||
default: {}
|
||||
'''
|
||||
"""
|
||||
|
||||
@@ -11,61 +11,66 @@ __metaclass__ = type
|
||||
|
||||
class ModuleDocFragment(object):
|
||||
# Parameters for FreeIPA/IPA modules
|
||||
DOCUMENTATION = r'''
|
||||
DOCUMENTATION = r"""
|
||||
options:
|
||||
ipa_port:
|
||||
description:
|
||||
- Port of FreeIPA / IPA server.
|
||||
- If the value is not specified in the task, the value of environment variable E(IPA_PORT) will be used instead.
|
||||
- If both the environment variable E(IPA_PORT) and the value are not specified in the task, then default value is set.
|
||||
- Port of FreeIPA / IPA server.
|
||||
- If the value is not specified in the task, the value of environment variable E(IPA_PORT) will be used instead.
|
||||
- If both the environment variable E(IPA_PORT) and the value are not specified in the task, then default value is set.
|
||||
type: int
|
||||
default: 443
|
||||
ipa_host:
|
||||
description:
|
||||
- IP or hostname of IPA server.
|
||||
- If the value is not specified in the task, the value of environment variable E(IPA_HOST) will be used instead.
|
||||
- If both the environment variable E(IPA_HOST) and the value are not specified in the task, then DNS will be used to try to discover the FreeIPA server.
|
||||
- The relevant entry needed in FreeIPA is the C(ipa-ca) entry.
|
||||
- If neither the DNS entry, nor the environment E(IPA_HOST), nor the value are available in the task, then the default value will be used.
|
||||
- IP or hostname of IPA server.
|
||||
- If the value is not specified in the task, the value of environment variable E(IPA_HOST) will be used instead.
|
||||
- If both the environment variable E(IPA_HOST) and the value are not specified in the task, then DNS will be used to
|
||||
try to discover the FreeIPA server.
|
||||
- The relevant entry needed in FreeIPA is the C(ipa-ca) entry.
|
||||
- If neither the DNS entry, nor the environment E(IPA_HOST), nor the value are available in the task, then the default
|
||||
value will be used.
|
||||
type: str
|
||||
default: ipa.example.com
|
||||
ipa_user:
|
||||
description:
|
||||
- Administrative account used on IPA server.
|
||||
- If the value is not specified in the task, the value of environment variable E(IPA_USER) will be used instead.
|
||||
- If both the environment variable E(IPA_USER) and the value are not specified in the task, then default value is set.
|
||||
- Administrative account used on IPA server.
|
||||
- If the value is not specified in the task, the value of environment variable E(IPA_USER) will be used instead.
|
||||
- If both the environment variable E(IPA_USER) and the value are not specified in the task, then default value is set.
|
||||
type: str
|
||||
default: admin
|
||||
ipa_pass:
|
||||
description:
|
||||
- Password of administrative user.
|
||||
- If the value is not specified in the task, the value of environment variable E(IPA_PASS) will be used instead.
|
||||
- Note that if the C(urllib_gssapi) library is available, it is possible to use GSSAPI to authenticate to FreeIPA.
|
||||
- If the environment variable E(KRB5CCNAME) is available, the module will use this kerberos credentials cache to authenticate to the FreeIPA server.
|
||||
- If the environment variable E(KRB5_CLIENT_KTNAME) is available, and E(KRB5CCNAME) is not; the module will use this kerberos keytab to authenticate.
|
||||
- If GSSAPI is not available, the usage of O(ipa_pass) is required.
|
||||
- Password of administrative user.
|
||||
- If the value is not specified in the task, the value of environment variable E(IPA_PASS) will be used instead.
|
||||
- Note that if the C(urllib_gssapi) library is available, it is possible to use GSSAPI to authenticate to FreeIPA.
|
||||
- If the environment variable E(KRB5CCNAME) is available, the module will use this kerberos credentials cache to authenticate
|
||||
to the FreeIPA server.
|
||||
- If the environment variable E(KRB5_CLIENT_KTNAME) is available, and E(KRB5CCNAME) is not; the module will use this
|
||||
kerberos keytab to authenticate.
|
||||
- If GSSAPI is not available, the usage of O(ipa_pass) is required.
|
||||
type: str
|
||||
ipa_prot:
|
||||
description:
|
||||
- Protocol used by IPA server.
|
||||
- If the value is not specified in the task, the value of environment variable E(IPA_PROT) will be used instead.
|
||||
- If both the environment variable E(IPA_PROT) and the value are not specified in the task, then default value is set.
|
||||
- Protocol used by IPA server.
|
||||
- If the value is not specified in the task, the value of environment variable E(IPA_PROT) will be used instead.
|
||||
- If both the environment variable E(IPA_PROT) and the value are not specified in the task, then default value is set.
|
||||
type: str
|
||||
choices: [ http, https ]
|
||||
choices: [http, https]
|
||||
default: https
|
||||
validate_certs:
|
||||
description:
|
||||
- This only applies if O(ipa_prot) is V(https).
|
||||
- If set to V(false), the SSL certificates will not be validated.
|
||||
- This should only set to V(false) used on personally controlled sites using self-signed certificates.
|
||||
- This only applies if O(ipa_prot) is V(https).
|
||||
- If set to V(false), the SSL certificates will not be validated.
|
||||
- This should only set to V(false) used on personally controlled sites using self-signed certificates.
|
||||
type: bool
|
||||
default: true
|
||||
ipa_timeout:
|
||||
description:
|
||||
- Specifies idle timeout (in seconds) for the connection.
|
||||
- For bulk operations, you may want to increase this in order to avoid timeout from IPA server.
|
||||
- If the value is not specified in the task, the value of environment variable E(IPA_TIMEOUT) will be used instead.
|
||||
- If both the environment variable E(IPA_TIMEOUT) and the value are not specified in the task, then default value is set.
|
||||
- Specifies idle timeout (in seconds) for the connection.
|
||||
- For bulk operations, you may want to increase this in order to avoid timeout from IPA server.
|
||||
- If the value is not specified in the task, the value of environment variable E(IPA_TIMEOUT) will be used instead.
|
||||
- If both the environment variable E(IPA_TIMEOUT) and the value are not specified in the task, then default value is
|
||||
set.
|
||||
type: int
|
||||
default: 10
|
||||
'''
|
||||
"""
|
||||
|
||||
@@ -11,69 +11,79 @@ __metaclass__ = type
|
||||
class ModuleDocFragment(object):
|
||||
|
||||
# Standard documentation fragment
|
||||
DOCUMENTATION = r'''
|
||||
DOCUMENTATION = r"""
|
||||
options:
|
||||
auth_keycloak_url:
|
||||
description:
|
||||
- URL to the Keycloak instance.
|
||||
type: str
|
||||
required: true
|
||||
aliases:
|
||||
- url
|
||||
auth_keycloak_url:
|
||||
description:
|
||||
- URL to the Keycloak instance.
|
||||
type: str
|
||||
required: true
|
||||
aliases:
|
||||
- url
|
||||
|
||||
auth_client_id:
|
||||
description:
|
||||
- OpenID Connect C(client_id) to authenticate to the API with.
|
||||
type: str
|
||||
default: admin-cli
|
||||
auth_client_id:
|
||||
description:
|
||||
- OpenID Connect C(client_id) to authenticate to the API with.
|
||||
type: str
|
||||
default: admin-cli
|
||||
|
||||
auth_realm:
|
||||
description:
|
||||
- Keycloak realm name to authenticate to for API access.
|
||||
type: str
|
||||
auth_realm:
|
||||
description:
|
||||
- Keycloak realm name to authenticate to for API access.
|
||||
type: str
|
||||
|
||||
auth_client_secret:
|
||||
description:
|
||||
- Client Secret to use in conjunction with O(auth_client_id) (if required).
|
||||
type: str
|
||||
auth_client_secret:
|
||||
description:
|
||||
- Client Secret to use in conjunction with O(auth_client_id) (if required).
|
||||
type: str
|
||||
|
||||
auth_username:
|
||||
description:
|
||||
- Username to authenticate for API access with.
|
||||
type: str
|
||||
aliases:
|
||||
- username
|
||||
auth_username:
|
||||
description:
|
||||
- Username to authenticate for API access with.
|
||||
type: str
|
||||
aliases:
|
||||
- username
|
||||
|
||||
auth_password:
|
||||
description:
|
||||
- Password to authenticate for API access with.
|
||||
type: str
|
||||
aliases:
|
||||
- password
|
||||
auth_password:
|
||||
description:
|
||||
- Password to authenticate for API access with.
|
||||
type: str
|
||||
aliases:
|
||||
- password
|
||||
|
||||
token:
|
||||
description:
|
||||
- Authentication token for Keycloak API.
|
||||
type: str
|
||||
version_added: 3.0.0
|
||||
token:
|
||||
description:
|
||||
- Authentication token for Keycloak API.
|
||||
type: str
|
||||
version_added: 3.0.0
|
||||
|
||||
validate_certs:
|
||||
description:
|
||||
- Verify TLS certificates (do not disable this in production).
|
||||
type: bool
|
||||
default: true
|
||||
validate_certs:
|
||||
description:
|
||||
- Verify TLS certificates (do not disable this in production).
|
||||
type: bool
|
||||
default: true
|
||||
|
||||
connection_timeout:
|
||||
description:
|
||||
- Controls the HTTP connections timeout period (in seconds) to Keycloak API.
|
||||
type: int
|
||||
default: 10
|
||||
version_added: 4.5.0
|
||||
connection_timeout:
|
||||
description:
|
||||
- Controls the HTTP connections timeout period (in seconds) to Keycloak API.
|
||||
type: int
|
||||
default: 10
|
||||
version_added: 4.5.0
|
||||
|
||||
http_agent:
|
||||
description:
|
||||
- Configures the HTTP User-Agent header.
|
||||
type: str
|
||||
default: Ansible
|
||||
version_added: 5.4.0
|
||||
'''
|
||||
http_agent:
|
||||
description:
|
||||
- Configures the HTTP User-Agent header.
|
||||
type: str
|
||||
default: Ansible
|
||||
version_added: 5.4.0
|
||||
"""
|
||||
|
||||
ACTIONGROUP_KEYCLOAK = r"""
|
||||
options: {}
|
||||
attributes:
|
||||
action_group:
|
||||
description: Use C(group/community.general.keycloak) in C(module_defaults) to set defaults for this module.
|
||||
support: full
|
||||
membership:
|
||||
- community.general.keycloak
|
||||
"""
|
||||
|
||||
@@ -12,12 +12,16 @@ __metaclass__ = type
|
||||
|
||||
class ModuleDocFragment(object):
|
||||
# Standard LDAP documentation fragment
|
||||
DOCUMENTATION = r'''
|
||||
DOCUMENTATION = r"""
|
||||
notes:
|
||||
- The default authentication settings will attempt to use a SASL EXTERNAL bind over a UNIX domain socket. This works well with the default Ubuntu
|
||||
install for example, which includes a C(cn=peercred,cn=external,cn=auth) ACL rule allowing root to modify the server configuration. If you need
|
||||
to use a simple bind to access your server, pass the credentials in O(bind_dn) and O(bind_pw).
|
||||
options:
|
||||
bind_dn:
|
||||
description:
|
||||
- A DN to bind with. If this is omitted, we'll try a SASL bind with the EXTERNAL mechanism as default.
|
||||
- If this is blank, we'll use an anonymous bind.
|
||||
- A DN to bind with. Try to use a SASL bind with the EXTERNAL mechanism as default when this parameter is omitted.
|
||||
- Use an anonymous bind if the parameter is blank.
|
||||
type: str
|
||||
bind_pw:
|
||||
description:
|
||||
@@ -57,7 +61,8 @@ options:
|
||||
version_added: 2.0.0
|
||||
server_uri:
|
||||
description:
|
||||
- The O(server_uri) parameter may be a comma- or whitespace-separated list of URIs containing only the schema, the host, and the port fields.
|
||||
- The O(server_uri) parameter may be a comma- or whitespace-separated list of URIs containing only the schema, the host,
|
||||
and the port fields.
|
||||
- The default value lets the underlying LDAP client library look for a UNIX domain socket in its default location.
|
||||
- Note that when using multiple URIs you cannot determine to which URI your client gets connected.
|
||||
- For URIs containing additional fields, particularly when using commas, behavior is undefined.
|
||||
@@ -65,7 +70,7 @@ options:
|
||||
default: ldapi:///
|
||||
start_tls:
|
||||
description:
|
||||
- If true, we'll use the START_TLS LDAP extension.
|
||||
- Use the START_TLS LDAP extension if set to V(true).
|
||||
type: bool
|
||||
default: false
|
||||
validate_certs:
|
||||
@@ -91,4 +96,4 @@ options:
|
||||
choices: ['enable', 'auto', 'disable']
|
||||
default: auto
|
||||
version_added: "6.4.0"
|
||||
'''
|
||||
"""
|
||||
|
||||
@@ -10,7 +10,7 @@ __metaclass__ = type
|
||||
|
||||
class ModuleDocFragment(object):
|
||||
# Standard Pylxca documentation fragment
|
||||
DOCUMENTATION = r'''
|
||||
DOCUMENTATION = r"""
|
||||
author:
|
||||
- Naval Patel (@navalkp)
|
||||
- Prashant Bhosale (@prabhosa)
|
||||
@@ -18,19 +18,19 @@ author:
|
||||
options:
|
||||
login_user:
|
||||
description:
|
||||
- The username for use in HTTP basic authentication.
|
||||
- The username for use in HTTP basic authentication.
|
||||
type: str
|
||||
required: true
|
||||
|
||||
login_password:
|
||||
description:
|
||||
- The password for use in HTTP basic authentication.
|
||||
- The password for use in HTTP basic authentication.
|
||||
type: str
|
||||
required: true
|
||||
|
||||
auth_url:
|
||||
description:
|
||||
- lxca HTTPS full web address.
|
||||
- Lxca HTTPS full web address.
|
||||
type: str
|
||||
required: true
|
||||
|
||||
@@ -40,4 +40,4 @@ requirements:
|
||||
notes:
|
||||
- Additional detail about pylxca can be found at U(https://github.com/lenovo/pylxca).
|
||||
- Playbooks using these modules can be found at U(https://github.com/lenovo/ansible.lenovo-lxca).
|
||||
'''
|
||||
"""
|
||||
|
||||
@@ -11,7 +11,7 @@ __metaclass__ = type
|
||||
class ModuleDocFragment(object):
|
||||
|
||||
# Standard ManageIQ documentation fragment
|
||||
DOCUMENTATION = r'''
|
||||
DOCUMENTATION = r"""
|
||||
options:
|
||||
manageiq_connection:
|
||||
description:
|
||||
@@ -34,20 +34,21 @@ options:
|
||||
type: str
|
||||
token:
|
||||
description:
|
||||
- ManageIQ token. E(MIQ_TOKEN) environment variable if set. Otherwise, required if no username or password is passed in.
|
||||
- ManageIQ token. E(MIQ_TOKEN) environment variable if set. Otherwise, required if no username or password is passed
|
||||
in.
|
||||
type: str
|
||||
validate_certs:
|
||||
description:
|
||||
- Whether SSL certificates should be verified for HTTPS requests.
|
||||
type: bool
|
||||
default: true
|
||||
aliases: [ verify_ssl ]
|
||||
aliases: [verify_ssl]
|
||||
ca_cert:
|
||||
description:
|
||||
- The path to a CA bundle file or directory with certificates.
|
||||
type: str
|
||||
aliases: [ ca_bundle_path ]
|
||||
aliases: [ca_bundle_path]
|
||||
|
||||
requirements:
|
||||
- 'manageiq-client U(https://github.com/ManageIQ/manageiq-api-client-python/)'
|
||||
'''
|
||||
"""
|
||||
|
||||
@@ -11,48 +11,48 @@ __metaclass__ = type
|
||||
class ModuleDocFragment(object):
|
||||
|
||||
# Standard files documentation fragment
|
||||
DOCUMENTATION = r'''
|
||||
DOCUMENTATION = r"""
|
||||
options:
|
||||
host:
|
||||
description:
|
||||
- FQDN of Nomad server.
|
||||
required: true
|
||||
type: str
|
||||
port:
|
||||
description:
|
||||
- Port of Nomad server.
|
||||
type: int
|
||||
default: 4646
|
||||
version_added: 8.0.0
|
||||
use_ssl:
|
||||
description:
|
||||
- Use TLS/SSL connection.
|
||||
type: bool
|
||||
default: true
|
||||
timeout:
|
||||
description:
|
||||
- Timeout (in seconds) for the request to Nomad.
|
||||
type: int
|
||||
default: 5
|
||||
validate_certs:
|
||||
description:
|
||||
- Enable TLS/SSL certificate validation.
|
||||
type: bool
|
||||
default: true
|
||||
client_cert:
|
||||
description:
|
||||
- Path of certificate for TLS/SSL.
|
||||
type: path
|
||||
client_key:
|
||||
description:
|
||||
- Path of certificate's private key for TLS/SSL.
|
||||
type: path
|
||||
namespace:
|
||||
description:
|
||||
- Namespace for Nomad.
|
||||
type: str
|
||||
token:
|
||||
description:
|
||||
- ACL token for authentication.
|
||||
type: str
|
||||
'''
|
||||
host:
|
||||
description:
|
||||
- FQDN of Nomad server.
|
||||
required: true
|
||||
type: str
|
||||
port:
|
||||
description:
|
||||
- Port of Nomad server.
|
||||
type: int
|
||||
default: 4646
|
||||
version_added: 8.0.0
|
||||
use_ssl:
|
||||
description:
|
||||
- Use TLS/SSL connection.
|
||||
type: bool
|
||||
default: true
|
||||
timeout:
|
||||
description:
|
||||
- Timeout (in seconds) for the request to Nomad.
|
||||
type: int
|
||||
default: 5
|
||||
validate_certs:
|
||||
description:
|
||||
- Enable TLS/SSL certificate validation.
|
||||
type: bool
|
||||
default: true
|
||||
client_cert:
|
||||
description:
|
||||
- Path of certificate for TLS/SSL.
|
||||
type: path
|
||||
client_key:
|
||||
description:
|
||||
- Path of certificate's private key for TLS/SSL.
|
||||
type: path
|
||||
namespace:
|
||||
description:
|
||||
- Namespace for Nomad.
|
||||
type: str
|
||||
token:
|
||||
description:
|
||||
- ACL token for authentication.
|
||||
type: str
|
||||
"""
|
||||
|
||||
@@ -10,16 +10,6 @@ __metaclass__ = type
|
||||
|
||||
class ModuleDocFragment(object):
|
||||
|
||||
# Standard Pure Storage documentation fragment
|
||||
DOCUMENTATION = r"""
|
||||
options: {}
|
||||
# See separate platform section for more details
|
||||
requirements:
|
||||
- See separate platform section for more details
|
||||
notes:
|
||||
- 'Ansible modules are available for the following Pure Storage products: FlashArray, FlashBlade.'
|
||||
"""
|
||||
|
||||
# Documentation fragment for FlashBlade
|
||||
FB = r"""
|
||||
options:
|
||||
|
||||
@@ -10,15 +10,6 @@ __metaclass__ = type
|
||||
|
||||
class ModuleDocFragment(object):
|
||||
|
||||
DOCUMENTATION = r"""
|
||||
options: {}
|
||||
# See respective platform section for more details
|
||||
requirements:
|
||||
- See respective platform section for more details
|
||||
notes:
|
||||
- Ansible modules are available for Vexata VX100 arrays.
|
||||
"""
|
||||
|
||||
# Documentation fragment for Vexata VX100 series
|
||||
VX100 = r'''
|
||||
options:
|
||||
|
||||
62
plugins/filter/accumulate.py
Normal file
62
plugins/filter/accumulate.py
Normal file
@@ -0,0 +1,62 @@
|
||||
# Copyright (c) Max Gautier <mg@max.gautier.name>
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
DOCUMENTATION = '''
|
||||
name: accumulate
|
||||
short_description: Produce a list of accumulated sums of the input list contents
|
||||
version_added: 10.1.0
|
||||
author: Max Gautier (@VannTen)
|
||||
description:
|
||||
- Passthrough to the L(Python itertools.accumulate function,https://docs.python.org/3/library/itertools.html#itertools.accumulate).
|
||||
- Transforms an input list into the cumulative list of results from applying addition to the elements of the input list.
|
||||
- Addition means the default Python implementation of C(+) for input list elements type.
|
||||
options:
|
||||
_input:
|
||||
description: A list.
|
||||
type: list
|
||||
elements: any
|
||||
required: true
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
_value:
|
||||
description: A list of cumulated sums of the elements of the input list.
|
||||
type: list
|
||||
elements: any
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Enumerate parent directories of some path
|
||||
ansible.builtin.debug:
|
||||
var: >
|
||||
"/some/path/to/my/file"
|
||||
| split('/') | map('split', '/')
|
||||
| community.general.accumulate | map('join', '/')
|
||||
# Produces: ['', '/some', '/some/path', '/some/path/to', '/some/path/to/my', '/some/path/to/my/file']
|
||||
- name: Growing string
|
||||
ansible.builtin.debug:
|
||||
var: "'abc' | community.general.accumulate"
|
||||
# Produces ['a', 'ab', 'abc']
|
||||
'''
|
||||
|
||||
from itertools import accumulate
|
||||
from collections.abc import Sequence
|
||||
|
||||
from ansible.errors import AnsibleFilterError
|
||||
|
||||
|
||||
def list_accumulate(sequence):
|
||||
if not isinstance(sequence, Sequence):
|
||||
raise AnsibleFilterError('Invalid value type (%s) for accumulate (%r)' %
|
||||
(type(sequence), sequence))
|
||||
|
||||
return accumulate(sequence)
|
||||
|
||||
|
||||
class FilterModule(object):
|
||||
|
||||
def filters(self):
|
||||
return {
|
||||
'accumulate': list_accumulate,
|
||||
}
|
||||
@@ -81,7 +81,6 @@ RETURN = '''
|
||||
'''
|
||||
|
||||
from ansible.errors import AnsibleFilterError
|
||||
from ansible.module_utils.common.text.converters import to_native
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.csv import (initialize_dialect, read_csv, CSVError,
|
||||
DialectNotAvailableError,
|
||||
@@ -99,7 +98,7 @@ def from_csv(data, dialect='excel', fieldnames=None, delimiter=None, skipinitial
|
||||
try:
|
||||
dialect = initialize_dialect(dialect, **dialect_params)
|
||||
except (CustomDialectFailureError, DialectNotAvailableError) as e:
|
||||
raise AnsibleFilterError(to_native(e))
|
||||
raise AnsibleFilterError(str(e))
|
||||
|
||||
reader = read_csv(data, dialect, fieldnames)
|
||||
|
||||
@@ -109,7 +108,7 @@ def from_csv(data, dialect='excel', fieldnames=None, delimiter=None, skipinitial
|
||||
for row in reader:
|
||||
data_list.append(row)
|
||||
except CSVError as e:
|
||||
raise AnsibleFilterError("Unable to process file: %s" % to_native(e))
|
||||
raise AnsibleFilterError(f"Unable to process file: {e}")
|
||||
|
||||
return data_list
|
||||
|
||||
|
||||
@@ -50,7 +50,6 @@ from ansible.errors import AnsibleFilterError
|
||||
from ansible.module_utils.six import string_types
|
||||
from ansible.module_utils.six.moves import StringIO
|
||||
from ansible.module_utils.six.moves.configparser import ConfigParser
|
||||
from ansible.module_utils.common.text.converters import to_native
|
||||
|
||||
|
||||
class IniParser(ConfigParser):
|
||||
@@ -83,8 +82,7 @@ def from_ini(obj):
|
||||
try:
|
||||
parser.read_file(StringIO(obj))
|
||||
except Exception as ex:
|
||||
raise AnsibleFilterError(f'from_ini failed to parse given string: '
|
||||
f'{to_native(ex)}', orig_exc=ex)
|
||||
raise AnsibleFilterError(f'from_ini failed to parse given string: {ex}', orig_exc=ex)
|
||||
|
||||
return parser.as_dict()
|
||||
|
||||
|
||||
@@ -10,16 +10,12 @@ __metaclass__ = type
|
||||
from ansible.errors import (
|
||||
AnsibleError,
|
||||
AnsibleFilterError,
|
||||
AnsibleFilterTypeError,
|
||||
)
|
||||
|
||||
from ansible.module_utils.common.text.converters import to_native
|
||||
from ansible.module_utils.common.collections import is_sequence
|
||||
|
||||
try:
|
||||
from ansible.errors import AnsibleTypeError
|
||||
except ImportError:
|
||||
from ansible.errors import AnsibleFilterTypeError as AnsibleTypeError
|
||||
|
||||
try:
|
||||
from hashids import Hashids
|
||||
HAS_HASHIDS = True
|
||||
@@ -68,7 +64,7 @@ def hashids_encode(nums, salt=None, alphabet=None, min_length=None):
|
||||
try:
|
||||
hashid = hashids.encode(*nums)
|
||||
except TypeError as e:
|
||||
raise AnsibleTypeError(
|
||||
raise AnsibleFilterTypeError(
|
||||
"Data to encode must by a tuple or list of ints: %s" % to_native(e)
|
||||
)
|
||||
|
||||
|
||||
@@ -23,107 +23,93 @@ DOCUMENTATION = '''
|
||||
type: dictionary
|
||||
'''
|
||||
|
||||
EXAMPLES = r"""
|
||||
# Substitution converts str to AnsibleUnicode or _AnsibleTaggedStr
|
||||
# ----------------------------------------------------------------
|
||||
EXAMPLES = '''
|
||||
# Substitution converts str to AnsibleUnicode
|
||||
# -------------------------------------------
|
||||
|
||||
# String. AnsibleUnicode or _AnsibleTaggedStr.
|
||||
- data: "abc"
|
||||
result: '{{ data | community.general.reveal_ansible_type }}'
|
||||
# result => AnsibleUnicode (or _AnsibleTaggedStr)
|
||||
# String. AnsibleUnicode.
|
||||
data: "abc"
|
||||
result: '{{ data | community.general.reveal_ansible_type }}'
|
||||
# result => AnsibleUnicode
|
||||
|
||||
# String. AnsibleUnicode/_AnsibleTaggedStr alias str.
|
||||
- alias: {"AnsibleUnicode": "str", "_AnsibleTaggedStr": "str"}
|
||||
data: "abc"
|
||||
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
|
||||
# String. AnsibleUnicode alias str.
|
||||
alias: {"AnsibleUnicode": "str"}
|
||||
data: "abc"
|
||||
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
|
||||
# result => str
|
||||
|
||||
# List. All items are AnsibleUnicode/_AnsibleTaggedStr.
|
||||
- data: ["a", "b", "c"]
|
||||
result: '{{ data | community.general.reveal_ansible_type }}'
|
||||
# result => list[AnsibleUnicode] or list[_AnsibleTaggedStr]
|
||||
# List. All items are AnsibleUnicode.
|
||||
data: ["a", "b", "c"]
|
||||
result: '{{ data | community.general.reveal_ansible_type }}'
|
||||
# result => list[AnsibleUnicode]
|
||||
|
||||
# Dictionary. All keys and values are AnsibleUnicode/_AnsibleTaggedStr.
|
||||
- data: {"a": "foo", "b": "bar", "c": "baz"}
|
||||
result: '{{ data | community.general.reveal_ansible_type }}'
|
||||
# result => dict[AnsibleUnicode, AnsibleUnicode] or dict[_AnsibleTaggedStr, _AnsibleTaggedStr]
|
||||
# Dictionary. All keys are AnsibleUnicode. All values are AnsibleUnicode.
|
||||
data: {"a": "foo", "b": "bar", "c": "baz"}
|
||||
result: '{{ data | community.general.reveal_ansible_type }}'
|
||||
# result => dict[AnsibleUnicode, AnsibleUnicode]
|
||||
|
||||
# No substitution and no alias. Type of strings is str
|
||||
# ----------------------------------------------------
|
||||
|
||||
# String
|
||||
- result: '{{ "abc" | community.general.reveal_ansible_type }}'
|
||||
result: '{{ "abc" | community.general.reveal_ansible_type }}'
|
||||
# result => str
|
||||
|
||||
# Integer
|
||||
- result: '{{ 123 | community.general.reveal_ansible_type }}'
|
||||
result: '{{ 123 | community.general.reveal_ansible_type }}'
|
||||
# result => int
|
||||
|
||||
# Float
|
||||
- result: '{{ 123.45 | community.general.reveal_ansible_type }}'
|
||||
result: '{{ 123.45 | community.general.reveal_ansible_type }}'
|
||||
# result => float
|
||||
|
||||
# Boolean
|
||||
- result: '{{ true | community.general.reveal_ansible_type }}'
|
||||
result: '{{ true | community.general.reveal_ansible_type }}'
|
||||
# result => bool
|
||||
|
||||
# List. All items are strings.
|
||||
- result: '{{ ["a", "b", "c"] | community.general.reveal_ansible_type }}'
|
||||
result: '{{ ["a", "b", "c"] | community.general.reveal_ansible_type }}'
|
||||
# result => list[str]
|
||||
|
||||
# List of dictionaries.
|
||||
- result: '{{ [{"a": 1}, {"b": 2}] | community.general.reveal_ansible_type }}'
|
||||
result: '{{ [{"a": 1}, {"b": 2}] | community.general.reveal_ansible_type }}'
|
||||
# result => list[dict]
|
||||
|
||||
# Dictionary. All keys are strings. All values are integers.
|
||||
- result: '{{ {"a": 1} | community.general.reveal_ansible_type }}'
|
||||
result: '{{ {"a": 1} | community.general.reveal_ansible_type }}'
|
||||
# result => dict[str, int]
|
||||
|
||||
# Dictionary. All keys are strings. All values are integers.
|
||||
- result: '{{ {"a": 1, "b": 2} | community.general.reveal_ansible_type }}'
|
||||
result: '{{ {"a": 1, "b": 2} | community.general.reveal_ansible_type }}'
|
||||
# result => dict[str, int]
|
||||
|
||||
# Type of strings is AnsibleUnicode, _AnsibleTaggedStr, or str
|
||||
# ------------------------------------------------------------
|
||||
# Type of strings is AnsibleUnicode or str
|
||||
# ----------------------------------------
|
||||
|
||||
# Dictionary. The keys are integers or strings. All values are strings.
|
||||
- alias:
|
||||
AnsibleUnicode: str
|
||||
_AnsibleTaggedStr: str
|
||||
_AnsibleTaggedInt: int
|
||||
data: {1: 'a', 'b': 'b'}
|
||||
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
|
||||
alias: {"AnsibleUnicode": "str"}
|
||||
data: {1: 'a', 'b': 'b'}
|
||||
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
|
||||
# result => dict[int|str, str]
|
||||
|
||||
# Dictionary. All keys are integers. All values are keys.
|
||||
- alias:
|
||||
AnsibleUnicode: str
|
||||
_AnsibleTaggedStr: str
|
||||
_AnsibleTaggedInt: int
|
||||
data: {1: 'a', 2: 'b'}
|
||||
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
|
||||
alias: {"AnsibleUnicode": "str"}
|
||||
data: {1: 'a', 2: 'b'}
|
||||
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
|
||||
# result => dict[int, str]
|
||||
|
||||
# Dictionary. All keys are strings. Multiple types values.
|
||||
- alias:
|
||||
AnsibleUnicode: str
|
||||
_AnsibleTaggedStr: str
|
||||
_AnsibleTaggedInt: int
|
||||
_AnsibleTaggedFloat: float
|
||||
data: {'a': 1, 'b': 1.1, 'c': 'abc', 'd': true, 'e': ['x', 'y', 'z'], 'f': {'x': 1, 'y': 2}}
|
||||
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
|
||||
alias: {"AnsibleUnicode": "str"}
|
||||
data: {'a': 1, 'b': 1.1, 'c': 'abc', 'd': True, 'e': ['x', 'y', 'z'], 'f': {'x': 1, 'y': 2}}
|
||||
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
|
||||
# result => dict[str, bool|dict|float|int|list|str]
|
||||
|
||||
# List. Multiple types items.
|
||||
- alias:
|
||||
AnsibleUnicode: str
|
||||
_AnsibleTaggedStr: str
|
||||
_AnsibleTaggedInt: int
|
||||
_AnsibleTaggedFloat: float
|
||||
data: [1, 2, 1.1, 'abc', true, ['x', 'y', 'z'], {'x': 1, 'y': 2}]
|
||||
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
|
||||
alias: {"AnsibleUnicode": "str"}
|
||||
data: [1, 2, 1.1, 'abc', True, ['x', 'y', 'z'], {'x': 1, 'y': 2}]
|
||||
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
|
||||
# result => list[bool|dict|float|int|list|str]
|
||||
"""
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
_value:
|
||||
@@ -137,7 +123,6 @@ from ansible_collections.community.general.plugins.plugin_utils.ansible_type imp
|
||||
def reveal_ansible_type(data, alias=None):
|
||||
"""Returns data type"""
|
||||
|
||||
# TODO: expose use_native_type parameter
|
||||
return _ansible_type(data, alias)
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
DOCUMENTATION:
|
||||
name: to_days
|
||||
short_description: Converts a duration string to days
|
||||
short_description: Converte a duration string to days
|
||||
version_added: 0.2.0
|
||||
description:
|
||||
- Parse a human readable time duration string and convert to days.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
DOCUMENTATION:
|
||||
name: to_hours
|
||||
short_description: Converts a duration string to hours
|
||||
short_description: Converte a duration string to hours
|
||||
version_added: 0.2.0
|
||||
description:
|
||||
- Parse a human readable time duration string and convert to hours.
|
||||
|
||||
@@ -56,7 +56,6 @@ from ansible.errors import AnsibleFilterError
|
||||
from ansible.module_utils.common._collections_compat import Mapping
|
||||
from ansible.module_utils.six.moves import StringIO
|
||||
from ansible.module_utils.six.moves.configparser import ConfigParser
|
||||
from ansible.module_utils.common.text.converters import to_native
|
||||
|
||||
|
||||
class IniParser(ConfigParser):
|
||||
@@ -79,7 +78,7 @@ def to_ini(obj):
|
||||
ini_parser.read_dict(obj)
|
||||
except Exception as ex:
|
||||
raise AnsibleFilterError('to_ini failed to parse given dict:'
|
||||
f'{to_native(ex)}', orig_exc=ex)
|
||||
f'{ex}', orig_exc=ex)
|
||||
|
||||
# catching empty dicts
|
||||
if obj == dict():
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
DOCUMENTATION:
|
||||
name: to_milliseconds
|
||||
short_description: Converts a duration string to milliseconds
|
||||
short_description: Converte a duration string to milliseconds
|
||||
version_added: 0.2.0
|
||||
description:
|
||||
- Parse a human readable time duration string and convert to milliseconds.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
DOCUMENTATION:
|
||||
name: to_minutes
|
||||
short_description: Converts a duration string to minutes
|
||||
short_description: Converte a duration string to minutes
|
||||
version_added: 0.2.0
|
||||
description:
|
||||
- Parse a human readable time duration string and convert to minutes.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user