mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-04-30 10:26:52 +00:00
Compare commits
150 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c67a5bda9 | ||
|
|
4ae436a8cc | ||
|
|
5f5c07a942 | ||
|
|
1cef1359d0 | ||
|
|
0d28bfb67e | ||
|
|
ef304ed824 | ||
|
|
bf17f289b3 | ||
|
|
0eff87d0be | ||
|
|
f00fabfa48 | ||
|
|
426cbafa06 | ||
|
|
93fe1f9a3e | ||
|
|
4e944772d5 | ||
|
|
50abeee579 | ||
|
|
eccc8d88b6 | ||
|
|
6d2d364a00 | ||
|
|
e781dd3c9b | ||
|
|
362f899a99 | ||
|
|
b44f6b8114 | ||
|
|
53a145ecb0 | ||
|
|
b22b44088f | ||
|
|
e0a1aa2f46 | ||
|
|
53e7e48834 | ||
|
|
62e3a2ed2f | ||
|
|
ecede6ca99 | ||
|
|
e1ac1fa6db | ||
|
|
81cef0bd05 | ||
|
|
a2bb118e95 | ||
|
|
bf9bcd9bb4 | ||
|
|
9bfd61e117 | ||
|
|
ca81a5cf2f | ||
|
|
853dd21eab | ||
|
|
6f267d8f35 | ||
|
|
1f975eff56 | ||
|
|
0ca922248f | ||
|
|
ef7ade6a56 | ||
|
|
d721283846 | ||
|
|
af410f5572 | ||
|
|
442dabbcc6 | ||
|
|
bbb155409e | ||
|
|
a83556af80 | ||
|
|
13a5e5a1ba | ||
|
|
466bd89bd4 | ||
|
|
bd4d5fe9db | ||
|
|
cf889faf42 | ||
|
|
ea313503dd | ||
|
|
57fa6526c4 | ||
|
|
ae4bee2627 | ||
|
|
87000ae491 | ||
|
|
46e221cbc6 | ||
|
|
3f2111582d | ||
|
|
bd8634e04e | ||
|
|
1ae57fc5dd | ||
|
|
1e5e0824d2 | ||
|
|
7eaf795774 | ||
|
|
3dc25edeac | ||
|
|
a67ee6cead | ||
|
|
9c5461dc12 | ||
|
|
0b59a71ae7 | ||
|
|
720de141b5 | ||
|
|
7ec6025690 | ||
|
|
53a5cdaed7 | ||
|
|
693efb35b3 | ||
|
|
07cd51a33b | ||
|
|
c80416164b | ||
|
|
a61bc5ab34 | ||
|
|
8ac8fa0aa9 | ||
|
|
b76994ee6e | ||
|
|
746bd3ea5d | ||
|
|
68baf56ea6 | ||
|
|
87377dd23f | ||
|
|
29f028e33b | ||
|
|
196e8fe4e3 | ||
|
|
83c6d18bc0 | ||
|
|
1314b0d7b2 | ||
|
|
be94a014c8 | ||
|
|
039c3da7dc | ||
|
|
2480250f1b | ||
|
|
860f0e12c0 | ||
|
|
2f56fd7b2a | ||
|
|
084879632a | ||
|
|
4eef56b7b3 | ||
|
|
13929acf02 | ||
|
|
070bcf80c4 | ||
|
|
0cf2a5ad05 | ||
|
|
76a64ea733 | ||
|
|
115eab2cfa | ||
|
|
dbba813e23 | ||
|
|
7daf78962b | ||
|
|
cf9fff5238 | ||
|
|
d8d68babe4 | ||
|
|
3f46cdc588 | ||
|
|
ea530784b8 | ||
|
|
dc2fa05b1f | ||
|
|
b2e51272ad | ||
|
|
afba9a11af | ||
|
|
c3ac479ae2 | ||
|
|
7e367244f7 | ||
|
|
331d2c7651 | ||
|
|
b35a262378 | ||
|
|
7d400663b6 | ||
|
|
0d0884b069 | ||
|
|
dd400e8c21 | ||
|
|
a60f9bc78b | ||
|
|
47714ecf79 | ||
|
|
d15ed4135b | ||
|
|
bd61228e40 | ||
|
|
26d7c28b33 | ||
|
|
2e533daffa | ||
|
|
6c50119eab | ||
|
|
bc3435b993 | ||
|
|
370f5d8082 | ||
|
|
e77c5413c9 | ||
|
|
800ee1bae0 | ||
|
|
8de8d21062 | ||
|
|
81e71b5034 | ||
|
|
44ce63ed85 | ||
|
|
a3c9c688b9 | ||
|
|
a332ed4429 | ||
|
|
91571f8bff | ||
|
|
43856eaa6f | ||
|
|
ae87b5479a | ||
|
|
42cd462780 | ||
|
|
d871378574 | ||
|
|
983b292399 | ||
|
|
6831aa5501 | ||
|
|
2d8a94a459 | ||
|
|
f721e76fdc | ||
|
|
3eadb9d637 | ||
|
|
033582b696 | ||
|
|
974997594f | ||
|
|
fa8ce6dea8 | ||
|
|
1d90e91528 | ||
|
|
a90e2c8002 | ||
|
|
c506375f2a | ||
|
|
4def9439bd | ||
|
|
023654473b | ||
|
|
a216f15dd9 | ||
|
|
f613983cb4 | ||
|
|
c22199794d | ||
|
|
24b1d92e84 | ||
|
|
4bc44e4062 | ||
|
|
06fd6d8742 | ||
|
|
dd0ae4a003 | ||
|
|
646ca74810 | ||
|
|
d60c107818 | ||
|
|
ef2d14f24e | ||
|
|
b3cde9b8a4 | ||
|
|
dc4222df0d | ||
|
|
b9a89d6d0f | ||
|
|
f48913d91b |
@@ -13,25 +13,13 @@ pr:
|
|||||||
- stable-*
|
- stable-*
|
||||||
|
|
||||||
schedules:
|
schedules:
|
||||||
- cron: 0 8 * * *
|
- cron: 0 9 * * *
|
||||||
displayName: Nightly (main)
|
displayName: Nightly
|
||||||
always: true
|
always: true
|
||||||
branches:
|
branches:
|
||||||
include:
|
include:
|
||||||
- main
|
- main
|
||||||
- cron: 0 10 * * *
|
- stable-*
|
||||||
displayName: Nightly (active stable branches)
|
|
||||||
always: true
|
|
||||||
branches:
|
|
||||||
include:
|
|
||||||
- stable-2
|
|
||||||
- stable-3
|
|
||||||
- cron: 0 11 * * 0
|
|
||||||
displayName: Weekly (old stable branches)
|
|
||||||
always: true
|
|
||||||
branches:
|
|
||||||
include:
|
|
||||||
- stable-1
|
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
- name: checkoutPath
|
- name: checkoutPath
|
||||||
@@ -68,19 +56,6 @@ stages:
|
|||||||
- test: 3
|
- test: 3
|
||||||
- test: 4
|
- test: 4
|
||||||
- test: extra
|
- test: extra
|
||||||
- stage: Sanity_2_11
|
|
||||||
displayName: Sanity 2.11
|
|
||||||
dependsOn: []
|
|
||||||
jobs:
|
|
||||||
- template: templates/matrix.yml
|
|
||||||
parameters:
|
|
||||||
nameFormat: Test {0}
|
|
||||||
testFormat: 2.11/sanity/{0}
|
|
||||||
targets:
|
|
||||||
- test: 1
|
|
||||||
- test: 2
|
|
||||||
- test: 3
|
|
||||||
- test: 4
|
|
||||||
- stage: Sanity_2_10
|
- stage: Sanity_2_10
|
||||||
displayName: Sanity 2.10
|
displayName: Sanity 2.10
|
||||||
dependsOn: []
|
dependsOn: []
|
||||||
@@ -124,22 +99,6 @@ stages:
|
|||||||
- test: 3.7
|
- test: 3.7
|
||||||
- test: 3.8
|
- test: 3.8
|
||||||
- test: 3.9
|
- test: 3.9
|
||||||
- stage: Units_2_11
|
|
||||||
displayName: Units 2.11
|
|
||||||
dependsOn: []
|
|
||||||
jobs:
|
|
||||||
- template: templates/matrix.yml
|
|
||||||
parameters:
|
|
||||||
nameFormat: Python {0}
|
|
||||||
testFormat: 2.11/units/{0}/1
|
|
||||||
targets:
|
|
||||||
- test: 2.6
|
|
||||||
- test: 2.7
|
|
||||||
- test: 3.5
|
|
||||||
- test: 3.6
|
|
||||||
- test: 3.7
|
|
||||||
- test: 3.8
|
|
||||||
- test: 3.9
|
|
||||||
- stage: Units_2_10
|
- stage: Units_2_10
|
||||||
displayName: Units 2.10
|
displayName: Units 2.10
|
||||||
dependsOn: []
|
dependsOn: []
|
||||||
@@ -187,33 +146,14 @@ stages:
|
|||||||
test: rhel/7.9
|
test: rhel/7.9
|
||||||
- name: RHEL 8.3
|
- name: RHEL 8.3
|
||||||
test: rhel/8.3
|
test: rhel/8.3
|
||||||
|
- name: FreeBSD 11.4
|
||||||
|
test: freebsd/11.4
|
||||||
- name: FreeBSD 12.2
|
- name: FreeBSD 12.2
|
||||||
test: freebsd/12.2
|
test: freebsd/12.2
|
||||||
- name: FreeBSD 13.0
|
|
||||||
test: freebsd/13.0
|
|
||||||
groups:
|
groups:
|
||||||
- 1
|
- 1
|
||||||
- 2
|
- 2
|
||||||
- 3
|
- 3
|
||||||
- stage: Remote_2_11
|
|
||||||
displayName: Remote 2.11
|
|
||||||
dependsOn: []
|
|
||||||
jobs:
|
|
||||||
- template: templates/matrix.yml
|
|
||||||
parameters:
|
|
||||||
testFormat: 2.11/{0}
|
|
||||||
targets:
|
|
||||||
- name: macOS 11.1
|
|
||||||
test: macos/11.1
|
|
||||||
- name: RHEL 7.9
|
|
||||||
test: rhel/7.9
|
|
||||||
- name: RHEL 8.3
|
|
||||||
test: rhel/8.3
|
|
||||||
- name: FreeBSD 12.2
|
|
||||||
test: freebsd/12.2
|
|
||||||
groups:
|
|
||||||
- 1
|
|
||||||
- 2
|
|
||||||
- stage: Remote_2_10
|
- stage: Remote_2_10
|
||||||
displayName: Remote 2.10
|
displayName: Remote 2.10
|
||||||
dependsOn: []
|
dependsOn: []
|
||||||
@@ -268,10 +208,10 @@ stages:
|
|||||||
test: centos7
|
test: centos7
|
||||||
- name: CentOS 8
|
- name: CentOS 8
|
||||||
test: centos8
|
test: centos8
|
||||||
|
- name: Fedora 32
|
||||||
|
test: fedora32
|
||||||
- name: Fedora 33
|
- name: Fedora 33
|
||||||
test: fedora33
|
test: fedora33
|
||||||
- name: Fedora 34
|
|
||||||
test: fedora34
|
|
||||||
- name: openSUSE 15 py2
|
- name: openSUSE 15 py2
|
||||||
test: opensuse15py2
|
test: opensuse15py2
|
||||||
- name: openSUSE 15 py3
|
- name: openSUSE 15 py3
|
||||||
@@ -284,25 +224,6 @@ stages:
|
|||||||
- 1
|
- 1
|
||||||
- 2
|
- 2
|
||||||
- 3
|
- 3
|
||||||
- stage: Docker_2_11
|
|
||||||
displayName: Docker 2.11
|
|
||||||
dependsOn: []
|
|
||||||
jobs:
|
|
||||||
- template: templates/matrix.yml
|
|
||||||
parameters:
|
|
||||||
testFormat: 2.11/linux/{0}
|
|
||||||
targets:
|
|
||||||
- name: CentOS 8
|
|
||||||
test: centos8
|
|
||||||
- name: Fedora 33
|
|
||||||
test: fedora33
|
|
||||||
- name: openSUSE 15 py3
|
|
||||||
test: opensuse15
|
|
||||||
- name: Ubuntu 20.04
|
|
||||||
test: ubuntu2004
|
|
||||||
groups:
|
|
||||||
- 2
|
|
||||||
- 3
|
|
||||||
- stage: Docker_2_10
|
- stage: Docker_2_10
|
||||||
displayName: Docker 2.10
|
displayName: Docker 2.10
|
||||||
dependsOn: []
|
dependsOn: []
|
||||||
@@ -349,16 +270,6 @@ stages:
|
|||||||
parameters:
|
parameters:
|
||||||
nameFormat: Python {0}
|
nameFormat: Python {0}
|
||||||
testFormat: devel/cloud/{0}/1
|
testFormat: devel/cloud/{0}/1
|
||||||
targets:
|
|
||||||
- test: 3.8
|
|
||||||
- stage: Cloud_2_11
|
|
||||||
displayName: Cloud 2.11
|
|
||||||
dependsOn: []
|
|
||||||
jobs:
|
|
||||||
- template: templates/matrix.yml
|
|
||||||
parameters:
|
|
||||||
nameFormat: Python {0}
|
|
||||||
testFormat: 2.11/cloud/{0}/1
|
|
||||||
targets:
|
targets:
|
||||||
- test: 2.7
|
- test: 2.7
|
||||||
- test: 3.6
|
- test: 3.6
|
||||||
@@ -388,22 +299,17 @@ stages:
|
|||||||
- Sanity_devel
|
- Sanity_devel
|
||||||
- Sanity_2_9
|
- Sanity_2_9
|
||||||
- Sanity_2_10
|
- Sanity_2_10
|
||||||
- Sanity_2_11
|
|
||||||
- Units_devel
|
- Units_devel
|
||||||
- Units_2_9
|
- Units_2_9
|
||||||
- Units_2_10
|
- Units_2_10
|
||||||
- Units_2_11
|
|
||||||
- Remote_devel
|
- Remote_devel
|
||||||
- Remote_2_9
|
- Remote_2_9
|
||||||
- Remote_2_10
|
- Remote_2_10
|
||||||
- Remote_2_11
|
|
||||||
- Docker_devel
|
- Docker_devel
|
||||||
- Docker_2_9
|
- Docker_2_9
|
||||||
- Docker_2_10
|
- Docker_2_10
|
||||||
- Docker_2_11
|
|
||||||
- Cloud_devel
|
- Cloud_devel
|
||||||
- Cloud_2_9
|
- Cloud_2_9
|
||||||
- Cloud_2_10
|
- Cloud_2_10
|
||||||
- Cloud_2_11
|
|
||||||
jobs:
|
jobs:
|
||||||
- template: templates/coverage.yml
|
- template: templates/coverage.yml
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ set -o pipefail -eu
|
|||||||
|
|
||||||
output_path="$1"
|
output_path="$1"
|
||||||
|
|
||||||
curl --silent --show-error https://ansible-ci-files.s3.us-east-1.amazonaws.com/codecov/codecov.sh > codecov.sh
|
curl --silent --show-error https://codecov.io/bash > codecov.sh
|
||||||
|
|
||||||
for file in "${output_path}"/reports/coverage*.xml; do
|
for file in "${output_path}"/reports/coverage*.xml; do
|
||||||
name="${file}"
|
name="${file}"
|
||||||
|
|||||||
83
.github/BOTMETA.yml
vendored
83
.github/BOTMETA.yml
vendored
@@ -1,7 +1,5 @@
|
|||||||
automerge: true
|
automerge: true
|
||||||
files:
|
files:
|
||||||
plugins/:
|
|
||||||
supershipit: aminvakil russoz
|
|
||||||
changelogs/fragments/:
|
changelogs/fragments/:
|
||||||
support: community
|
support: community
|
||||||
$actions:
|
$actions:
|
||||||
@@ -17,8 +15,6 @@ files:
|
|||||||
labels: become
|
labels: become
|
||||||
$callbacks/:
|
$callbacks/:
|
||||||
labels: callbacks
|
labels: callbacks
|
||||||
$callbacks/loganalytics.py:
|
|
||||||
maintainers: zhcli
|
|
||||||
$callbacks/logstash.py:
|
$callbacks/logstash.py:
|
||||||
maintainers: ujenmr
|
maintainers: ujenmr
|
||||||
$callbacks/say.py:
|
$callbacks/say.py:
|
||||||
@@ -57,24 +53,14 @@ files:
|
|||||||
$doc_fragments/xenserver.py:
|
$doc_fragments/xenserver.py:
|
||||||
maintainers: bvitnik
|
maintainers: bvitnik
|
||||||
labels: xenserver
|
labels: xenserver
|
||||||
$filters/dict.py:
|
|
||||||
maintainers: felixfontein
|
|
||||||
$filters/dict_kv.py:
|
$filters/dict_kv.py:
|
||||||
maintainers: giner
|
maintainers: giner
|
||||||
$filters/from_csv.py:
|
|
||||||
maintainers: Ajpantuso
|
|
||||||
$filters/hashids:
|
|
||||||
maintainers: Ajpantuso
|
|
||||||
$filters/jc.py:
|
$filters/jc.py:
|
||||||
maintainers: kellyjonbrazil
|
maintainers: kellyjonbrazil
|
||||||
$filters/list.py:
|
$filters/list.py:
|
||||||
maintainers: vbotka
|
maintainers: vbotka
|
||||||
$filters/path_join_shim.py:
|
|
||||||
maintainers: felixfontein
|
|
||||||
$filters/time.py:
|
$filters/time.py:
|
||||||
maintainers: resmo
|
maintainers: resmo
|
||||||
$filters/version_sort.py:
|
|
||||||
maintainers: ericzolf
|
|
||||||
$httpapis/:
|
$httpapis/:
|
||||||
maintainers: $team_networking
|
maintainers: $team_networking
|
||||||
labels: networking
|
labels: networking
|
||||||
@@ -88,10 +74,6 @@ files:
|
|||||||
maintainers: $team_linode
|
maintainers: $team_linode
|
||||||
labels: cloud linode
|
labels: cloud linode
|
||||||
keywords: linode dynamic inventory script
|
keywords: linode dynamic inventory script
|
||||||
$inventories/lxd.py:
|
|
||||||
maintainers: conloos
|
|
||||||
$inventories/proxmox.py:
|
|
||||||
maintainers: $team_virt ilijamt
|
|
||||||
$inventories/scaleway.py:
|
$inventories/scaleway.py:
|
||||||
maintainers: $team_scaleway
|
maintainers: $team_scaleway
|
||||||
labels: cloud scaleway
|
labels: cloud scaleway
|
||||||
@@ -157,6 +139,7 @@ files:
|
|||||||
$module_utils/redfish_utils.py:
|
$module_utils/redfish_utils.py:
|
||||||
maintainers: $team_redfish
|
maintainers: $team_redfish
|
||||||
labels: redfish_utils
|
labels: redfish_utils
|
||||||
|
$module_utils/remote_management/dellemc/: rajeevarakkal
|
||||||
$module_utils/remote_management/lxca/common.py: navalkp prabhosa
|
$module_utils/remote_management/lxca/common.py: navalkp prabhosa
|
||||||
$module_utils/scaleway.py:
|
$module_utils/scaleway.py:
|
||||||
maintainers: $team_scaleway
|
maintainers: $team_scaleway
|
||||||
@@ -192,14 +175,14 @@ files:
|
|||||||
maintainers: zbal
|
maintainers: zbal
|
||||||
$modules/cloud/lxc/lxc_container.py:
|
$modules/cloud/lxc/lxc_container.py:
|
||||||
maintainers: cloudnull
|
maintainers: cloudnull
|
||||||
$modules/cloud/lxc/lxc_profile.py:
|
|
||||||
maintainers: conloos
|
|
||||||
$modules/cloud/lxd/:
|
$modules/cloud/lxd/:
|
||||||
ignore: hnakamur
|
ignore: hnakamur
|
||||||
$modules/cloud/memset/:
|
$modules/cloud/memset/:
|
||||||
maintainers: glitchcrab
|
maintainers: glitchcrab
|
||||||
$modules/cloud/misc/cloud_init_data_facts.py:
|
$modules/cloud/misc/cloud_init_data_facts.py:
|
||||||
maintainers: resmo
|
maintainers: resmo
|
||||||
|
$modules/cloud/misc/helm.py:
|
||||||
|
maintainers: flaper87
|
||||||
$modules/cloud/misc/proxmox.py:
|
$modules/cloud/misc/proxmox.py:
|
||||||
maintainers: $team_virt UnderGreen
|
maintainers: $team_virt UnderGreen
|
||||||
labels: proxmox virt
|
labels: proxmox virt
|
||||||
@@ -227,7 +210,7 @@ files:
|
|||||||
$modules/cloud/misc/:
|
$modules/cloud/misc/:
|
||||||
ignore: ryansb
|
ignore: ryansb
|
||||||
$modules/cloud/misc/terraform.py:
|
$modules/cloud/misc/terraform.py:
|
||||||
maintainers: m-yosefpor rainerleber
|
maintainers: m-yosefpor
|
||||||
$modules/cloud/misc/xenserver_facts.py:
|
$modules/cloud/misc/xenserver_facts.py:
|
||||||
maintainers: caphrim007 cheese
|
maintainers: caphrim007 cheese
|
||||||
labels: xenserver_facts
|
labels: xenserver_facts
|
||||||
@@ -311,7 +294,6 @@ files:
|
|||||||
maintainers: bvitnik
|
maintainers: bvitnik
|
||||||
$modules/clustering/consul/:
|
$modules/clustering/consul/:
|
||||||
maintainers: $team_consul
|
maintainers: $team_consul
|
||||||
ignore: colin-nolan
|
|
||||||
$modules/clustering/etcd3.py:
|
$modules/clustering/etcd3.py:
|
||||||
maintainers: evrardjp
|
maintainers: evrardjp
|
||||||
ignore: vfauth
|
ignore: vfauth
|
||||||
@@ -348,8 +330,6 @@ files:
|
|||||||
maintainers: dareko
|
maintainers: dareko
|
||||||
$modules/files/archive.py:
|
$modules/files/archive.py:
|
||||||
maintainers: bendoh
|
maintainers: bendoh
|
||||||
$modules/files/filesize.py:
|
|
||||||
maintainers: quidame
|
|
||||||
$modules/files/ini_file.py:
|
$modules/files/ini_file.py:
|
||||||
maintainers: jpmens noseka1
|
maintainers: jpmens noseka1
|
||||||
$modules/files/iso_extract.py:
|
$modules/files/iso_extract.py:
|
||||||
@@ -363,6 +343,8 @@ files:
|
|||||||
maintainers: dagwieers magnus919 tbielawa cmprescott sm4rk0
|
maintainers: dagwieers magnus919 tbielawa cmprescott sm4rk0
|
||||||
labels: m:xml xml
|
labels: m:xml xml
|
||||||
ignore: magnus919
|
ignore: magnus919
|
||||||
|
$modules/identity/onepassword_facts.py:
|
||||||
|
maintainers: Rylon
|
||||||
$modules/identity/ipa/:
|
$modules/identity/ipa/:
|
||||||
maintainers: $team_ipa
|
maintainers: $team_ipa
|
||||||
$modules/identity/ipa/ipa_pwpolicy.py:
|
$modules/identity/ipa/ipa_pwpolicy.py:
|
||||||
@@ -375,8 +357,6 @@ files:
|
|||||||
maintainers: $team_keycloak
|
maintainers: $team_keycloak
|
||||||
$modules/identity/keycloak/keycloak_group.py:
|
$modules/identity/keycloak/keycloak_group.py:
|
||||||
maintainers: adamgoossens
|
maintainers: adamgoossens
|
||||||
$modules/identity/keycloak/keycloak_realm.py:
|
|
||||||
maintainers: kris2kris
|
|
||||||
$modules/identity/onepassword_info.py:
|
$modules/identity/onepassword_info.py:
|
||||||
maintainers: Rylon
|
maintainers: Rylon
|
||||||
$modules/identity/opendj/opendj_backendprop.py:
|
$modules/identity/opendj/opendj_backendprop.py:
|
||||||
@@ -438,8 +418,6 @@ files:
|
|||||||
maintainers: andsens
|
maintainers: andsens
|
||||||
$modules/monitoring/spectrum_device.py:
|
$modules/monitoring/spectrum_device.py:
|
||||||
maintainers: orgito
|
maintainers: orgito
|
||||||
$modules/monitoring/spectrum_model_attrs.py:
|
|
||||||
maintainers: tgates81
|
|
||||||
$modules/monitoring/stackdriver.py:
|
$modules/monitoring/stackdriver.py:
|
||||||
maintainers: bwhaley
|
maintainers: bwhaley
|
||||||
$modules/monitoring/statsd.py:
|
$modules/monitoring/statsd.py:
|
||||||
@@ -456,7 +434,7 @@ files:
|
|||||||
$modules/net_tools/dnsmadeeasy.py:
|
$modules/net_tools/dnsmadeeasy.py:
|
||||||
maintainers: briceburg
|
maintainers: briceburg
|
||||||
$modules/net_tools/haproxy.py:
|
$modules/net_tools/haproxy.py:
|
||||||
maintainers: ravibhure Normo
|
maintainers: ravibhure
|
||||||
$modules/net_tools/:
|
$modules/net_tools/:
|
||||||
maintainers: nerzhul
|
maintainers: nerzhul
|
||||||
$modules/net_tools/infinity/infinity.py:
|
$modules/net_tools/infinity/infinity.py:
|
||||||
@@ -469,6 +447,8 @@ files:
|
|||||||
maintainers: akostyuk
|
maintainers: akostyuk
|
||||||
$modules/net_tools/ipwcli_dns.py:
|
$modules/net_tools/ipwcli_dns.py:
|
||||||
maintainers: cwollinger
|
maintainers: cwollinger
|
||||||
|
$modules/net_tools/ldap/ldap_attr.py:
|
||||||
|
maintainers: jtyr
|
||||||
$modules/net_tools/ldap/ldap_attrs.py:
|
$modules/net_tools/ldap/ldap_attrs.py:
|
||||||
maintainers: drybjed jtyr noles
|
maintainers: drybjed jtyr noles
|
||||||
$modules/net_tools/ldap/ldap_entry.py:
|
$modules/net_tools/ldap/ldap_entry.py:
|
||||||
@@ -564,10 +544,9 @@ files:
|
|||||||
$modules/packaging/language/bundler.py:
|
$modules/packaging/language/bundler.py:
|
||||||
maintainers: thoiberg
|
maintainers: thoiberg
|
||||||
$modules/packaging/language/composer.py:
|
$modules/packaging/language/composer.py:
|
||||||
maintainers: dmtrs
|
maintainers: dmtrs resmo
|
||||||
ignore: resmo
|
|
||||||
$modules/packaging/language/cpanm.py:
|
$modules/packaging/language/cpanm.py:
|
||||||
maintainers: fcuny russoz
|
maintainers: fcuny
|
||||||
$modules/packaging/language/easy_install.py:
|
$modules/packaging/language/easy_install.py:
|
||||||
maintainers: mattupstate
|
maintainers: mattupstate
|
||||||
$modules/packaging/language/gem.py:
|
$modules/packaging/language/gem.py:
|
||||||
@@ -712,10 +691,15 @@ files:
|
|||||||
labels: zypper
|
labels: zypper
|
||||||
ignore: dirtyharrycallahan robinro
|
ignore: dirtyharrycallahan robinro
|
||||||
$modules/packaging/os/zypper_repository.py:
|
$modules/packaging/os/zypper_repository.py:
|
||||||
maintainers: $team_suse matze
|
maintainers: matze
|
||||||
labels: zypper
|
|
||||||
$modules/remote_management/cobbler/:
|
$modules/remote_management/cobbler/:
|
||||||
maintainers: dagwieers
|
maintainers: dagwieers
|
||||||
|
$modules/remote_management/dellemc/:
|
||||||
|
maintainers: rajeevarakkal
|
||||||
|
$modules/remote_management/dellemc/idrac_server_config_profile.py:
|
||||||
|
maintainers: jagadeeshnv
|
||||||
|
$modules/remote_management/dellemc/ome_device_info.py:
|
||||||
|
maintainers: Sajna-Shetty
|
||||||
$modules/remote_management/hpilo/:
|
$modules/remote_management/hpilo/:
|
||||||
maintainers: haad
|
maintainers: haad
|
||||||
ignore: dagwieers
|
ignore: dagwieers
|
||||||
@@ -735,6 +719,8 @@ files:
|
|||||||
maintainers: evertmulder
|
maintainers: evertmulder
|
||||||
$modules/remote_management/manageiq/manageiq_tenant.py:
|
$modules/remote_management/manageiq/manageiq_tenant.py:
|
||||||
maintainers: evertmulder
|
maintainers: evertmulder
|
||||||
|
$modules/remote_management/oneview/oneview_datacenter_facts.py:
|
||||||
|
maintainers: aalexmonteiro madhav-bharadwaj ricardogpsf soodpr
|
||||||
$modules/remote_management/oneview/:
|
$modules/remote_management/oneview/:
|
||||||
maintainers: adriane-cardozo fgbulsoni tmiotto
|
maintainers: adriane-cardozo fgbulsoni tmiotto
|
||||||
$modules/remote_management/oneview/oneview_datacenter_info.py:
|
$modules/remote_management/oneview/oneview_datacenter_info.py:
|
||||||
@@ -767,8 +753,6 @@ files:
|
|||||||
ignore: erydo
|
ignore: erydo
|
||||||
$modules/source_control/github/github_release.py:
|
$modules/source_control/github/github_release.py:
|
||||||
maintainers: adrianmoisey
|
maintainers: adrianmoisey
|
||||||
$modules/source_control/github/github_repo.py:
|
|
||||||
maintainers: atorrescogollo
|
|
||||||
$modules/source_control/github/:
|
$modules/source_control/github/:
|
||||||
maintainers: stpierre
|
maintainers: stpierre
|
||||||
$modules/source_control/gitlab/:
|
$modules/source_control/gitlab/:
|
||||||
@@ -783,6 +767,12 @@ files:
|
|||||||
maintainers: yeukhon
|
maintainers: yeukhon
|
||||||
$modules/storage/emc/emc_vnx_sg_member.py:
|
$modules/storage/emc/emc_vnx_sg_member.py:
|
||||||
maintainers: remixtj
|
maintainers: remixtj
|
||||||
|
$modules/storage/glusterfs/:
|
||||||
|
maintainers: devyanikota
|
||||||
|
$modules/storage/glusterfs/gluster_peer.py:
|
||||||
|
maintainers: sac
|
||||||
|
$modules/storage/glusterfs/gluster_volume.py:
|
||||||
|
maintainers: rosmo
|
||||||
$modules/storage/hpe3par/ss_3par_cpg.py:
|
$modules/storage/hpe3par/ss_3par_cpg.py:
|
||||||
maintainers: farhan7500 gautamphegde
|
maintainers: farhan7500 gautamphegde
|
||||||
$modules/storage/ibm/:
|
$modules/storage/ibm/:
|
||||||
@@ -804,6 +794,9 @@ files:
|
|||||||
maintainers: johanwiren
|
maintainers: johanwiren
|
||||||
$modules/storage/zfs/zfs_delegate_admin.py:
|
$modules/storage/zfs/zfs_delegate_admin.py:
|
||||||
maintainers: natefoo
|
maintainers: natefoo
|
||||||
|
$modules/system/python_requirements_facts.py:
|
||||||
|
maintainers: willthames
|
||||||
|
ignore: ryansb
|
||||||
$modules/system/aix:
|
$modules/system/aix:
|
||||||
maintainers: $team_aix
|
maintainers: $team_aix
|
||||||
labels: aix
|
labels: aix
|
||||||
@@ -843,7 +836,7 @@ files:
|
|||||||
$modules/system/iptables_state.py:
|
$modules/system/iptables_state.py:
|
||||||
maintainers: quidame
|
maintainers: quidame
|
||||||
$modules/system/java_cert.py:
|
$modules/system/java_cert.py:
|
||||||
maintainers: haad absynth76
|
maintainers: haad
|
||||||
$modules/system/java_keystore.py:
|
$modules/system/java_keystore.py:
|
||||||
maintainers: Mogztter
|
maintainers: Mogztter
|
||||||
$modules/system/kernel_blacklist.py:
|
$modules/system/kernel_blacklist.py:
|
||||||
@@ -934,6 +927,10 @@ files:
|
|||||||
labels: xfconf
|
labels: xfconf
|
||||||
$modules/system/xfs_quota.py:
|
$modules/system/xfs_quota.py:
|
||||||
maintainers: bushvin
|
maintainers: bushvin
|
||||||
|
$modules/web_infrastructure/jenkins_job_facts.py:
|
||||||
|
maintainers: stpierre
|
||||||
|
$modules/web_infrastructure/nginx_status_facts.py:
|
||||||
|
maintainers: resmo
|
||||||
$modules/web_infrastructure/apache2_mod_proxy.py:
|
$modules/web_infrastructure/apache2_mod_proxy.py:
|
||||||
maintainers: oboukili
|
maintainers: oboukili
|
||||||
$modules/web_infrastructure/apache2_module.py:
|
$modules/web_infrastructure/apache2_module.py:
|
||||||
@@ -1009,14 +1006,14 @@ macros:
|
|||||||
terminals: plugins/terminal
|
terminals: plugins/terminal
|
||||||
team_aix: MorrisA bcoca d-little flynn1973 gforster kairoaraujo marvin-sinister mator molekuul ramooncamacho wtcross
|
team_aix: MorrisA bcoca d-little flynn1973 gforster kairoaraujo marvin-sinister mator molekuul ramooncamacho wtcross
|
||||||
team_bsd: JoergFiedler MacLemon bcoca dch jasperla mekanix opoplawski overhacked tuxillo
|
team_bsd: JoergFiedler MacLemon bcoca dch jasperla mekanix opoplawski overhacked tuxillo
|
||||||
team_consul: sgargan
|
team_consul: colin-nolan sgargan
|
||||||
team_cyberark_conjur: jvanderhoof ryanprior
|
team_cyberark_conjur: jvanderhoof ryanprior
|
||||||
team_e_spirit: MatrixCrawler getjack
|
team_e_spirit: MatrixCrawler getjack
|
||||||
team_flatpak: JayKayy oolongbrothers
|
team_flatpak: JayKayy oolongbrothers
|
||||||
team_gitlab: Lunik Shaps dj-wasabi marwatk waheedi zanssa scodeman metanovii
|
team_gitlab: Lunik Shaps dj-wasabi marwatk waheedi zanssa scodeman
|
||||||
team_hpux: bcoca davx8342
|
team_hpux: bcoca davx8342
|
||||||
team_huawei: QijunPan TommyLike edisonxiang freesky-edward hwDCN niuzhenguo xuxiaowei0512 yanzhangi zengchen1024 zhongjun2
|
team_huawei: QijunPan TommyLike edisonxiang freesky-edward hwDCN niuzhenguo xuxiaowei0512 yanzhangi zengchen1024 zhongjun2
|
||||||
team_ipa: Akasurde Nosmoht fxfitz justchris1
|
team_ipa: Akasurde Nosmoht fxfitz
|
||||||
team_jboss: Wolfant jairojunior wbrefvem
|
team_jboss: Wolfant jairojunior wbrefvem
|
||||||
team_keycloak: eikef ndclt
|
team_keycloak: eikef ndclt
|
||||||
team_linode: InTheCloudDan decentral1se displague rmcintosh Charliekenney23 LBGarber
|
team_linode: InTheCloudDan decentral1se displague rmcintosh Charliekenney23 LBGarber
|
||||||
@@ -1024,12 +1021,12 @@ macros:
|
|||||||
team_manageiq: abellotti cben gtanzillo yaacov zgalor dkorn evertmulder
|
team_manageiq: abellotti cben gtanzillo yaacov zgalor dkorn evertmulder
|
||||||
team_netapp: amit0701 carchi8py hulquest lmprice lonico ndswartz schmots1
|
team_netapp: amit0701 carchi8py hulquest lmprice lonico ndswartz schmots1
|
||||||
team_networking: NilashishC Qalthos danielmellado ganeshrn justjais trishnaguha sganesh-infoblox privateip
|
team_networking: NilashishC Qalthos danielmellado ganeshrn justjais trishnaguha sganesh-infoblox privateip
|
||||||
team_opennebula: ilicmilan meerkampdvv rsmontero xorel nilsding
|
team_opennebula: ilicmilan meerkampdvv rsmontero xorel
|
||||||
team_oracle: manojmeda mross22 nalsaber
|
team_oracle: manojmeda mross22 nalsaber
|
||||||
team_purestorage: bannaych dnix101 genegr lionmax opslounge raekins sdodsley sile16
|
team_purestorage: bannaych dnix101 genegr lionmax opslounge raekins sdodsley sile16
|
||||||
team_redfish: mraineri tomasg2012 xmadsen renxulei
|
team_redfish: mraineri tomasg2012 xmadsen renxulei
|
||||||
team_rhn: FlossWare alikins barnabycourt vritant
|
team_rhn: FlossWare alikins barnabycourt vritant
|
||||||
team_scaleway: QuentinBrosse abarbare jerome-quere kindermoumoute remyleone sieben
|
team_scaleway: QuentinBrosse abarbare jerome-quere kindermoumoute remyleone sieben
|
||||||
team_solaris: bcoca fishman jasperla jpdasma mator scathatheworm troy2914 xen0l
|
team_solaris: bcoca fishman jasperla jpdasma mator scathatheworm troy2914 xen0l
|
||||||
team_suse: commel dcermak evrardjp lrupp toabctl AnderEnder alxgu andytom sealor
|
team_suse: commel dcermak evrardjp lrupp toabctl AnderEnder alxgu andytom
|
||||||
team_virt: joshainglis karmab tleguern Thulium-Drake Ajpantuso
|
team_virt: joshainglis karmab Aversiste Thulium-Drake
|
||||||
|
|||||||
135
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
135
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -1,135 +0,0 @@
|
|||||||
---
|
|
||||||
name: Bug report
|
|
||||||
description: Create a report to help us improve
|
|
||||||
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
⚠
|
|
||||||
Verify first that your issue is not [already reported on GitHub][issue search].
|
|
||||||
Also test if the latest release and devel branch are affected too.
|
|
||||||
*Complete **all** sections as described, this form is processed automatically.*
|
|
||||||
|
|
||||||
[issue search]: https://github.com/ansible-collections/community.general/search?q=is%3Aissue&type=issues
|
|
||||||
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Summary
|
|
||||||
description: Explain the problem briefly below.
|
|
||||||
placeholder: >-
|
|
||||||
When I try to do X with the collection from the main branch on GitHub, Y
|
|
||||||
breaks in a way Z under the env E. Here are all the details I know
|
|
||||||
about this problem...
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: dropdown
|
|
||||||
attributes:
|
|
||||||
label: Issue Type
|
|
||||||
# FIXME: Once GitHub allows defining the default choice, update this
|
|
||||||
options:
|
|
||||||
- Bug Report
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
# For smaller collections we could use a multi-select and hardcode the list
|
|
||||||
# May generate this list via GitHub action and walking files under https://github.com/ansible-collections/community.general/tree/main/plugins
|
|
||||||
# Select from list, filter as you type (`mysql` would only show the 3 mysql components)
|
|
||||||
# OR freeform - doesn't seem to be supported in adaptivecards
|
|
||||||
label: Component Name
|
|
||||||
description: >-
|
|
||||||
Write the short name of the module, plugin, task or feature below,
|
|
||||||
*use your best guess if unsure*.
|
|
||||||
placeholder: dnf, apt, yum, pip, user etc.
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Ansible Version
|
|
||||||
description: >-
|
|
||||||
Paste verbatim output from `ansible --version` between
|
|
||||||
tripple backticks.
|
|
||||||
value: |
|
|
||||||
```console (paste below)
|
|
||||||
$ ansible --version
|
|
||||||
|
|
||||||
```
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Configuration
|
|
||||||
description: >-
|
|
||||||
If this issue has an example piece of YAML that can help to reproduce this problem, please provide it.
|
|
||||||
This can be a piece of YAML from, e.g., an automation, script, scene or configuration.
|
|
||||||
Paste verbatim output from `ansible-config dump --only-changed` between quotes
|
|
||||||
value: |
|
|
||||||
```console (paste below)
|
|
||||||
$ ansible-config dump --only-changed
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: OS / Environment
|
|
||||||
description: >-
|
|
||||||
Provide all relevant information below, e.g. target OS versions,
|
|
||||||
network device firmware, etc.
|
|
||||||
placeholder: RHEL 8, CentOS Stream etc.
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Steps to Reproduce
|
|
||||||
description: |
|
|
||||||
Describe exactly how to reproduce the problem, using a minimal test-case. It would *really* help us understand your problem if you could also pased any playbooks, configs and commands you used.
|
|
||||||
|
|
||||||
**HINT:** You can paste https://gist.github.com links for larger files.
|
|
||||||
value: |
|
|
||||||
<!--- Paste example playbooks or commands between quotes below -->
|
|
||||||
```yaml (paste below)
|
|
||||||
|
|
||||||
```
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Expected Results
|
|
||||||
description: >-
|
|
||||||
Describe what you expected to happen when running the steps above.
|
|
||||||
placeholder: >-
|
|
||||||
I expected X to happen because I assumed Y.
|
|
||||||
that it did not.
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Actual Results
|
|
||||||
description: |
|
|
||||||
Describe what actually happened. If possible run with extra verbosity (`-vvvv`).
|
|
||||||
|
|
||||||
Paste verbatim command output between quotes.
|
|
||||||
value: |
|
|
||||||
```console (paste below)
|
|
||||||
|
|
||||||
```
|
|
||||||
- type: checkboxes
|
|
||||||
attributes:
|
|
||||||
label: Code of Conduct
|
|
||||||
description: |
|
|
||||||
Read the [Ansible Code of Conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html?utm_medium=github&utm_source=issue_form--ansible-collections) first.
|
|
||||||
options:
|
|
||||||
- label: I agree to follow the Ansible Code of Conduct
|
|
||||||
required: true
|
|
||||||
...
|
|
||||||
27
.github/ISSUE_TEMPLATE/config.yml
vendored
27
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,27 +0,0 @@
|
|||||||
---
|
|
||||||
# Ref: https://help.github.com/en/github/building-a-strong-community/configuring-issue-templates-for-your-repository#configuring-the-template-chooser
|
|
||||||
blank_issues_enabled: false # default: true
|
|
||||||
contact_links:
|
|
||||||
- name: Security bug report
|
|
||||||
url: https://docs.ansible.com/ansible-core/devel/community/reporting_bugs_and_features.html?utm_medium=github&utm_source=issue_template_chooser_ansible_collections
|
|
||||||
about: |
|
|
||||||
Please learn how to report security vulnerabilities here.
|
|
||||||
|
|
||||||
For all security related bugs, email security@ansible.com
|
|
||||||
instead of using this issue tracker and you will receive
|
|
||||||
a prompt response.
|
|
||||||
|
|
||||||
For more information, see
|
|
||||||
https://docs.ansible.com/ansible/latest/community/reporting_bugs_and_features.html
|
|
||||||
- name: Ansible Code of Conduct
|
|
||||||
url: https://docs.ansible.com/ansible/latest/community/code_of_conduct.html?utm_medium=github&utm_source=issue_template_chooser_ansible_collections
|
|
||||||
about: Be nice to other members of the community.
|
|
||||||
- name: Talks to the community
|
|
||||||
url: https://docs.ansible.com/ansible/latest/community/communication.html?utm_medium=github&utm_source=issue_template_chooser#mailing-list-information
|
|
||||||
about: Please ask and answer usage questions here
|
|
||||||
- name: Working groups
|
|
||||||
url: https://github.com/ansible/community/wiki
|
|
||||||
about: Interested in improving a specific area? Become a part of a working group!
|
|
||||||
- name: For Enterprise
|
|
||||||
url: https://www.ansible.com/products/engine?utm_medium=github&utm_source=issue_template_chooser_ansible_collections
|
|
||||||
about: Red Hat offers support for the Ansible Automation Platform
|
|
||||||
111
.github/ISSUE_TEMPLATE/documentation_report.yml
vendored
111
.github/ISSUE_TEMPLATE/documentation_report.yml
vendored
@@ -1,111 +0,0 @@
|
|||||||
---
|
|
||||||
name: Documentation Report
|
|
||||||
description: Ask us about docs
|
|
||||||
# NOTE: issue body is enabled to allow screenshots
|
|
||||||
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
⚠
|
|
||||||
Verify first that your issue is not [already reported on GitHub][issue search].
|
|
||||||
Also test if the latest release and devel branch are affected too.
|
|
||||||
*Complete **all** sections as described, this form is processed automatically.*
|
|
||||||
|
|
||||||
[issue search]: https://github.com/ansible-collections/community.general/search?q=is%3Aissue&type=issues
|
|
||||||
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Summary
|
|
||||||
description: |
|
|
||||||
Explain the problem briefly below, add suggestions to wording or structure.
|
|
||||||
|
|
||||||
**HINT:** Did you know the documentation has an `Edit on GitHub` link on every page?
|
|
||||||
placeholder: >-
|
|
||||||
I was reading the Collection documentation of version X and I'm having
|
|
||||||
problems understanding Y. It would be very helpful if that got
|
|
||||||
rephrased as Z.
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: dropdown
|
|
||||||
attributes:
|
|
||||||
label: Issue Type
|
|
||||||
# FIXME: Once GitHub allows defining the default choice, update this
|
|
||||||
options:
|
|
||||||
- Documentation Report
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: input
|
|
||||||
attributes:
|
|
||||||
label: Component Name
|
|
||||||
description: >-
|
|
||||||
Write the short name of the rst file, module, plugin, task or
|
|
||||||
feature below, *use your best guess if unsure*.
|
|
||||||
placeholder: mysql_user
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Ansible Version
|
|
||||||
description: >-
|
|
||||||
Paste verbatim output from `ansible --version` between
|
|
||||||
tripple backticks.
|
|
||||||
value: |
|
|
||||||
```console (paste below)
|
|
||||||
$ ansible --version
|
|
||||||
|
|
||||||
```
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Configuration
|
|
||||||
description: >-
|
|
||||||
Paste verbatim output from `ansible-config dump --only-changed` between quotes.
|
|
||||||
value: |
|
|
||||||
```console (paste below)
|
|
||||||
$ ansible-config dump --only-changed
|
|
||||||
|
|
||||||
```
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: OS / Environment
|
|
||||||
description: >-
|
|
||||||
Provide all relevant information below, e.g. OS version,
|
|
||||||
browser, etc.
|
|
||||||
placeholder: Fedora 33, Firefox etc.
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Additional Information
|
|
||||||
description: |
|
|
||||||
Describe how this improves the documentation, e.g. before/after situation or screenshots.
|
|
||||||
|
|
||||||
**Tip:** It's not possible to upload the screenshot via this field directly but you can use the last textarea in this form to attach them.
|
|
||||||
|
|
||||||
**HINT:** You can paste https://gist.github.com links for larger files.
|
|
||||||
placeholder: >-
|
|
||||||
When the improvement is applied, it makes it more straightforward
|
|
||||||
to understand X.
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
|
|
||||||
- type: checkboxes
|
|
||||||
attributes:
|
|
||||||
label: Code of Conduct
|
|
||||||
description: |
|
|
||||||
Read the [Ansible Code of Conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html?utm_medium=github&utm_source=issue_form--ansible-collections) first.
|
|
||||||
options:
|
|
||||||
- label: I agree to follow the Ansible Code of Conduct
|
|
||||||
required: true
|
|
||||||
...
|
|
||||||
69
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
69
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@@ -1,69 +0,0 @@
|
|||||||
---
|
|
||||||
name: Feature request
|
|
||||||
description: Suggest an idea for this project
|
|
||||||
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
⚠
|
|
||||||
Verify first that your issue is not [already reported on GitHub][issue search].
|
|
||||||
Also test if the latest release and devel branch are affected too.
|
|
||||||
*Complete **all** sections as described, this form is processed automatically.*
|
|
||||||
|
|
||||||
[issue search]: https://github.com/ansible-collections/community.general/search?q=is%3Aissue&type=issues
|
|
||||||
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Summary
|
|
||||||
description: Describe the new feature/improvement briefly below.
|
|
||||||
placeholder: >-
|
|
||||||
I am trying to do X with the collection from the main branch on GitHub and
|
|
||||||
I think that implementing a feature Y would be very helpful for me and
|
|
||||||
every other user of ansible-core because of Z.
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: dropdown
|
|
||||||
attributes:
|
|
||||||
label: Issue Type
|
|
||||||
# FIXME: Once GitHub allows defining the default choice, update this
|
|
||||||
options:
|
|
||||||
- Feature Idea
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: input
|
|
||||||
attributes:
|
|
||||||
label: Component Name
|
|
||||||
description: >-
|
|
||||||
Write the short name of the module, plugin, task or feature below,
|
|
||||||
*use your best guess if unsure*.
|
|
||||||
placeholder: dnf, apt, yum, pip, user etc.
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Additional Information
|
|
||||||
description: |
|
|
||||||
Describe how the feature would be used, why it is needed and what it would solve.
|
|
||||||
|
|
||||||
**HINT:** You can paste https://gist.github.com links for larger files.
|
|
||||||
value: |
|
|
||||||
<!--- Paste example playbooks or commands between quotes below -->
|
|
||||||
```yaml (paste below)
|
|
||||||
|
|
||||||
```
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
- type: checkboxes
|
|
||||||
attributes:
|
|
||||||
label: Code of Conduct
|
|
||||||
description: |
|
|
||||||
Read the [Ansible Code of Conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html?utm_medium=github&utm_source=issue_form--ansible-collections) first.
|
|
||||||
options:
|
|
||||||
- label: I agree to follow the Ansible Code of Conduct
|
|
||||||
required: true
|
|
||||||
...
|
|
||||||
1209
CHANGELOG.rst
1209
CHANGELOG.rst
File diff suppressed because it is too large
Load Diff
@@ -1,17 +1,15 @@
|
|||||||
# Community General Collection
|
# Community General Collection
|
||||||
|
|
||||||
[](https://dev.azure.com/ansible/community.general/_build?definitionId=31)
|
[](https://dev.azure.com/ansible/community.general/_build?definitionId=31)
|
||||||
[](https://codecov.io/gh/ansible-collections/community.general)
|
[](https://codecov.io/gh/ansible-collections/community.general)
|
||||||
|
|
||||||
This repo contains the `community.general` Ansible Collection. The collection includes many modules and plugins supported by Ansible community which are not part of more specialized community collections.
|
This repo contains the `community.general` Ansible Collection. The collection includes many modules and plugins supported by Ansible community which are not part of more specialized community collections.
|
||||||
|
|
||||||
You can find [documentation for this collection on the Ansible docs site](https://docs.ansible.com/ansible/latest/collections/community/general/).
|
You can find [documentation for this collection on the Ansible docs site](https://docs.ansible.com/ansible/latest/collections/community/general/).
|
||||||
|
|
||||||
Please note that this collection does **not** support Windows targets. Only connection plugins included in this collection might support Windows targets, and will explicitly mention that in their documentation if they do so.
|
|
||||||
|
|
||||||
## Tested with Ansible
|
## Tested with Ansible
|
||||||
|
|
||||||
Tested with the current Ansible 2.9, ansible-base 2.10 and ansible-core 2.11 releases and the current development version of ansible-core. Ansible versions before 2.9.10 are not supported.
|
Tested with the current Ansible 2.9 and 2.10 releases and the current development version of Ansible. Ansible versions before 2.9.10 are not supported.
|
||||||
|
|
||||||
## External requirements
|
## External requirements
|
||||||
|
|
||||||
@@ -78,7 +76,7 @@ Basic instructions without release branches:
|
|||||||
|
|
||||||
## Release notes
|
## Release notes
|
||||||
|
|
||||||
See the [changelog](https://github.com/ansible-collections/community.general/blob/stable-3/CHANGELOG.rst).
|
See the [changelog](https://github.com/ansible-collections/community.general/blob/stable-2/CHANGELOG.rst).
|
||||||
|
|
||||||
## Roadmap
|
## Roadmap
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,72 +0,0 @@
|
|||||||
Committers Guidelines for community.general
|
|
||||||
===========================================
|
|
||||||
|
|
||||||
This document is based on the [Ansible committer guidelines](https://github.com/ansible/ansible/blob/b57444af14062ec96e0af75fdfc2098c74fe2d9a/docs/docsite/rst/community/committer_guidelines.rst) ([latest version](https://docs.ansible.com/ansible/devel/community/committer_guidelines.html)).
|
|
||||||
|
|
||||||
These are the guidelines for people with commit privileges on the Ansible Community General Collection GitHub repository. Please read the guidelines before you commit.
|
|
||||||
|
|
||||||
These guidelines apply to everyone. At the same time, this is NOT a process document. So just use good judgment. You have been given commit access because we trust your judgment.
|
|
||||||
|
|
||||||
That said, use the trust wisely.
|
|
||||||
|
|
||||||
If you abuse the trust and break components and builds, and so on, the trust level falls and you may be asked not to commit or you may lose your commit privileges.
|
|
||||||
|
|
||||||
Our workflow on GitHub
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
As a committer, you may already know this, but our workflow forms a lot of our team policies. Please ensure you are aware of the following workflow steps:
|
|
||||||
|
|
||||||
* Fork the repository upon which you want to do some work to your own personal repository
|
|
||||||
* Work on the specific branch upon which you need to commit
|
|
||||||
* Create a Pull Request back to the collection repository and await reviews
|
|
||||||
* Adjust code as necessary based on the Comments provided
|
|
||||||
* Ask someone from the other committers to do a final review and merge
|
|
||||||
|
|
||||||
Sometimes, committers merge their own pull requests. This section is a set of guidelines. If you are changing a comma in a doc or making a very minor change, you can use your best judgement. This is another trust thing. The process is critical for any major change, but for little things or getting something done quickly, use your best judgement and make sure people on the team are aware of your work.
|
|
||||||
|
|
||||||
Roles
|
|
||||||
-----
|
|
||||||
* Release managers: Merge pull requests to `stable-X` branches, create tags to do releases.
|
|
||||||
* Committers: Fine to do PRs for most things, but we should have a timebox. Hanging PRs may merge on the judgement of these devs.
|
|
||||||
* Module maintainers: Module maintainers own specific modules and have indirect commit access through the current module PR mechanisms. This is primary [ansibullbot](https://github.com/ansibullbot)'s `shipit` mechanism.
|
|
||||||
|
|
||||||
General rules
|
|
||||||
-------------
|
|
||||||
Individuals with direct commit access to this collection repository are entrusted with powers that allow them to do a broad variety of things--probably more than we can write down. Rather than rules, treat these as general *guidelines*, individuals with this power are expected to use their best judgement.
|
|
||||||
|
|
||||||
* Do NOTs:
|
|
||||||
|
|
||||||
- Do not commit directly.
|
|
||||||
- Do not merge your own PRs. Someone else should have a chance to review and approve the PR merge. You have a small amount of leeway here for very minor changes.
|
|
||||||
- Do not forget about non-standard / alternate environments. Consider the alternatives. Yes, people have bad/unusual/strange environments (like binaries from multiple init systems installed), but they are the ones who need us the most.
|
|
||||||
- Do not drag your community team members down. Discuss the technical merits of any pull requests you review. Avoid negativity and personal comments. For more guidance on being a good community member, read the [Ansible Community Code of Conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html).
|
|
||||||
- Do not forget about the maintenance burden. High-maintenance features may not be worth adding.
|
|
||||||
- Do not break playbooks. Always keep backwards compatibility in mind.
|
|
||||||
- Do not forget to keep it simple. Complexity breeds all kinds of problems.
|
|
||||||
- Do not merge to branches other than `main`, especially not to `stable-X`, if you do not have explicit permission to do so.
|
|
||||||
- Do not create tags. Tags are used in the release process, and should only be created by the people responsible for managing the stable branches.
|
|
||||||
|
|
||||||
* Do:
|
|
||||||
|
|
||||||
- Squash, avoid merges whenever possible, use GitHub's squash commits or cherry pick if needed (bisect thanks you).
|
|
||||||
- Be active. Committers who have no activity on the project (through merges, triage, commits, and so on) will have their permissions suspended.
|
|
||||||
- Consider backwards compatibility (goes back to "do not break existing playbooks").
|
|
||||||
- Write tests. PRs with tests are looked at with more priority than PRs without tests that should have them included. While not all changes require tests, be sure to add them for bug fixes or functionality changes.
|
|
||||||
- Discuss with other committers, specially when you are unsure of something.
|
|
||||||
- Document! If your PR is a new feature or a change to behavior, make sure you've updated all associated documentation or have notified the right people to do so.
|
|
||||||
- Consider scope, sometimes a fix can be generalized.
|
|
||||||
- Keep it simple, then things are maintainable, debuggable and intelligible.
|
|
||||||
|
|
||||||
Committers are expected to continue to follow the same community and contribution guidelines followed by the rest of the Ansible community.
|
|
||||||
|
|
||||||
|
|
||||||
People
|
|
||||||
------
|
|
||||||
|
|
||||||
Individuals who have been asked to become a part of this group have generally been contributing in significant ways to the community.general collection for some time. Should they agree, they are requested to add their names and GitHub IDs to this file, in the section below, through a pull request. Doing so indicates that these individuals agree to act in the ways that their fellow committers trust that they will act.
|
|
||||||
|
|
||||||
| Name | GitHub ID | IRC Nick | Other |
|
|
||||||
| ------------------- | -------------------- | ------------------ | -------------------- |
|
|
||||||
| Andrew Klychkov | andersson007 | andersson007_ | |
|
|
||||||
| Felix Fontein | felixfontein | felixfontein | |
|
|
||||||
| John R Barker | gundalow | gundalow | |
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
namespace: community
|
namespace: community
|
||||||
name: general
|
name: general
|
||||||
version: 3.0.2
|
version: 2.4.0
|
||||||
readme: README.md
|
readme: README.md
|
||||||
authors:
|
authors:
|
||||||
- Ansible (https://github.com/ansible)
|
- Ansible (https://github.com/ansible)
|
||||||
|
|||||||
173
meta/runtime.yml
173
meta/runtime.yml
@@ -39,7 +39,7 @@ plugin_routing:
|
|||||||
redirect: community.hashi_vault.hashi_vault
|
redirect: community.hashi_vault.hashi_vault
|
||||||
modules:
|
modules:
|
||||||
ali_instance_facts:
|
ali_instance_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.general.ali_instance_info instead.
|
warning_text: Use community.general.ali_instance_info instead.
|
||||||
docker_compose:
|
docker_compose:
|
||||||
@@ -159,7 +159,8 @@ plugin_routing:
|
|||||||
gcpubsub_info:
|
gcpubsub_info:
|
||||||
redirect: community.google.gcpubsub_info
|
redirect: community.google.gcpubsub_info
|
||||||
gcpubsub_facts:
|
gcpubsub_facts:
|
||||||
tombstone:
|
redirect: community.google.gcpubsub_info
|
||||||
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.google.gcpubsub_info instead.
|
warning_text: Use community.google.gcpubsub_info instead.
|
||||||
gcspanner:
|
gcspanner:
|
||||||
@@ -170,23 +171,22 @@ plugin_routing:
|
|||||||
tombstone:
|
tombstone:
|
||||||
removal_version: 2.0.0
|
removal_version: 2.0.0
|
||||||
warning_text: Use community.general.github_webhook and community.general.github_webhook_info instead.
|
warning_text: Use community.general.github_webhook and community.general.github_webhook_info instead.
|
||||||
# Adding tombstones burns the old name, so we simply remove the entries:
|
gluster_heal_info:
|
||||||
# gluster_heal_info:
|
deprecation:
|
||||||
# tombstone:
|
removal_version: 3.0.0
|
||||||
# removal_version: 3.0.0
|
warning_text: The gluster modules have migrated to the gluster.gluster collection. Use gluster.gluster.gluster_heal_info instead.
|
||||||
# warning_text: The gluster modules have migrated to the gluster.gluster collection. Use gluster.gluster.gluster_heal_info instead.
|
gluster_peer:
|
||||||
# gluster_peer:
|
deprecation:
|
||||||
# tombstone:
|
removal_version: 3.0.0
|
||||||
# removal_version: 3.0.0
|
warning_text: The gluster modules have migrated to the gluster.gluster collection. Use gluster.gluster.gluster_peer instead.
|
||||||
# warning_text: The gluster modules have migrated to the gluster.gluster collection. Use gluster.gluster.gluster_peer instead.
|
gluster_volume:
|
||||||
# gluster_volume:
|
deprecation:
|
||||||
# tombstone:
|
removal_version: 3.0.0
|
||||||
# removal_version: 3.0.0
|
warning_text: The gluster modules have migrated to the gluster.gluster collection. Use gluster.gluster.gluster_volume instead.
|
||||||
# warning_text: The gluster modules have migrated to the gluster.gluster collection. Use gluster.gluster.gluster_volume instead.
|
helm:
|
||||||
# helm:
|
deprecation:
|
||||||
# tombstone:
|
removal_version: 3.0.0
|
||||||
# removal_version: 3.0.0
|
warning_text: The helm module in community.general has been deprecated. Use community.kubernetes.helm instead.
|
||||||
# warning_text: Use community.kubernetes.helm instead.
|
|
||||||
hetzner_failover_ip:
|
hetzner_failover_ip:
|
||||||
redirect: community.hrobot.failover_ip
|
redirect: community.hrobot.failover_ip
|
||||||
hetzner_failover_ip_info:
|
hetzner_failover_ip_info:
|
||||||
@@ -196,19 +196,15 @@ plugin_routing:
|
|||||||
hetzner_firewall_info:
|
hetzner_firewall_info:
|
||||||
redirect: community.hrobot.firewall_info
|
redirect: community.hrobot.firewall_info
|
||||||
hpilo_facts:
|
hpilo_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.general.hpilo_info instead.
|
warning_text: Use community.general.hpilo_info instead.
|
||||||
idrac_firmware:
|
|
||||||
redirect: dellemc.openmanage.idrac_firmware
|
|
||||||
idrac_redfish_facts:
|
idrac_redfish_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.general.idrac_redfish_info instead.
|
warning_text: Use community.general.idrac_redfish_info instead.
|
||||||
idrac_server_config_profile:
|
|
||||||
redirect: dellemc.openmanage.idrac_server_config_profile
|
|
||||||
jenkins_job_facts:
|
jenkins_job_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.general.jenkins_job_info instead.
|
warning_text: Use community.general.jenkins_job_info instead.
|
||||||
katello:
|
katello:
|
||||||
@@ -228,7 +224,7 @@ plugin_routing:
|
|||||||
kubevirt_vm:
|
kubevirt_vm:
|
||||||
redirect: community.kubevirt.kubevirt_vm
|
redirect: community.kubevirt.kubevirt_vm
|
||||||
ldap_attr:
|
ldap_attr:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.general.ldap_attrs instead.
|
warning_text: Use community.general.ldap_attrs instead.
|
||||||
logicmonitor:
|
logicmonitor:
|
||||||
@@ -240,11 +236,11 @@ plugin_routing:
|
|||||||
removal_version: 1.0.0
|
removal_version: 1.0.0
|
||||||
warning_text: The logicmonitor_facts module is no longer maintained and the API used has been disabled in 2017.
|
warning_text: The logicmonitor_facts module is no longer maintained and the API used has been disabled in 2017.
|
||||||
memset_memstore_facts:
|
memset_memstore_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.general.memset_memstore_info instead.
|
warning_text: Use community.general.memset_memstore_info instead.
|
||||||
memset_server_facts:
|
memset_server_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.general.memset_server_info instead.
|
warning_text: Use community.general.memset_server_info instead.
|
||||||
na_cdot_aggregate:
|
na_cdot_aggregate:
|
||||||
@@ -280,161 +276,159 @@ plugin_routing:
|
|||||||
removal_version: 2.0.0
|
removal_version: 2.0.0
|
||||||
warning_text: Use netapp.ontap.na_ontap_volume instead.
|
warning_text: Use netapp.ontap.na_ontap_volume instead.
|
||||||
na_ontap_gather_facts:
|
na_ontap_gather_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use netapp.ontap.na_ontap_info instead.
|
warning_text: Use netapp.ontap.na_ontap_info instead.
|
||||||
nginx_status_facts:
|
nginx_status_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.general.nginx_status_info instead.
|
warning_text: Use community.general.nginx_status_info instead.
|
||||||
ome_device_info:
|
|
||||||
redirect: dellemc.openmanage.ome_device_info
|
|
||||||
one_image_facts:
|
one_image_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.general.one_image_info instead.
|
warning_text: Use community.general.one_image_info instead.
|
||||||
onepassword_facts:
|
onepassword_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.general.onepassword_info instead.
|
warning_text: Use community.general.onepassword_info instead.
|
||||||
oneview_datacenter_facts:
|
oneview_datacenter_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.general.oneview_datacenter_info instead.
|
warning_text: Use community.general.oneview_datacenter_info instead.
|
||||||
oneview_enclosure_facts:
|
oneview_enclosure_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.general.oneview_enclosure_info instead.
|
warning_text: Use community.general.oneview_enclosure_info instead.
|
||||||
oneview_ethernet_network_facts:
|
oneview_ethernet_network_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.general.oneview_ethernet_network_info instead.
|
warning_text: Use community.general.oneview_ethernet_network_info instead.
|
||||||
oneview_fc_network_facts:
|
oneview_fc_network_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.general.oneview_fc_network_info instead.
|
warning_text: Use community.general.oneview_fc_network_info instead.
|
||||||
oneview_fcoe_network_facts:
|
oneview_fcoe_network_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.general.oneview_fcoe_network_info instead.
|
warning_text: Use community.general.oneview_fcoe_network_info instead.
|
||||||
oneview_logical_interconnect_group_facts:
|
oneview_logical_interconnect_group_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.general.oneview_logical_interconnect_group_info instead.
|
warning_text: Use community.general.oneview_logical_interconnect_group_info instead.
|
||||||
oneview_network_set_facts:
|
oneview_network_set_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.general.oneview_network_set_info instead.
|
warning_text: Use community.general.oneview_network_set_info instead.
|
||||||
oneview_san_manager_facts:
|
oneview_san_manager_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.general.oneview_san_manager_info instead.
|
warning_text: Use community.general.oneview_san_manager_info instead.
|
||||||
online_server_facts:
|
online_server_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.general.online_server_info instead.
|
warning_text: Use community.general.online_server_info instead.
|
||||||
online_user_facts:
|
online_user_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.general.online_user_info instead.
|
warning_text: Use community.general.online_user_info instead.
|
||||||
ovirt:
|
ovirt:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use ovirt.ovirt.ovirt_vm instead.
|
warning_text: Use ovirt.ovirt.ovirt_vm instead.
|
||||||
ovirt_affinity_label_facts:
|
ovirt_affinity_label_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use ovirt.ovirt.ovirt_affinity_label_info instead.
|
warning_text: Use ovirt.ovirt.ovirt_affinity_label_info instead.
|
||||||
ovirt_api_facts:
|
ovirt_api_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use ovirt.ovirt.ovirt_api_info instead.
|
warning_text: Use ovirt.ovirt.ovirt_api_info instead.
|
||||||
ovirt_cluster_facts:
|
ovirt_cluster_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use ovirt.ovirt.ovirt_cluster_info instead.
|
warning_text: Use ovirt.ovirt.ovirt_cluster_info instead.
|
||||||
ovirt_datacenter_facts:
|
ovirt_datacenter_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use ovirt.ovirt.ovirt_datacenter_info instead.
|
warning_text: Use ovirt.ovirt.ovirt_datacenter_info instead.
|
||||||
ovirt_disk_facts:
|
ovirt_disk_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use ovirt.ovirt.ovirt_disk_info instead.
|
warning_text: Use ovirt.ovirt.ovirt_disk_info instead.
|
||||||
ovirt_event_facts:
|
ovirt_event_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use ovirt.ovirt.ovirt_event_info instead.
|
warning_text: Use ovirt.ovirt.ovirt_event_info instead.
|
||||||
ovirt_external_provider_facts:
|
ovirt_external_provider_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use ovirt.ovirt.ovirt_external_provider_info instead.
|
warning_text: Use ovirt.ovirt.ovirt_external_provider_info instead.
|
||||||
ovirt_group_facts:
|
ovirt_group_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use ovirt.ovirt.ovirt_group_info instead.
|
warning_text: Use ovirt.ovirt.ovirt_group_info instead.
|
||||||
ovirt_host_facts:
|
ovirt_host_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use ovirt.ovirt.ovirt_host_info instead.
|
warning_text: Use ovirt.ovirt.ovirt_host_info instead.
|
||||||
ovirt_host_storage_facts:
|
ovirt_host_storage_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use ovirt.ovirt.ovirt_host_storage_info instead.
|
warning_text: Use ovirt.ovirt.ovirt_host_storage_info instead.
|
||||||
ovirt_network_facts:
|
ovirt_network_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use ovirt.ovirt.ovirt_network_info instead.
|
warning_text: Use ovirt.ovirt.ovirt_network_info instead.
|
||||||
ovirt_nic_facts:
|
ovirt_nic_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use ovirt.ovirt.ovirt_nic_info instead.
|
warning_text: Use ovirt.ovirt.ovirt_nic_info instead.
|
||||||
ovirt_permission_facts:
|
ovirt_permission_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use ovirt.ovirt.ovirt_permission_info instead.
|
warning_text: Use ovirt.ovirt.ovirt_permission_info instead.
|
||||||
ovirt_quota_facts:
|
ovirt_quota_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use ovirt.ovirt.ovirt_quota_info instead.
|
warning_text: Use ovirt.ovirt.ovirt_quota_info instead.
|
||||||
ovirt_scheduling_policy_facts:
|
ovirt_scheduling_policy_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use ovirt.ovirt.ovirt_scheduling_policy_info instead.
|
warning_text: Use ovirt.ovirt.ovirt_scheduling_policy_info instead.
|
||||||
ovirt_snapshot_facts:
|
ovirt_snapshot_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use ovirt.ovirt.ovirt_snapshot_info instead.
|
warning_text: Use ovirt.ovirt.ovirt_snapshot_info instead.
|
||||||
ovirt_storage_domain_facts:
|
ovirt_storage_domain_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use ovirt.ovirt.ovirt_storage_domain_info instead.
|
warning_text: Use ovirt.ovirt.ovirt_storage_domain_info instead.
|
||||||
ovirt_storage_template_facts:
|
ovirt_storage_template_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use ovirt.ovirt.ovirt_storage_template_info instead.
|
warning_text: Use ovirt.ovirt.ovirt_storage_template_info instead.
|
||||||
ovirt_storage_vm_facts:
|
ovirt_storage_vm_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use ovirt.ovirt.ovirt_storage_vm_info instead.
|
warning_text: Use ovirt.ovirt.ovirt_storage_vm_info instead.
|
||||||
ovirt_tag_facts:
|
ovirt_tag_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use ovirt.ovirt.ovirt_tag_info instead.
|
warning_text: Use ovirt.ovirt.ovirt_tag_info instead.
|
||||||
ovirt_template_facts:
|
ovirt_template_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use ovirt.ovirt.ovirt_template_info instead.
|
warning_text: Use ovirt.ovirt.ovirt_template_info instead.
|
||||||
ovirt_user_facts:
|
ovirt_user_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use ovirt.ovirt.ovirt_user_info instead.
|
warning_text: Use ovirt.ovirt.ovirt_user_info instead.
|
||||||
ovirt_vm_facts:
|
ovirt_vm_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use ovirt.ovirt.ovirt_vm_info instead.
|
warning_text: Use ovirt.ovirt.ovirt_vm_info instead.
|
||||||
ovirt_vmpool_facts:
|
ovirt_vmpool_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use ovirt.ovirt.ovirt_vmpool_info instead.
|
warning_text: Use ovirt.ovirt.ovirt_vmpool_info instead.
|
||||||
postgresql_copy:
|
postgresql_copy:
|
||||||
@@ -482,47 +476,47 @@ plugin_routing:
|
|||||||
postgresql_user:
|
postgresql_user:
|
||||||
redirect: community.postgresql.postgresql_user
|
redirect: community.postgresql.postgresql_user
|
||||||
purefa_facts:
|
purefa_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use purestorage.flasharray.purefa_info instead.
|
warning_text: Use purestorage.flasharray.purefa_info instead.
|
||||||
purefb_facts:
|
purefb_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use purestorage.flashblade.purefb_info instead.
|
warning_text: Use purestorage.flashblade.purefb_info instead.
|
||||||
python_requirements_facts:
|
python_requirements_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.general.python_requirements_info instead.
|
warning_text: Use community.general.python_requirements_info instead.
|
||||||
redfish_facts:
|
redfish_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.general.redfish_info instead.
|
warning_text: Use community.general.redfish_info instead.
|
||||||
scaleway_image_facts:
|
scaleway_image_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.general.scaleway_image_info instead.
|
warning_text: Use community.general.scaleway_image_info instead.
|
||||||
scaleway_ip_facts:
|
scaleway_ip_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.general.scaleway_ip_info instead.
|
warning_text: Use community.general.scaleway_ip_info instead.
|
||||||
scaleway_organization_facts:
|
scaleway_organization_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.general.scaleway_organization_info instead.
|
warning_text: Use community.general.scaleway_organization_info instead.
|
||||||
scaleway_security_group_facts:
|
scaleway_security_group_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.general.scaleway_security_group_info instead.
|
warning_text: Use community.general.scaleway_security_group_info instead.
|
||||||
scaleway_server_facts:
|
scaleway_server_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.general.scaleway_server_info instead.
|
warning_text: Use community.general.scaleway_server_info instead.
|
||||||
scaleway_snapshot_facts:
|
scaleway_snapshot_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.general.scaleway_snapshot_info instead.
|
warning_text: Use community.general.scaleway_snapshot_info instead.
|
||||||
scaleway_volume_facts:
|
scaleway_volume_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.general.scaleway_volume_info instead.
|
warning_text: Use community.general.scaleway_volume_info instead.
|
||||||
sf_account_manager:
|
sf_account_manager:
|
||||||
@@ -546,15 +540,15 @@ plugin_routing:
|
|||||||
removal_version: 2.0.0
|
removal_version: 2.0.0
|
||||||
warning_text: Use netapp.elementsw.na_elementsw_volume instead.
|
warning_text: Use netapp.elementsw.na_elementsw_volume instead.
|
||||||
smartos_image_facts:
|
smartos_image_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.general.smartos_image_info instead.
|
warning_text: Use community.general.smartos_image_info instead.
|
||||||
vertica_facts:
|
vertica_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.general.vertica_info instead.
|
warning_text: Use community.general.vertica_info instead.
|
||||||
xenserver_guest_facts:
|
xenserver_guest_facts:
|
||||||
tombstone:
|
deprecation:
|
||||||
removal_version: 3.0.0
|
removal_version: 3.0.0
|
||||||
warning_text: Use community.general.xenserver_guest_info instead.
|
warning_text: Use community.general.xenserver_guest_info instead.
|
||||||
doc_fragments:
|
doc_fragments:
|
||||||
@@ -571,8 +565,6 @@ plugin_routing:
|
|||||||
postgresql:
|
postgresql:
|
||||||
redirect: community.postgresql.postgresql
|
redirect: community.postgresql.postgresql
|
||||||
module_utils:
|
module_utils:
|
||||||
remote_management.dellemc.dellemc_idrac:
|
|
||||||
redirect: dellemc.openmanage.dellemc_idrac
|
|
||||||
docker.common:
|
docker.common:
|
||||||
redirect: community.docker.common
|
redirect: community.docker.common
|
||||||
docker.swarm:
|
docker.swarm:
|
||||||
@@ -587,8 +579,6 @@ plugin_routing:
|
|||||||
redirect: community.hrobot.robot
|
redirect: community.hrobot.robot
|
||||||
kubevirt:
|
kubevirt:
|
||||||
redirect: community.kubevirt.kubevirt
|
redirect: community.kubevirt.kubevirt
|
||||||
remote_management.dellemc.ome:
|
|
||||||
redirect: dellemc.openmanage.ome
|
|
||||||
postgresql:
|
postgresql:
|
||||||
redirect: community.postgresql.postgresql
|
redirect: community.postgresql.postgresql
|
||||||
callback:
|
callback:
|
||||||
@@ -611,10 +601,3 @@ plugin_routing:
|
|||||||
redirect: community.docker.docker_swarm
|
redirect: community.docker.docker_swarm
|
||||||
kubevirt:
|
kubevirt:
|
||||||
redirect: community.kubevirt.kubevirt
|
redirect: community.kubevirt.kubevirt
|
||||||
filter:
|
|
||||||
path_join:
|
|
||||||
# The ansible.builtin.path_join filter has been added in ansible-base 2.10.
|
|
||||||
# Since plugin routing is only available since ansible-base 2.10, this
|
|
||||||
# redirect will be used for ansible-base 2.10 or later, and the included
|
|
||||||
# path_join filter will be used for Ansible 2.9 or earlier.
|
|
||||||
redirect: ansible.builtin.path_join
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from __future__ import (absolute_import, division, print_function)
|
|||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
DOCUMENTATION = """
|
DOCUMENTATION = """
|
||||||
name: sudosu
|
become: sudosu
|
||||||
short_description: Run tasks using sudo su -
|
short_description: Run tasks using sudo su -
|
||||||
description:
|
description:
|
||||||
- This become plugins allows your remote/login user to execute commands as another user via the C(sudo) and C(su) utilities combined.
|
- This become plugins allows your remote/login user to execute commands as another user via the C(sudo) and C(su) utilities combined.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from __future__ import (absolute_import, division, print_function)
|
|||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
DOCUMENTATION = '''
|
||||||
name: loganalytics
|
callback: loganalytics
|
||||||
type: aggregate
|
type: aggregate
|
||||||
short_description: Posts task results to Azure Log Analytics
|
short_description: Posts task results to Azure Log Analytics
|
||||||
author: "Cyrus Li (@zhcli) <cyrus1006@gmail.com>"
|
author: "Cyrus Li (@zhcli) <cyrus1006@gmail.com>"
|
||||||
|
|||||||
@@ -37,13 +37,12 @@ import tempfile
|
|||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
from ansible.plugins.connection import ConnectionBase
|
|
||||||
from ansible.utils.display import Display
|
from ansible.utils.display import Display
|
||||||
|
|
||||||
display = Display()
|
display = Display()
|
||||||
|
|
||||||
|
|
||||||
class Connection(ConnectionBase):
|
class Connection(object):
|
||||||
''' Func-based connections '''
|
''' Func-based connections '''
|
||||||
|
|
||||||
has_pipelining = False
|
has_pipelining = False
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ options:
|
|||||||
description:
|
description:
|
||||||
- Keycloak realm name to authenticate to for API access.
|
- Keycloak realm name to authenticate to for API access.
|
||||||
type: str
|
type: str
|
||||||
|
required: true
|
||||||
|
|
||||||
auth_client_secret:
|
auth_client_secret:
|
||||||
description:
|
description:
|
||||||
@@ -40,6 +41,7 @@ options:
|
|||||||
description:
|
description:
|
||||||
- Username to authenticate for API access with.
|
- Username to authenticate for API access with.
|
||||||
type: str
|
type: str
|
||||||
|
required: true
|
||||||
aliases:
|
aliases:
|
||||||
- username
|
- username
|
||||||
|
|
||||||
@@ -47,15 +49,10 @@ options:
|
|||||||
description:
|
description:
|
||||||
- Password to authenticate for API access with.
|
- Password to authenticate for API access with.
|
||||||
type: str
|
type: str
|
||||||
|
required: true
|
||||||
aliases:
|
aliases:
|
||||||
- password
|
- password
|
||||||
|
|
||||||
token:
|
|
||||||
description:
|
|
||||||
- Authentication token for Keycloak API.
|
|
||||||
type: str
|
|
||||||
version_added: 3.0.0
|
|
||||||
|
|
||||||
validate_certs:
|
validate_certs:
|
||||||
description:
|
description:
|
||||||
- Verify TLS certificates (do not disable this in production).
|
- Verify TLS certificates (do not disable this in production).
|
||||||
|
|||||||
59
plugins/doc_fragments/ovirt_facts.py
Normal file
59
plugins/doc_fragments/ovirt_facts.py
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Copyright: (c) 2016, Red Hat, Inc.
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
|
||||||
|
class ModuleDocFragment(object):
|
||||||
|
|
||||||
|
# info standard oVirt documentation fragment
|
||||||
|
DOCUMENTATION = r'''
|
||||||
|
options:
|
||||||
|
fetch_nested:
|
||||||
|
description:
|
||||||
|
- If I(yes) the module will fetch additional data from the API.
|
||||||
|
- It will fetch only IDs of nested entity. It doesn't fetch multiple levels of nested attributes.
|
||||||
|
Only the attributes of the current entity. User can configure to fetch other
|
||||||
|
attributes of the nested entities by specifying C(nested_attributes).
|
||||||
|
type: bool
|
||||||
|
default: false
|
||||||
|
nested_attributes:
|
||||||
|
description:
|
||||||
|
- Specifies list of the attributes which should be fetched from the API.
|
||||||
|
- This parameter apply only when C(fetch_nested) is I(true).
|
||||||
|
type: list
|
||||||
|
auth:
|
||||||
|
description:
|
||||||
|
- "Dictionary with values needed to create HTTP/HTTPS connection to oVirt:"
|
||||||
|
- C(username)[I(required)] - The name of the user, something like I(admin@internal).
|
||||||
|
Default value is set by I(OVIRT_USERNAME) environment variable.
|
||||||
|
- "C(password)[I(required)] - The password of the user. Default value is set by I(OVIRT_PASSWORD) environment variable."
|
||||||
|
- "C(url)- A string containing the API URL of the server, usually
|
||||||
|
something like `I(https://server.example.com/ovirt-engine/api)`. Default value is set by I(OVIRT_URL) environment variable.
|
||||||
|
Either C(url) or C(hostname) is required."
|
||||||
|
- "C(hostname) - A string containing the hostname of the server, usually
|
||||||
|
something like `I(server.example.com)`. Default value is set by I(OVIRT_HOSTNAME) environment variable.
|
||||||
|
Either C(url) or C(hostname) is required."
|
||||||
|
- "C(token) - Token to be used instead of login with username/password. Default value is set by I(OVIRT_TOKEN) environment variable."
|
||||||
|
- "C(insecure) - A boolean flag that indicates if the server TLS
|
||||||
|
certificate and host name should be checked."
|
||||||
|
- "C(ca_file) - A PEM file containing the trusted CA certificates. The
|
||||||
|
certificate presented by the server will be verified using these CA
|
||||||
|
certificates. If `C(ca_file)` parameter is not set, system wide
|
||||||
|
CA certificate store is used. Default value is set by I(OVIRT_CAFILE) environment variable."
|
||||||
|
- "C(kerberos) - A boolean flag indicating if Kerberos authentication
|
||||||
|
should be used instead of the default basic authentication."
|
||||||
|
- "C(headers) - Dictionary of HTTP headers to be added to each API call."
|
||||||
|
type: dict
|
||||||
|
required: true
|
||||||
|
requirements:
|
||||||
|
- python >= 2.7
|
||||||
|
- ovirt-engine-sdk-python >= 4.3.0
|
||||||
|
notes:
|
||||||
|
- "In order to use this module you have to install oVirt Python SDK.
|
||||||
|
To ensure it's installed with correct version you can create the following task:
|
||||||
|
ansible.builtin.pip: name=ovirt-engine-sdk-python version=4.3.0"
|
||||||
|
'''
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Copyright: (c) 2021, Felix Fontein <felix@fontein.de>
|
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
|
|
||||||
from __future__ import absolute_import, division, print_function
|
|
||||||
__metaclass__ = type
|
|
||||||
|
|
||||||
|
|
||||||
def dict_filter(sequence):
|
|
||||||
'''Convert a list of tuples to a dictionary.
|
|
||||||
|
|
||||||
Example: ``[[1, 2], ['a', 'b']] | community.general.dict`` results in ``{1: 2, 'a': 'b'}``
|
|
||||||
'''
|
|
||||||
return dict(sequence)
|
|
||||||
|
|
||||||
|
|
||||||
class FilterModule(object):
|
|
||||||
'''Ansible jinja2 filters'''
|
|
||||||
|
|
||||||
def filters(self):
|
|
||||||
return {
|
|
||||||
'dict': dict_filter,
|
|
||||||
}
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Copyright: (c) 2021, Andrew Pantuso (@ajpantuso) <ajpantuso@gmail.com>
|
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
|
|
||||||
from __future__ import absolute_import, division, print_function
|
|
||||||
__metaclass__ = type
|
|
||||||
|
|
||||||
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 hashids import Hashids
|
|
||||||
HAS_HASHIDS = True
|
|
||||||
except ImportError:
|
|
||||||
HAS_HASHIDS = False
|
|
||||||
|
|
||||||
|
|
||||||
def initialize_hashids(**kwargs):
|
|
||||||
if not HAS_HASHIDS:
|
|
||||||
raise AnsibleError("The hashids library must be installed in order to use this plugin")
|
|
||||||
|
|
||||||
params = dict((k, v) for k, v in kwargs.items() if v)
|
|
||||||
|
|
||||||
try:
|
|
||||||
return Hashids(**params)
|
|
||||||
except TypeError as e:
|
|
||||||
raise AnsibleFilterError(
|
|
||||||
"The provided parameters %s are invalid: %s" % (
|
|
||||||
', '.join(["%s=%s" % (k, v) for k, v in params.items()]),
|
|
||||||
to_native(e)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def hashids_encode(nums, salt=None, alphabet=None, min_length=None):
|
|
||||||
"""Generates a YouTube-like hash from a sequence of ints
|
|
||||||
|
|
||||||
:nums: Sequence of one or more ints to hash
|
|
||||||
:salt: String to use as salt when hashing
|
|
||||||
:alphabet: String of 16 or more unique characters to produce a hash
|
|
||||||
:min_length: Minimum length of hash produced
|
|
||||||
"""
|
|
||||||
|
|
||||||
hashids = initialize_hashids(
|
|
||||||
salt=salt,
|
|
||||||
alphabet=alphabet,
|
|
||||||
min_length=min_length
|
|
||||||
)
|
|
||||||
|
|
||||||
# Handles the case where a single int is not encapsulated in a list or tuple.
|
|
||||||
# User convenience seems preferable to strict typing in this case
|
|
||||||
# Also avoids obfuscated error messages related to single invalid inputs
|
|
||||||
if not is_sequence(nums):
|
|
||||||
nums = [nums]
|
|
||||||
|
|
||||||
try:
|
|
||||||
hashid = hashids.encode(*nums)
|
|
||||||
except TypeError as e:
|
|
||||||
raise AnsibleFilterTypeError(
|
|
||||||
"Data to encode must by a tuple or list of ints: %s" % to_native(e)
|
|
||||||
)
|
|
||||||
|
|
||||||
return hashid
|
|
||||||
|
|
||||||
|
|
||||||
def hashids_decode(hashid, salt=None, alphabet=None, min_length=None):
|
|
||||||
"""Decodes a YouTube-like hash to a sequence of ints
|
|
||||||
|
|
||||||
:hashid: Hash string to decode
|
|
||||||
:salt: String to use as salt when hashing
|
|
||||||
:alphabet: String of 16 or more unique characters to produce a hash
|
|
||||||
:min_length: Minimum length of hash produced
|
|
||||||
"""
|
|
||||||
|
|
||||||
hashids = initialize_hashids(
|
|
||||||
salt=salt,
|
|
||||||
alphabet=alphabet,
|
|
||||||
min_length=min_length
|
|
||||||
)
|
|
||||||
nums = hashids.decode(hashid)
|
|
||||||
return list(nums)
|
|
||||||
|
|
||||||
|
|
||||||
class FilterModule(object):
|
|
||||||
|
|
||||||
def filters(self):
|
|
||||||
return {
|
|
||||||
'hashids_encode': hashids_encode,
|
|
||||||
'hashids_decode': hashids_decode,
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Copyright: (c) 2020-2021, Felix Fontein <felix@fontein.de>
|
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
|
|
||||||
from __future__ import absolute_import, division, print_function
|
|
||||||
__metaclass__ = type
|
|
||||||
|
|
||||||
|
|
||||||
import os.path
|
|
||||||
|
|
||||||
|
|
||||||
def path_join(list):
|
|
||||||
'''Join list of paths.
|
|
||||||
|
|
||||||
This is a minimal shim for ansible.builtin.path_join included in ansible-base 2.10.
|
|
||||||
This should only be called by Ansible 2.9 or earlier. See meta/runtime.yml for details.
|
|
||||||
'''
|
|
||||||
return os.path.join(*list)
|
|
||||||
|
|
||||||
|
|
||||||
class FilterModule(object):
|
|
||||||
'''Ansible jinja2 filters'''
|
|
||||||
|
|
||||||
def filters(self):
|
|
||||||
return {
|
|
||||||
'path_join': path_join,
|
|
||||||
}
|
|
||||||
@@ -1,950 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright: (c) 2021, Frank Dornheim <dornheim@posteo.de>
|
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
|
|
||||||
from __future__ import (absolute_import, division, print_function)
|
|
||||||
__metaclass__ = type
|
|
||||||
|
|
||||||
DOCUMENTATION = r'''
|
|
||||||
name: lxd
|
|
||||||
short_description: Returns Ansible inventory from lxd host
|
|
||||||
description:
|
|
||||||
- Get inventory from the lxd.
|
|
||||||
- Uses a YAML configuration file that ends with 'lxd.(yml|yaml)'.
|
|
||||||
version_added: "3.0.0"
|
|
||||||
author: "Frank Dornheim (@conloos)"
|
|
||||||
options:
|
|
||||||
plugin:
|
|
||||||
description: Token that ensures this is a source file for the 'lxd' plugin.
|
|
||||||
required: true
|
|
||||||
choices: [ 'community.general.lxd' ]
|
|
||||||
url:
|
|
||||||
description:
|
|
||||||
- The unix domain socket path or the https URL for the lxd server.
|
|
||||||
- Sockets in filesystem have to start with C(unix:).
|
|
||||||
- Mostly C(unix:/var/lib/lxd/unix.socket) or C(unix:/var/snap/lxd/common/lxd/unix.socket).
|
|
||||||
default: unix:/var/snap/lxd/common/lxd/unix.socket
|
|
||||||
type: str
|
|
||||||
client_key:
|
|
||||||
description:
|
|
||||||
- The client certificate key file path.
|
|
||||||
aliases: [ key_file ]
|
|
||||||
default: $HOME/.config/lxc/client.key
|
|
||||||
type: path
|
|
||||||
client_cert:
|
|
||||||
description:
|
|
||||||
- The client certificate file path.
|
|
||||||
aliases: [ cert_file ]
|
|
||||||
default: $HOME/.config/lxc/client.crt
|
|
||||||
type: path
|
|
||||||
trust_password:
|
|
||||||
description:
|
|
||||||
- The client trusted password.
|
|
||||||
- You need to set this password on the lxd server before
|
|
||||||
running this module using the following command
|
|
||||||
C(lxc config set core.trust_password <some random password>)
|
|
||||||
See U(https://www.stgraber.org/2016/04/18/lxd-api-direct-interaction/).
|
|
||||||
- If I(trust_password) is set, this module send a request for authentication before sending any requests.
|
|
||||||
type: str
|
|
||||||
state:
|
|
||||||
description: Filter the container according to the current status.
|
|
||||||
type: str
|
|
||||||
default: none
|
|
||||||
choices: [ 'STOPPED', 'STARTING', 'RUNNING', 'none' ]
|
|
||||||
prefered_container_network_interface:
|
|
||||||
description:
|
|
||||||
- If a container has multiple network interfaces, select which one is the prefered as pattern.
|
|
||||||
- Combined with the first number that can be found e.g. 'eth' + 0.
|
|
||||||
type: str
|
|
||||||
default: eth
|
|
||||||
prefered_container_network_family:
|
|
||||||
description:
|
|
||||||
- If a container has multiple network interfaces, which one is the prefered by family.
|
|
||||||
- Specify C(inet) for IPv4 and C(inet6) for IPv6.
|
|
||||||
type: str
|
|
||||||
default: inet
|
|
||||||
choices: [ 'inet', 'inet6' ]
|
|
||||||
groupby:
|
|
||||||
description:
|
|
||||||
- Create groups by the following keywords C(location), C(pattern), C(network_range), C(os), C(release), C(profile), C(vlanid).
|
|
||||||
- See example for syntax.
|
|
||||||
type: dict
|
|
||||||
'''
|
|
||||||
|
|
||||||
EXAMPLES = '''
|
|
||||||
# simple lxd.yml
|
|
||||||
plugin: community.general.lxd
|
|
||||||
url: unix:/var/snap/lxd/common/lxd/unix.socket
|
|
||||||
|
|
||||||
# simple lxd.yml including filter
|
|
||||||
plugin: community.general.lxd
|
|
||||||
url: unix:/var/snap/lxd/common/lxd/unix.socket
|
|
||||||
state: RUNNING
|
|
||||||
|
|
||||||
# grouping lxd.yml
|
|
||||||
groupby:
|
|
||||||
testpattern:
|
|
||||||
type: pattern
|
|
||||||
attribute: test
|
|
||||||
vlan666:
|
|
||||||
type: vlanid
|
|
||||||
attribute: 666
|
|
||||||
locationBerlin:
|
|
||||||
type: location
|
|
||||||
attribute: Berlin
|
|
||||||
osUbuntu:
|
|
||||||
type: os
|
|
||||||
attribute: ubuntu
|
|
||||||
releaseFocal:
|
|
||||||
type: release
|
|
||||||
attribute: focal
|
|
||||||
releaseBionic:
|
|
||||||
type: release
|
|
||||||
attribute: bionic
|
|
||||||
profileDefault:
|
|
||||||
type: profile
|
|
||||||
attribute: default
|
|
||||||
profileX11:
|
|
||||||
type: profile
|
|
||||||
attribute: x11
|
|
||||||
netRangeIPv4:
|
|
||||||
type: network_range
|
|
||||||
attribute: 10.98.143.0/24
|
|
||||||
netRangeIPv6:
|
|
||||||
type: network_range
|
|
||||||
attribute: fd42:bd00:7b11:2167:216:3eff::/24
|
|
||||||
'''
|
|
||||||
|
|
||||||
import binascii
|
|
||||||
import json
|
|
||||||
import re
|
|
||||||
import time
|
|
||||||
import os
|
|
||||||
import socket
|
|
||||||
from ansible.plugins.inventory import BaseInventoryPlugin
|
|
||||||
from ansible.module_utils._text import to_native, to_text
|
|
||||||
from ansible.module_utils.common.dict_transformations import dict_merge
|
|
||||||
from ansible.errors import AnsibleError, AnsibleParserError
|
|
||||||
from ansible_collections.community.general.plugins.module_utils.compat import ipaddress
|
|
||||||
from ansible_collections.community.general.plugins.module_utils.lxd import LXDClient, LXDClientException
|
|
||||||
|
|
||||||
|
|
||||||
class InventoryModule(BaseInventoryPlugin):
|
|
||||||
DEBUG = 4
|
|
||||||
NAME = 'community.general.lxd'
|
|
||||||
SNAP_SOCKET_URL = 'unix:/var/snap/lxd/common/lxd/unix.socket'
|
|
||||||
SOCKET_URL = 'unix:/var/lib/lxd/unix.socket'
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def load_json_data(path):
|
|
||||||
"""Load json data
|
|
||||||
|
|
||||||
Load json data from file
|
|
||||||
|
|
||||||
Args:
|
|
||||||
list(path): Path elements
|
|
||||||
str(file_name): Filename of data
|
|
||||||
Kwargs:
|
|
||||||
None
|
|
||||||
Raises:
|
|
||||||
None
|
|
||||||
Returns:
|
|
||||||
dict(json_data): json data"""
|
|
||||||
try:
|
|
||||||
with open(path, 'r') as json_file:
|
|
||||||
return json.load(json_file)
|
|
||||||
except (IOError, json.decoder.JSONDecodeError) as err:
|
|
||||||
raise AnsibleParserError('Could not load the test data from {0}: {1}'.format(to_native(path), to_native(err)))
|
|
||||||
|
|
||||||
def save_json_data(self, path, file_name=None):
|
|
||||||
"""save data as json
|
|
||||||
|
|
||||||
Save data as json file
|
|
||||||
|
|
||||||
Args:
|
|
||||||
list(path): Path elements
|
|
||||||
str(file_name): Filename of data
|
|
||||||
Kwargs:
|
|
||||||
None
|
|
||||||
Raises:
|
|
||||||
None
|
|
||||||
Returns:
|
|
||||||
None"""
|
|
||||||
|
|
||||||
if file_name:
|
|
||||||
path.append(file_name)
|
|
||||||
else:
|
|
||||||
prefix = 'lxd_data-'
|
|
||||||
time_stamp = time.strftime('%Y%m%d-%H%M%S')
|
|
||||||
suffix = '.atd'
|
|
||||||
path.append(prefix + time_stamp + suffix)
|
|
||||||
|
|
||||||
try:
|
|
||||||
cwd = os.path.abspath(os.path.dirname(__file__))
|
|
||||||
with open(os.path.abspath(os.path.join(cwd, *path)), 'w') as json_file:
|
|
||||||
json.dump(self.data, json_file)
|
|
||||||
except IOError as err:
|
|
||||||
raise AnsibleParserError('Could not save data: {0}'.format(to_native(err)))
|
|
||||||
|
|
||||||
def verify_file(self, path):
|
|
||||||
"""Check the config
|
|
||||||
|
|
||||||
Return true/false if the config-file is valid for this plugin
|
|
||||||
|
|
||||||
Args:
|
|
||||||
str(path): path to the config
|
|
||||||
Kwargs:
|
|
||||||
None
|
|
||||||
Raises:
|
|
||||||
None
|
|
||||||
Returns:
|
|
||||||
bool(valid): is valid"""
|
|
||||||
valid = False
|
|
||||||
if super(InventoryModule, self).verify_file(path):
|
|
||||||
if path.endswith(('lxd.yaml', 'lxd.yml')):
|
|
||||||
valid = True
|
|
||||||
else:
|
|
||||||
self.display.vvv('Inventory source not ending in "lxd.yaml" or "lxd.yml"')
|
|
||||||
return valid
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def validate_url(url):
|
|
||||||
"""validate url
|
|
||||||
|
|
||||||
check whether the url is correctly formatted
|
|
||||||
|
|
||||||
Args:
|
|
||||||
url
|
|
||||||
Kwargs:
|
|
||||||
None
|
|
||||||
Raises:
|
|
||||||
AnsibleError
|
|
||||||
Returns:
|
|
||||||
bool"""
|
|
||||||
if not isinstance(url, str):
|
|
||||||
return False
|
|
||||||
if not url.startswith(('unix:', 'https:')):
|
|
||||||
raise AnsibleError('URL is malformed: {0}'.format(to_native(url)))
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _connect_to_socket(self):
|
|
||||||
"""connect to lxd socket
|
|
||||||
|
|
||||||
Connect to lxd socket by provided url or defaults
|
|
||||||
|
|
||||||
Args:
|
|
||||||
None
|
|
||||||
Kwargs:
|
|
||||||
None
|
|
||||||
Raises:
|
|
||||||
AnsibleError
|
|
||||||
Returns:
|
|
||||||
None"""
|
|
||||||
error_storage = {}
|
|
||||||
url_list = [self.get_option('url'), self.SNAP_SOCKET_URL, self.SOCKET_URL]
|
|
||||||
urls = (url for url in url_list if self.validate_url(url))
|
|
||||||
for url in urls:
|
|
||||||
try:
|
|
||||||
socket_connection = LXDClient(url, self.client_key, self.client_cert, self.debug)
|
|
||||||
return socket_connection
|
|
||||||
except LXDClientException as err:
|
|
||||||
error_storage[url] = err
|
|
||||||
raise AnsibleError('No connection to the socket: {0}'.format(to_native(error_storage)))
|
|
||||||
|
|
||||||
def _get_networks(self):
|
|
||||||
"""Get Networknames
|
|
||||||
|
|
||||||
Returns all network config names
|
|
||||||
|
|
||||||
Args:
|
|
||||||
None
|
|
||||||
Kwargs:
|
|
||||||
None
|
|
||||||
Raises:
|
|
||||||
None
|
|
||||||
Returns:
|
|
||||||
list(names): names of all network_configs"""
|
|
||||||
# e.g. {'type': 'sync',
|
|
||||||
# 'status': 'Success',
|
|
||||||
# 'status_code': 200,
|
|
||||||
# 'operation': '',
|
|
||||||
# 'error_code': 0,
|
|
||||||
# 'error': '',
|
|
||||||
# 'metadata': ['/1.0/networks/lxdbr0']}
|
|
||||||
network_configs = self.socket.do('GET', '/1.0/networks')
|
|
||||||
return [m.split('/')[3] for m in network_configs['metadata']]
|
|
||||||
|
|
||||||
def _get_containers(self):
|
|
||||||
"""Get Containernames
|
|
||||||
|
|
||||||
Returns all containernames
|
|
||||||
|
|
||||||
Args:
|
|
||||||
None
|
|
||||||
Kwargs:
|
|
||||||
None
|
|
||||||
Raises:
|
|
||||||
None
|
|
||||||
Returns:
|
|
||||||
list(names): names of all containers"""
|
|
||||||
# e.g. {'type': 'sync',
|
|
||||||
# 'status': 'Success',
|
|
||||||
# 'status_code': 200,
|
|
||||||
# 'operation': '',
|
|
||||||
# 'error_code': 0,
|
|
||||||
# 'error': '',
|
|
||||||
# 'metadata': ['/1.0/containers/udemy-ansible-ubuntu-2004']}
|
|
||||||
containers = self.socket.do('GET', '/1.0/containers')
|
|
||||||
return [m.split('/')[3] for m in containers['metadata']]
|
|
||||||
|
|
||||||
def _get_config(self, branch, name):
|
|
||||||
"""Get inventory of container
|
|
||||||
|
|
||||||
Get config of container
|
|
||||||
|
|
||||||
Args:
|
|
||||||
str(branch): Name oft the API-Branch
|
|
||||||
str(name): Name of Container
|
|
||||||
Kwargs:
|
|
||||||
None
|
|
||||||
Source:
|
|
||||||
https://github.com/lxc/lxd/blob/master/doc/rest-api.md
|
|
||||||
Raises:
|
|
||||||
None
|
|
||||||
Returns:
|
|
||||||
dict(config): Config of the container"""
|
|
||||||
config = {}
|
|
||||||
if isinstance(branch, (tuple, list)):
|
|
||||||
config[name] = {branch[1]: self.socket.do('GET', '/1.0/{0}/{1}/{2}'.format(to_native(branch[0]), to_native(name), to_native(branch[1])))}
|
|
||||||
else:
|
|
||||||
config[name] = {branch: self.socket.do('GET', '/1.0/{0}/{1}'.format(to_native(branch), to_native(name)))}
|
|
||||||
return config
|
|
||||||
|
|
||||||
def get_container_data(self, names):
|
|
||||||
"""Create Inventory of the container
|
|
||||||
|
|
||||||
Iterate through the different branches of the containers and collect Informations.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
list(names): List of container names
|
|
||||||
Kwargs:
|
|
||||||
None
|
|
||||||
Raises:
|
|
||||||
None
|
|
||||||
Returns:
|
|
||||||
None"""
|
|
||||||
# tuple(('instances','metadata/templates')) to get section in branch
|
|
||||||
# e.g. /1.0/instances/<name>/metadata/templates
|
|
||||||
branches = ['containers', ('instances', 'state')]
|
|
||||||
container_config = {}
|
|
||||||
for branch in branches:
|
|
||||||
for name in names:
|
|
||||||
container_config['containers'] = self._get_config(branch, name)
|
|
||||||
self.data = dict_merge(container_config, self.data)
|
|
||||||
|
|
||||||
def get_network_data(self, names):
|
|
||||||
"""Create Inventory of the container
|
|
||||||
|
|
||||||
Iterate through the different branches of the containers and collect Informations.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
list(names): List of container names
|
|
||||||
Kwargs:
|
|
||||||
None
|
|
||||||
Raises:
|
|
||||||
None
|
|
||||||
Returns:
|
|
||||||
None"""
|
|
||||||
# tuple(('instances','metadata/templates')) to get section in branch
|
|
||||||
# e.g. /1.0/instances/<name>/metadata/templates
|
|
||||||
branches = [('networks', 'state')]
|
|
||||||
network_config = {}
|
|
||||||
for branch in branches:
|
|
||||||
for name in names:
|
|
||||||
try:
|
|
||||||
network_config['networks'] = self._get_config(branch, name)
|
|
||||||
except LXDClientException:
|
|
||||||
network_config['networks'] = {name: None}
|
|
||||||
self.data = dict_merge(network_config, self.data)
|
|
||||||
|
|
||||||
def extract_network_information_from_container_config(self, container_name):
|
|
||||||
"""Returns the network interface configuration
|
|
||||||
|
|
||||||
Returns the network ipv4 and ipv6 config of the container without local-link
|
|
||||||
|
|
||||||
Args:
|
|
||||||
str(container_name): Name oft he container
|
|
||||||
Kwargs:
|
|
||||||
None
|
|
||||||
Raises:
|
|
||||||
None
|
|
||||||
Returns:
|
|
||||||
dict(network_configuration): network config"""
|
|
||||||
container_network_interfaces = self._get_data_entry('containers/{0}/state/metadata/network'.format(container_name))
|
|
||||||
network_configuration = None
|
|
||||||
if container_network_interfaces:
|
|
||||||
network_configuration = {}
|
|
||||||
gen_interface_names = [interface_name for interface_name in container_network_interfaces if interface_name != 'lo']
|
|
||||||
for interface_name in gen_interface_names:
|
|
||||||
gen_address = [address for address in container_network_interfaces[interface_name]['addresses'] if address.get('scope') != 'link']
|
|
||||||
network_configuration[interface_name] = []
|
|
||||||
for address in gen_address:
|
|
||||||
address_set = {}
|
|
||||||
address_set['family'] = address.get('family')
|
|
||||||
address_set['address'] = address.get('address')
|
|
||||||
address_set['netmask'] = address.get('netmask')
|
|
||||||
address_set['combined'] = address.get('address') + '/' + address.get('netmask')
|
|
||||||
network_configuration[interface_name].append(address_set)
|
|
||||||
return network_configuration
|
|
||||||
|
|
||||||
def get_prefered_container_network_interface(self, container_name):
|
|
||||||
"""Helper to get the prefered interface of thr container
|
|
||||||
|
|
||||||
Helper to get the prefered interface provide by neme pattern from 'prefered_container_network_interface'.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
str(containe_name): name of container
|
|
||||||
Kwargs:
|
|
||||||
None
|
|
||||||
Raises:
|
|
||||||
None
|
|
||||||
Returns:
|
|
||||||
str(prefered_interface): None or interface name"""
|
|
||||||
container_network_interfaces = self._get_data_entry('inventory/{0}/network_interfaces'.format(container_name))
|
|
||||||
prefered_interface = None # init
|
|
||||||
if container_network_interfaces: # container have network interfaces
|
|
||||||
# generator if interfaces which start with the desired pattern
|
|
||||||
net_generator = [interface for interface in container_network_interfaces if interface.startswith(self.prefered_container_network_interface)]
|
|
||||||
selected_interfaces = [] # init
|
|
||||||
for interface in net_generator:
|
|
||||||
selected_interfaces.append(interface)
|
|
||||||
if len(selected_interfaces) > 0:
|
|
||||||
prefered_interface = sorted(selected_interfaces)[0]
|
|
||||||
return prefered_interface
|
|
||||||
|
|
||||||
def get_container_vlans(self, container_name):
|
|
||||||
"""Get VLAN(s) from container
|
|
||||||
|
|
||||||
Helper to get the VLAN_ID from the container
|
|
||||||
|
|
||||||
Args:
|
|
||||||
str(containe_name): name of container
|
|
||||||
Kwargs:
|
|
||||||
None
|
|
||||||
Raises:
|
|
||||||
None
|
|
||||||
Returns:
|
|
||||||
None"""
|
|
||||||
# get network device configuration and store {network: vlan_id}
|
|
||||||
network_vlans = {}
|
|
||||||
for network in self._get_data_entry('networks'):
|
|
||||||
if self._get_data_entry('state/metadata/vlan/vid', data=self.data['networks'].get(network)):
|
|
||||||
network_vlans[network] = self._get_data_entry('state/metadata/vlan/vid', data=self.data['networks'].get(network))
|
|
||||||
|
|
||||||
# get networkdevices of container and return
|
|
||||||
# e.g.
|
|
||||||
# "eth0":{ "name":"eth0",
|
|
||||||
# "network":"lxdbr0",
|
|
||||||
# "type":"nic"},
|
|
||||||
vlan_ids = {}
|
|
||||||
devices = self._get_data_entry('containers/{0}/containers/metadata/expanded_devices'.format(to_native(container_name)))
|
|
||||||
for device in devices:
|
|
||||||
if 'network' in devices[device]:
|
|
||||||
if devices[device]['network'] in network_vlans:
|
|
||||||
vlan_ids[devices[device].get('network')] = network_vlans[devices[device].get('network')]
|
|
||||||
return vlan_ids if vlan_ids else None
|
|
||||||
|
|
||||||
def _get_data_entry(self, path, data=None, delimiter='/'):
|
|
||||||
"""Helper to get data
|
|
||||||
|
|
||||||
Helper to get data from self.data by a path like 'path/to/target'
|
|
||||||
Attention: Escaping of the delimiter is not (yet) provided.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
str(path): path to nested dict
|
|
||||||
Kwargs:
|
|
||||||
dict(data): datastore
|
|
||||||
str(delimiter): delimiter in Path.
|
|
||||||
Raises:
|
|
||||||
None
|
|
||||||
Returns:
|
|
||||||
*(value)"""
|
|
||||||
try:
|
|
||||||
if not data:
|
|
||||||
data = self.data
|
|
||||||
if delimiter in path:
|
|
||||||
path = path.split(delimiter)
|
|
||||||
|
|
||||||
if isinstance(path, list) and len(path) > 1:
|
|
||||||
data = data[path.pop(0)]
|
|
||||||
path = delimiter.join(path)
|
|
||||||
return self._get_data_entry(path, data, delimiter) # recursion
|
|
||||||
return data[path]
|
|
||||||
except KeyError:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def _set_data_entry(self, container_name, key, value, path=None):
|
|
||||||
"""Helper to save data
|
|
||||||
|
|
||||||
Helper to save the data in self.data
|
|
||||||
Detect if data is allready in branch and use dict_merge() to prevent that branch is overwritten.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
str(container_name): name of container
|
|
||||||
str(key): same as dict
|
|
||||||
*(value): same as dict
|
|
||||||
Kwargs:
|
|
||||||
str(path): path to branch-part
|
|
||||||
Raises:
|
|
||||||
AnsibleParserError
|
|
||||||
Returns:
|
|
||||||
None"""
|
|
||||||
if not path:
|
|
||||||
path = self.data['inventory']
|
|
||||||
if container_name not in path:
|
|
||||||
path[container_name] = {}
|
|
||||||
|
|
||||||
try:
|
|
||||||
if isinstance(value, dict) and key in path[container_name]:
|
|
||||||
path[container_name] = dict_merge(value, path[container_name][key])
|
|
||||||
else:
|
|
||||||
path[container_name][key] = value
|
|
||||||
except KeyError as err:
|
|
||||||
raise AnsibleParserError("Unable to store Informations: {0}".format(to_native(err)))
|
|
||||||
|
|
||||||
def extract_information_from_container_configs(self):
|
|
||||||
"""Process configuration information
|
|
||||||
|
|
||||||
Preparation of the data
|
|
||||||
|
|
||||||
Args:
|
|
||||||
dict(configs): Container configurations
|
|
||||||
Kwargs:
|
|
||||||
None
|
|
||||||
Raises:
|
|
||||||
None
|
|
||||||
Returns:
|
|
||||||
None"""
|
|
||||||
# create branch "inventory"
|
|
||||||
if 'inventory' not in self.data:
|
|
||||||
self.data['inventory'] = {}
|
|
||||||
|
|
||||||
for container_name in self.data['containers']:
|
|
||||||
self._set_data_entry(container_name, 'os', self._get_data_entry(
|
|
||||||
'containers/{0}/containers/metadata/config/image.os'.format(container_name)))
|
|
||||||
self._set_data_entry(container_name, 'release', self._get_data_entry(
|
|
||||||
'containers/{0}/containers/metadata/config/image.release'.format(container_name)))
|
|
||||||
self._set_data_entry(container_name, 'version', self._get_data_entry(
|
|
||||||
'containers/{0}/containers/metadata/config/image.version'.format(container_name)))
|
|
||||||
self._set_data_entry(container_name, 'profile', self._get_data_entry(
|
|
||||||
'containers/{0}/containers/metadata/profiles'.format(container_name)))
|
|
||||||
self._set_data_entry(container_name, 'location', self._get_data_entry(
|
|
||||||
'containers/{0}/containers/metadata/location'.format(container_name)))
|
|
||||||
self._set_data_entry(container_name, 'state', self._get_data_entry(
|
|
||||||
'containers/{0}/containers/metadata/config/volatile.last_state.power'.format(container_name)))
|
|
||||||
self._set_data_entry(container_name, 'network_interfaces', self.extract_network_information_from_container_config(container_name))
|
|
||||||
self._set_data_entry(container_name, 'preferred_interface', self.get_prefered_container_network_interface(container_name))
|
|
||||||
self._set_data_entry(container_name, 'vlan_ids', self.get_container_vlans(container_name))
|
|
||||||
|
|
||||||
def build_inventory_network(self, container_name):
|
|
||||||
"""Add the network interfaces of the container to the inventory
|
|
||||||
|
|
||||||
Logic:
|
|
||||||
- if the container have no interface -> 'ansible_connection: local'
|
|
||||||
- get preferred_interface & prefered_container_network_family -> 'ansible_connection: ssh' & 'ansible_host: <IP>'
|
|
||||||
- first Interface from: network_interfaces prefered_container_network_family -> 'ansible_connection: ssh' & 'ansible_host: <IP>'
|
|
||||||
|
|
||||||
Args:
|
|
||||||
str(container_name): name of container
|
|
||||||
Kwargs:
|
|
||||||
None
|
|
||||||
Raises:
|
|
||||||
None
|
|
||||||
Returns:
|
|
||||||
None"""
|
|
||||||
|
|
||||||
def interface_selection(container_name):
|
|
||||||
"""Select container Interface for inventory
|
|
||||||
|
|
||||||
Logic:
|
|
||||||
- get preferred_interface & prefered_container_network_family -> str(IP)
|
|
||||||
- first Interface from: network_interfaces prefered_container_network_family -> str(IP)
|
|
||||||
|
|
||||||
Args:
|
|
||||||
str(container_name): name of container
|
|
||||||
Kwargs:
|
|
||||||
None
|
|
||||||
Raises:
|
|
||||||
None
|
|
||||||
Returns:
|
|
||||||
dict(interface_name: ip)"""
|
|
||||||
prefered_interface = self._get_data_entry('inventory/{0}/preferred_interface'.format(container_name)) # name or None
|
|
||||||
prefered_container_network_family = self.prefered_container_network_family
|
|
||||||
|
|
||||||
ip_address = ''
|
|
||||||
if prefered_interface:
|
|
||||||
interface = self._get_data_entry('inventory/{0}/network_interfaces/{1}'.format(container_name, prefered_interface))
|
|
||||||
for config in interface:
|
|
||||||
if config['family'] == prefered_container_network_family:
|
|
||||||
ip_address = config['address']
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
interface = self._get_data_entry('inventory/{0}/network_interfaces'.format(container_name))
|
|
||||||
for config in interface:
|
|
||||||
if config['family'] == prefered_container_network_family:
|
|
||||||
ip_address = config['address']
|
|
||||||
break
|
|
||||||
return ip_address
|
|
||||||
|
|
||||||
if self._get_data_entry('inventory/{0}/network_interfaces'.format(container_name)): # container have network interfaces
|
|
||||||
if self._get_data_entry('inventory/{0}/preferred_interface'.format(container_name)): # container have a preferred interface
|
|
||||||
self.inventory.set_variable(container_name, 'ansible_connection', 'ssh')
|
|
||||||
self.inventory.set_variable(container_name, 'ansible_host', interface_selection(container_name))
|
|
||||||
else:
|
|
||||||
self.inventory.set_variable(container_name, 'ansible_connection', 'local')
|
|
||||||
|
|
||||||
def build_inventory_hosts(self):
|
|
||||||
"""Build host-part dynamic inventory
|
|
||||||
|
|
||||||
Build the host-part of the dynamic inventory.
|
|
||||||
Add Hosts and host_vars to the inventory.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
None
|
|
||||||
Kwargs:
|
|
||||||
None
|
|
||||||
Raises:
|
|
||||||
None
|
|
||||||
Returns:
|
|
||||||
None"""
|
|
||||||
for container_name in self.data['inventory']:
|
|
||||||
# Only consider containers that match the "state" filter, if self.state is not None
|
|
||||||
if self.filter:
|
|
||||||
if self.filter.lower() != self._get_data_entry('inventory/{0}/state'.format(container_name)).lower():
|
|
||||||
continue
|
|
||||||
# add container
|
|
||||||
self.inventory.add_host(container_name)
|
|
||||||
# add network informations
|
|
||||||
self.build_inventory_network(container_name)
|
|
||||||
# add os
|
|
||||||
self.inventory.set_variable(container_name, 'ansible_lxd_os', self._get_data_entry('inventory/{0}/os'.format(container_name)).lower())
|
|
||||||
# add release
|
|
||||||
self.inventory.set_variable(container_name, 'ansible_lxd_release', self._get_data_entry('inventory/{0}/release'.format(container_name)).lower())
|
|
||||||
# add profile
|
|
||||||
self.inventory.set_variable(container_name, 'ansible_lxd_profile', self._get_data_entry('inventory/{0}/profile'.format(container_name)))
|
|
||||||
# add state
|
|
||||||
self.inventory.set_variable(container_name, 'ansible_lxd_state', self._get_data_entry('inventory/{0}/state'.format(container_name)).lower())
|
|
||||||
# add location information
|
|
||||||
if self._get_data_entry('inventory/{0}/location'.format(container_name)) != "none": # wrong type by lxd 'none' != 'None'
|
|
||||||
self.inventory.set_variable(container_name, 'ansible_lxd_location', self._get_data_entry('inventory/{0}/location'.format(container_name)))
|
|
||||||
# add VLAN_ID information
|
|
||||||
if self._get_data_entry('inventory/{0}/vlan_ids'.format(container_name)):
|
|
||||||
self.inventory.set_variable(container_name, 'ansible_lxd_vlan_ids', self._get_data_entry('inventory/{0}/vlan_ids'.format(container_name)))
|
|
||||||
|
|
||||||
def build_inventory_groups_location(self, group_name):
|
|
||||||
"""create group by attribute: location
|
|
||||||
|
|
||||||
Args:
|
|
||||||
str(group_name): Group name
|
|
||||||
Kwargs:
|
|
||||||
None
|
|
||||||
Raises:
|
|
||||||
None
|
|
||||||
Returns:
|
|
||||||
None"""
|
|
||||||
# maybe we just want to expand one group
|
|
||||||
if group_name not in self.inventory.groups:
|
|
||||||
self.inventory.add_group(group_name)
|
|
||||||
|
|
||||||
for container_name in self.inventory.hosts:
|
|
||||||
if 'ansible_lxd_location' in self.inventory.get_host(container_name).get_vars():
|
|
||||||
self.inventory.add_child(group_name, container_name)
|
|
||||||
|
|
||||||
def build_inventory_groups_pattern(self, group_name):
|
|
||||||
"""create group by name pattern
|
|
||||||
|
|
||||||
Args:
|
|
||||||
str(group_name): Group name
|
|
||||||
Kwargs:
|
|
||||||
None
|
|
||||||
Raises:
|
|
||||||
None
|
|
||||||
Returns:
|
|
||||||
None"""
|
|
||||||
# maybe we just want to expand one group
|
|
||||||
if group_name not in self.inventory.groups:
|
|
||||||
self.inventory.add_group(group_name)
|
|
||||||
|
|
||||||
regex_pattern = self.groupby[group_name].get('attribute')
|
|
||||||
|
|
||||||
for container_name in self.inventory.hosts:
|
|
||||||
result = re.search(regex_pattern, container_name)
|
|
||||||
if result:
|
|
||||||
self.inventory.add_child(group_name, container_name)
|
|
||||||
|
|
||||||
def build_inventory_groups_network_range(self, group_name):
|
|
||||||
"""check if IP is in network-class
|
|
||||||
|
|
||||||
Args:
|
|
||||||
str(group_name): Group name
|
|
||||||
Kwargs:
|
|
||||||
None
|
|
||||||
Raises:
|
|
||||||
None
|
|
||||||
Returns:
|
|
||||||
None"""
|
|
||||||
# maybe we just want to expand one group
|
|
||||||
if group_name not in self.inventory.groups:
|
|
||||||
self.inventory.add_group(group_name)
|
|
||||||
|
|
||||||
try:
|
|
||||||
network = ipaddress.ip_network(to_text(self.groupby[group_name].get('attribute')))
|
|
||||||
except ValueError as err:
|
|
||||||
raise AnsibleParserError(
|
|
||||||
'Error while parsing network range {0}: {1}'.format(self.groupby[group_name].get('attribute'), to_native(err)))
|
|
||||||
|
|
||||||
for container_name in self.inventory.hosts:
|
|
||||||
if self.data['inventory'][container_name].get('network_interfaces') is not None:
|
|
||||||
for interface in self.data['inventory'][container_name].get('network_interfaces'):
|
|
||||||
for interface_family in self.data['inventory'][container_name].get('network_interfaces')[interface]:
|
|
||||||
try:
|
|
||||||
address = ipaddress.ip_address(to_text(interface_family['address']))
|
|
||||||
if address.version == network.version and address in network:
|
|
||||||
self.inventory.add_child(group_name, container_name)
|
|
||||||
except ValueError:
|
|
||||||
# Ignore invalid IP addresses returned by lxd
|
|
||||||
pass
|
|
||||||
|
|
||||||
def build_inventory_groups_os(self, group_name):
|
|
||||||
"""create group by attribute: os
|
|
||||||
|
|
||||||
Args:
|
|
||||||
str(group_name): Group name
|
|
||||||
Kwargs:
|
|
||||||
Noneself.data['inventory'][container_name][interface]
|
|
||||||
Raises:
|
|
||||||
None
|
|
||||||
Returns:
|
|
||||||
None"""
|
|
||||||
# maybe we just want to expand one group
|
|
||||||
if group_name not in self.inventory.groups:
|
|
||||||
self.inventory.add_group(group_name)
|
|
||||||
|
|
||||||
gen_containers = [
|
|
||||||
container_name for container_name in self.inventory.hosts
|
|
||||||
if 'ansible_lxd_os' in self.inventory.get_host(container_name).get_vars()]
|
|
||||||
for container_name in gen_containers:
|
|
||||||
if self.groupby[group_name].get('attribute').lower() == self.inventory.get_host(container_name).get_vars().get('ansible_lxd_os'):
|
|
||||||
self.inventory.add_child(group_name, container_name)
|
|
||||||
|
|
||||||
def build_inventory_groups_release(self, group_name):
|
|
||||||
"""create group by attribute: release
|
|
||||||
|
|
||||||
Args:
|
|
||||||
str(group_name): Group name
|
|
||||||
Kwargs:
|
|
||||||
None
|
|
||||||
Raises:
|
|
||||||
None
|
|
||||||
Returns:
|
|
||||||
None"""
|
|
||||||
# maybe we just want to expand one group
|
|
||||||
if group_name not in self.inventory.groups:
|
|
||||||
self.inventory.add_group(group_name)
|
|
||||||
|
|
||||||
gen_containers = [
|
|
||||||
container_name for container_name in self.inventory.hosts
|
|
||||||
if 'ansible_lxd_release' in self.inventory.get_host(container_name).get_vars()]
|
|
||||||
for container_name in gen_containers:
|
|
||||||
if self.groupby[group_name].get('attribute').lower() == self.inventory.get_host(container_name).get_vars().get('ansible_lxd_release'):
|
|
||||||
self.inventory.add_child(group_name, container_name)
|
|
||||||
|
|
||||||
def build_inventory_groups_profile(self, group_name):
|
|
||||||
"""create group by attribute: profile
|
|
||||||
|
|
||||||
Args:
|
|
||||||
str(group_name): Group name
|
|
||||||
Kwargs:
|
|
||||||
None
|
|
||||||
Raises:
|
|
||||||
None
|
|
||||||
Returns:
|
|
||||||
None"""
|
|
||||||
# maybe we just want to expand one group
|
|
||||||
if group_name not in self.inventory.groups:
|
|
||||||
self.inventory.add_group(group_name)
|
|
||||||
|
|
||||||
gen_containers = [
|
|
||||||
container_name for container_name in self.inventory.hosts.keys()
|
|
||||||
if 'ansible_lxd_profile' in self.inventory.get_host(container_name).get_vars().keys()]
|
|
||||||
for container_name in gen_containers:
|
|
||||||
if self.groupby[group_name].get('attribute').lower() in self.inventory.get_host(container_name).get_vars().get('ansible_lxd_profile'):
|
|
||||||
self.inventory.add_child(group_name, container_name)
|
|
||||||
|
|
||||||
def build_inventory_groups_vlanid(self, group_name):
|
|
||||||
"""create group by attribute: vlanid
|
|
||||||
|
|
||||||
Args:
|
|
||||||
str(group_name): Group name
|
|
||||||
Kwargs:
|
|
||||||
None
|
|
||||||
Raises:
|
|
||||||
None
|
|
||||||
Returns:
|
|
||||||
None"""
|
|
||||||
# maybe we just want to expand one group
|
|
||||||
if group_name not in self.inventory.groups:
|
|
||||||
self.inventory.add_group(group_name)
|
|
||||||
|
|
||||||
gen_containers = [
|
|
||||||
container_name for container_name in self.inventory.hosts.keys()
|
|
||||||
if 'ansible_lxd_vlan_ids' in self.inventory.get_host(container_name).get_vars().keys()]
|
|
||||||
for container_name in gen_containers:
|
|
||||||
if self.groupby[group_name].get('attribute') in self.inventory.get_host(container_name).get_vars().get('ansible_lxd_vlan_ids').values():
|
|
||||||
self.inventory.add_child(group_name, container_name)
|
|
||||||
|
|
||||||
def build_inventory_groups(self):
|
|
||||||
"""Build group-part dynamic inventory
|
|
||||||
|
|
||||||
Build the group-part of the dynamic inventory.
|
|
||||||
Add groups to the inventory.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
None
|
|
||||||
Kwargs:
|
|
||||||
None
|
|
||||||
Raises:
|
|
||||||
None
|
|
||||||
Returns:
|
|
||||||
None"""
|
|
||||||
|
|
||||||
def group_type(group_name):
|
|
||||||
"""create groups defined by lxd.yml or defaultvalues
|
|
||||||
|
|
||||||
create groups defined by lxd.yml or defaultvalues
|
|
||||||
supportetd:
|
|
||||||
* 'location'
|
|
||||||
* 'pattern'
|
|
||||||
* 'network_range'
|
|
||||||
* 'os'
|
|
||||||
* 'release'
|
|
||||||
* 'profile'
|
|
||||||
* 'vlanid'
|
|
||||||
|
|
||||||
Args:
|
|
||||||
str(group_name): Group name
|
|
||||||
Kwargs:
|
|
||||||
None
|
|
||||||
Raises:
|
|
||||||
None
|
|
||||||
Returns:
|
|
||||||
None"""
|
|
||||||
|
|
||||||
# Due to the compatibility with python 2 no use of map
|
|
||||||
if self.groupby[group_name].get('type') == 'location':
|
|
||||||
self.build_inventory_groups_location(group_name)
|
|
||||||
elif self.groupby[group_name].get('type') == 'pattern':
|
|
||||||
self.build_inventory_groups_pattern(group_name)
|
|
||||||
elif self.groupby[group_name].get('type') == 'network_range':
|
|
||||||
self.build_inventory_groups_network_range(group_name)
|
|
||||||
elif self.groupby[group_name].get('type') == 'os':
|
|
||||||
self.build_inventory_groups_os(group_name)
|
|
||||||
elif self.groupby[group_name].get('type') == 'release':
|
|
||||||
self.build_inventory_groups_release(group_name)
|
|
||||||
elif self.groupby[group_name].get('type') == 'profile':
|
|
||||||
self.build_inventory_groups_profile(group_name)
|
|
||||||
elif self.groupby[group_name].get('type') == 'vlanid':
|
|
||||||
self.build_inventory_groups_vlanid(group_name)
|
|
||||||
else:
|
|
||||||
raise AnsibleParserError('Unknown group type: {0}'.format(to_native(group_name)))
|
|
||||||
|
|
||||||
if self.groupby:
|
|
||||||
for group_name in self.groupby:
|
|
||||||
if not group_name.isalnum():
|
|
||||||
raise AnsibleParserError('Invalid character(s) in groupname: {0}'.format(to_native(group_name)))
|
|
||||||
group_type(group_name)
|
|
||||||
|
|
||||||
def build_inventory(self):
|
|
||||||
"""Build dynamic inventory
|
|
||||||
|
|
||||||
Build the dynamic inventory.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
None
|
|
||||||
Kwargs:
|
|
||||||
None
|
|
||||||
Raises:
|
|
||||||
None
|
|
||||||
Returns:
|
|
||||||
None"""
|
|
||||||
|
|
||||||
self.build_inventory_hosts()
|
|
||||||
self.build_inventory_groups()
|
|
||||||
|
|
||||||
def _populate(self):
|
|
||||||
"""Return the hosts and groups
|
|
||||||
|
|
||||||
Returns the processed container configurations from the lxd import
|
|
||||||
|
|
||||||
Args:
|
|
||||||
None
|
|
||||||
Kwargs:
|
|
||||||
None
|
|
||||||
Raises:
|
|
||||||
None
|
|
||||||
Returns:
|
|
||||||
None"""
|
|
||||||
|
|
||||||
if len(self.data) == 0: # If no data is injected by unittests open socket
|
|
||||||
self.socket = self._connect_to_socket()
|
|
||||||
self.get_container_data(self._get_containers())
|
|
||||||
self.get_network_data(self._get_networks())
|
|
||||||
|
|
||||||
self.extract_information_from_container_configs()
|
|
||||||
|
|
||||||
# self.display.vvv(self.save_json_data([os.path.abspath(__file__)]))
|
|
||||||
|
|
||||||
self.build_inventory()
|
|
||||||
|
|
||||||
def parse(self, inventory, loader, path, cache):
|
|
||||||
"""Return dynamic inventory from source
|
|
||||||
|
|
||||||
Returns the processed inventory from the lxd import
|
|
||||||
|
|
||||||
Args:
|
|
||||||
str(inventory): inventory object with existing data and
|
|
||||||
the methods to add hosts/groups/variables
|
|
||||||
to inventory
|
|
||||||
str(loader): Ansible's DataLoader
|
|
||||||
str(path): path to the config
|
|
||||||
bool(cache): use or avoid caches
|
|
||||||
Kwargs:
|
|
||||||
None
|
|
||||||
Raises:
|
|
||||||
AnsibleParserError
|
|
||||||
Returns:
|
|
||||||
None"""
|
|
||||||
|
|
||||||
super(InventoryModule, self).parse(inventory, loader, path, cache=False)
|
|
||||||
# Read the inventory YAML file
|
|
||||||
self._read_config_data(path)
|
|
||||||
try:
|
|
||||||
self.client_key = self.get_option('client_key')
|
|
||||||
self.client_cert = self.get_option('client_cert')
|
|
||||||
self.debug = self.DEBUG
|
|
||||||
self.data = {} # store for inventory-data
|
|
||||||
self.groupby = self.get_option('groupby')
|
|
||||||
self.plugin = self.get_option('plugin')
|
|
||||||
self.prefered_container_network_family = self.get_option('prefered_container_network_family')
|
|
||||||
self.prefered_container_network_interface = self.get_option('prefered_container_network_interface')
|
|
||||||
if self.get_option('state').lower() == 'none': # none in config is str()
|
|
||||||
self.filter = None
|
|
||||||
else:
|
|
||||||
self.filter = self.get_option('state').lower()
|
|
||||||
self.trust_password = self.get_option('trust_password')
|
|
||||||
self.url = self.get_option('url')
|
|
||||||
except Exception as err:
|
|
||||||
raise AnsibleParserError(
|
|
||||||
'All correct options required: {0}'.format(to_native(err)))
|
|
||||||
# Call our internal helper to populate the dynamic inventory
|
|
||||||
self._populate()
|
|
||||||
@@ -71,25 +71,6 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
|||||||
self._nmap = None
|
self._nmap = None
|
||||||
super(InventoryModule, self).__init__()
|
super(InventoryModule, self).__init__()
|
||||||
|
|
||||||
def _populate(self, hosts):
|
|
||||||
# Use constructed if applicable
|
|
||||||
strict = self.get_option('strict')
|
|
||||||
|
|
||||||
for host in hosts:
|
|
||||||
hostname = host['name']
|
|
||||||
self.inventory.add_host(hostname)
|
|
||||||
for var, value in host.items():
|
|
||||||
self.inventory.set_variable(hostname, var, value)
|
|
||||||
|
|
||||||
# Composed variables
|
|
||||||
self._set_composite_vars(self.get_option('compose'), host, hostname, strict=strict)
|
|
||||||
|
|
||||||
# Complex groups based on jinja2 conditionals, hosts that meet the conditional are added to group
|
|
||||||
self._add_host_to_composed_groups(self.get_option('groups'), host, hostname, strict=strict)
|
|
||||||
|
|
||||||
# Create groups based on variable values and add the corresponding hosts to it
|
|
||||||
self._add_host_to_keyed_groups(self.get_option('keyed_groups'), host, hostname, strict=strict)
|
|
||||||
|
|
||||||
def verify_file(self, path):
|
def verify_file(self, path):
|
||||||
|
|
||||||
valid = False
|
valid = False
|
||||||
@@ -101,7 +82,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
|||||||
|
|
||||||
return valid
|
return valid
|
||||||
|
|
||||||
def parse(self, inventory, loader, path, cache=True):
|
def parse(self, inventory, loader, path, cache=False):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self._nmap = get_bin_path('nmap')
|
self._nmap = get_bin_path('nmap')
|
||||||
@@ -112,101 +93,75 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
|||||||
|
|
||||||
self._read_config_data(path)
|
self._read_config_data(path)
|
||||||
|
|
||||||
cache_key = self.get_cache_key(path)
|
# setup command
|
||||||
|
cmd = [self._nmap]
|
||||||
|
if not self._options['ports']:
|
||||||
|
cmd.append('-sP')
|
||||||
|
|
||||||
# cache may be True or False at this point to indicate if the inventory is being refreshed
|
if self._options['ipv4'] and not self._options['ipv6']:
|
||||||
# get the user's cache option too to see if we should save the cache if it is changing
|
cmd.append('-4')
|
||||||
user_cache_setting = self.get_option('cache')
|
elif self._options['ipv6'] and not self._options['ipv4']:
|
||||||
|
cmd.append('-6')
|
||||||
|
elif not self._options['ipv6'] and not self._options['ipv4']:
|
||||||
|
raise AnsibleParserError('One of ipv4 or ipv6 must be enabled for this plugin')
|
||||||
|
|
||||||
# read if the user has caching enabled and the cache isn't being refreshed
|
if self._options['exclude']:
|
||||||
attempt_to_read_cache = user_cache_setting and cache
|
cmd.append('--exclude')
|
||||||
# update if the user has caching enabled and the cache is being refreshed; update this value to True if the cache has expired below
|
cmd.append(','.join(self._options['exclude']))
|
||||||
cache_needs_update = user_cache_setting and not cache
|
|
||||||
|
cmd.append(self._options['address'])
|
||||||
|
try:
|
||||||
|
# execute
|
||||||
|
p = Popen(cmd, stdout=PIPE, stderr=PIPE)
|
||||||
|
stdout, stderr = p.communicate()
|
||||||
|
if p.returncode != 0:
|
||||||
|
raise AnsibleParserError('Failed to run nmap, rc=%s: %s' % (p.returncode, to_native(stderr)))
|
||||||
|
|
||||||
|
# parse results
|
||||||
|
host = None
|
||||||
|
ip = None
|
||||||
|
ports = []
|
||||||
|
|
||||||
if attempt_to_read_cache:
|
|
||||||
try:
|
try:
|
||||||
results = self._cache[cache_key]
|
t_stdout = to_text(stdout, errors='surrogate_or_strict')
|
||||||
except KeyError:
|
except UnicodeError as e:
|
||||||
# This occurs if the cache_key is not in the cache or if the cache_key expired, so the cache needs to be updated
|
raise AnsibleParserError('Invalid (non unicode) input returned: %s' % to_native(e))
|
||||||
cache_needs_update = True
|
|
||||||
|
|
||||||
if cache_needs_update:
|
for line in t_stdout.splitlines():
|
||||||
# setup command
|
hits = self.find_host.match(line)
|
||||||
cmd = [self._nmap]
|
if hits:
|
||||||
if not self._options['ports']:
|
if host is not None:
|
||||||
cmd.append('-sP')
|
self.inventory.set_variable(host, 'ports', ports)
|
||||||
|
|
||||||
if self._options['ipv4'] and not self._options['ipv6']:
|
# if dns only shows arpa, just use ip instead as hostname
|
||||||
cmd.append('-4')
|
if hits.group(1).endswith('.in-addr.arpa'):
|
||||||
elif self._options['ipv6'] and not self._options['ipv4']:
|
host = hits.group(2)
|
||||||
cmd.append('-6')
|
else:
|
||||||
elif not self._options['ipv6'] and not self._options['ipv4']:
|
host = hits.group(1)
|
||||||
raise AnsibleParserError('One of ipv4 or ipv6 must be enabled for this plugin')
|
|
||||||
|
|
||||||
if self._options['exclude']:
|
# if no reverse dns exists, just use ip instead as hostname
|
||||||
cmd.append('--exclude')
|
if hits.group(2) is not None:
|
||||||
cmd.append(','.join(self._options['exclude']))
|
ip = hits.group(2)
|
||||||
|
else:
|
||||||
|
ip = hits.group(1)
|
||||||
|
|
||||||
cmd.append(self._options['address'])
|
if host is not None:
|
||||||
try:
|
# update inventory
|
||||||
# execute
|
self.inventory.add_host(host)
|
||||||
p = Popen(cmd, stdout=PIPE, stderr=PIPE)
|
self.inventory.set_variable(host, 'ip', ip)
|
||||||
stdout, stderr = p.communicate()
|
ports = []
|
||||||
if p.returncode != 0:
|
continue
|
||||||
raise AnsibleParserError('Failed to run nmap, rc=%s: %s' % (p.returncode, to_native(stderr)))
|
|
||||||
|
|
||||||
# parse results
|
host_ports = self.find_port.match(line)
|
||||||
host = None
|
if host is not None and host_ports:
|
||||||
ip = None
|
ports.append({'port': host_ports.group(1), 'protocol': host_ports.group(2), 'state': host_ports.group(3), 'service': host_ports.group(4)})
|
||||||
ports = []
|
continue
|
||||||
results = []
|
|
||||||
|
|
||||||
try:
|
# TODO: parse more data, OS?
|
||||||
t_stdout = to_text(stdout, errors='surrogate_or_strict')
|
|
||||||
except UnicodeError as e:
|
|
||||||
raise AnsibleParserError('Invalid (non unicode) input returned: %s' % to_native(e))
|
|
||||||
|
|
||||||
for line in t_stdout.splitlines():
|
# if any leftovers
|
||||||
hits = self.find_host.match(line)
|
if host and ports:
|
||||||
if hits:
|
self.inventory.set_variable(host, 'ports', ports)
|
||||||
if host is not None and ports:
|
|
||||||
results[-1]['ports'] = ports
|
|
||||||
|
|
||||||
# if dns only shows arpa, just use ip instead as hostname
|
except Exception as e:
|
||||||
if hits.group(1).endswith('.in-addr.arpa'):
|
raise AnsibleParserError("failed to parse %s: %s " % (to_native(path), to_native(e)))
|
||||||
host = hits.group(2)
|
|
||||||
else:
|
|
||||||
host = hits.group(1)
|
|
||||||
|
|
||||||
# if no reverse dns exists, just use ip instead as hostname
|
|
||||||
if hits.group(2) is not None:
|
|
||||||
ip = hits.group(2)
|
|
||||||
else:
|
|
||||||
ip = hits.group(1)
|
|
||||||
|
|
||||||
if host is not None:
|
|
||||||
# update inventory
|
|
||||||
results.append(dict())
|
|
||||||
results[-1]['name'] = host
|
|
||||||
results[-1]['ip'] = ip
|
|
||||||
ports = []
|
|
||||||
continue
|
|
||||||
|
|
||||||
host_ports = self.find_port.match(line)
|
|
||||||
if host is not None and host_ports:
|
|
||||||
ports.append({'port': host_ports.group(1),
|
|
||||||
'protocol': host_ports.group(2),
|
|
||||||
'state': host_ports.group(3),
|
|
||||||
'service': host_ports.group(4)})
|
|
||||||
continue
|
|
||||||
|
|
||||||
# if any leftovers
|
|
||||||
if host and ports:
|
|
||||||
results[-1]['ports'] = ports
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
raise AnsibleParserError("failed to parse %s: %s " % (to_native(path), to_native(e)))
|
|
||||||
|
|
||||||
self._cache[cache_key] = results
|
|
||||||
|
|
||||||
self._populate(results)
|
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ DOCUMENTATION = '''
|
|||||||
- Will retrieve the first network interface with an IP for Proxmox nodes.
|
- Will retrieve the first network interface with an IP for Proxmox nodes.
|
||||||
- Can retrieve LXC/QEMU configuration as facts.
|
- Can retrieve LXC/QEMU configuration as facts.
|
||||||
extends_documentation_fragment:
|
extends_documentation_fragment:
|
||||||
- constructed
|
|
||||||
- inventory_cache
|
- inventory_cache
|
||||||
options:
|
options:
|
||||||
plugin:
|
plugin:
|
||||||
@@ -70,21 +69,6 @@ DOCUMENTATION = '''
|
|||||||
description: Gather LXC/QEMU configuration facts.
|
description: Gather LXC/QEMU configuration facts.
|
||||||
default: no
|
default: no
|
||||||
type: bool
|
type: bool
|
||||||
want_proxmox_nodes_ansible_host:
|
|
||||||
version_added: 3.0.0
|
|
||||||
description:
|
|
||||||
- Whether to set C(ansbile_host) for proxmox nodes.
|
|
||||||
- When set to C(true) (default), will use the first available interface. This can be different from what you expect.
|
|
||||||
default: true
|
|
||||||
type: bool
|
|
||||||
strict:
|
|
||||||
version_added: 2.5.0
|
|
||||||
compose:
|
|
||||||
version_added: 2.5.0
|
|
||||||
groups:
|
|
||||||
version_added: 2.5.0
|
|
||||||
keyed_groups:
|
|
||||||
version_added: 2.5.0
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
EXAMPLES = '''
|
EXAMPLES = '''
|
||||||
@@ -94,15 +78,6 @@ url: http://localhost:8006
|
|||||||
user: ansible@pve
|
user: ansible@pve
|
||||||
password: secure
|
password: secure
|
||||||
validate_certs: no
|
validate_certs: no
|
||||||
keyed_groups:
|
|
||||||
- key: proxmox_tags_parsed
|
|
||||||
separator: ""
|
|
||||||
prefix: group
|
|
||||||
groups:
|
|
||||||
webservers: "'web' in (proxmox_tags_parsed|list)"
|
|
||||||
mailservers: "'mail' in (proxmox_tags_parsed|list)"
|
|
||||||
compose:
|
|
||||||
ansible_port: 2222
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import re
|
import re
|
||||||
@@ -111,7 +86,7 @@ from ansible.module_utils.common._collections_compat import MutableMapping
|
|||||||
from distutils.version import LooseVersion
|
from distutils.version import LooseVersion
|
||||||
|
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable
|
from ansible.plugins.inventory import BaseInventoryPlugin, Cacheable
|
||||||
from ansible.module_utils.six.moves.urllib.parse import urlencode
|
from ansible.module_utils.six.moves.urllib.parse import urlencode
|
||||||
|
|
||||||
# 3rd party imports
|
# 3rd party imports
|
||||||
@@ -124,7 +99,7 @@ except ImportError:
|
|||||||
HAS_REQUESTS = False
|
HAS_REQUESTS = False
|
||||||
|
|
||||||
|
|
||||||
class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
class InventoryModule(BaseInventoryPlugin, Cacheable):
|
||||||
''' Host inventory parser for ansible using Proxmox as source. '''
|
''' Host inventory parser for ansible using Proxmox as source. '''
|
||||||
|
|
||||||
NAME = 'community.general.proxmox'
|
NAME = 'community.general.proxmox'
|
||||||
@@ -231,45 +206,9 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
|||||||
except Exception:
|
except Exception:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _get_agent_network_interfaces(self, node, vmid, vmtype):
|
|
||||||
result = []
|
|
||||||
|
|
||||||
try:
|
|
||||||
ifaces = self._get_json(
|
|
||||||
"%s/api2/json/nodes/%s/%s/%s/agent/network-get-interfaces" % (
|
|
||||||
self.proxmox_url, node, vmtype, vmid
|
|
||||||
)
|
|
||||||
)['result']
|
|
||||||
|
|
||||||
if "error" in ifaces:
|
|
||||||
if "class" in ifaces["error"]:
|
|
||||||
# This happens on Windows, even though qemu agent is running, the IP address
|
|
||||||
# cannot be fetched, as it's unsupported, also a command disabled can happen.
|
|
||||||
errorClass = ifaces["error"]["class"]
|
|
||||||
if errorClass in ["Unsupported"]:
|
|
||||||
self.display.v("Retrieving network interfaces from guest agents on windows with older qemu-guest-agents is not supported")
|
|
||||||
elif errorClass in ["CommandDisabled"]:
|
|
||||||
self.display.v("Retrieving network interfaces from guest agents has been disabled")
|
|
||||||
return result
|
|
||||||
|
|
||||||
for iface in ifaces:
|
|
||||||
result.append({
|
|
||||||
'name': iface['name'],
|
|
||||||
'mac-address': iface['hardware-address'] if 'hardware-address' in iface else '',
|
|
||||||
'ip-addresses': ["%s/%s" % (ip['ip-address'], ip['prefix']) for ip in iface['ip-addresses']] if 'ip-addresses' in iface else []
|
|
||||||
})
|
|
||||||
except requests.HTTPError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
def _get_vm_config(self, node, vmid, vmtype, name):
|
def _get_vm_config(self, node, vmid, vmtype, name):
|
||||||
ret = self._get_json("%s/api2/json/nodes/%s/%s/%s/config" % (self.proxmox_url, node, vmtype, vmid))
|
ret = self._get_json("%s/api2/json/nodes/%s/%s/%s/config" % (self.proxmox_url, node, vmtype, vmid))
|
||||||
|
|
||||||
node_key = 'node'
|
|
||||||
node_key = self.to_safe('%s%s' % (self.get_option('facts_prefix'), node_key.lower()))
|
|
||||||
self.inventory.set_variable(name, node_key, node)
|
|
||||||
|
|
||||||
vmid_key = 'vmid'
|
vmid_key = 'vmid'
|
||||||
vmid_key = self.to_safe('%s%s' % (self.get_option('facts_prefix'), vmid_key.lower()))
|
vmid_key = self.to_safe('%s%s' % (self.get_option('facts_prefix'), vmid_key.lower()))
|
||||||
self.inventory.set_variable(name, vmid_key, vmid)
|
self.inventory.set_variable(name, vmid_key, vmid)
|
||||||
@@ -297,14 +236,6 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
|||||||
parsed_value = [tag.strip() for tag in value.split(",")]
|
parsed_value = [tag.strip() for tag in value.split(",")]
|
||||||
self.inventory.set_variable(name, parsed_key, parsed_value)
|
self.inventory.set_variable(name, parsed_key, parsed_value)
|
||||||
|
|
||||||
# The first field in the agent string tells you whether the agent is enabled
|
|
||||||
# the rest of the comma separated string is extra config for the agent
|
|
||||||
if config == 'agent' and int(value.split(',')[0]):
|
|
||||||
agent_iface_key = self.to_safe('%s%s' % (key, "_interfaces"))
|
|
||||||
agent_iface_value = self._get_agent_network_interfaces(node, vmid, vmtype)
|
|
||||||
if agent_iface_value:
|
|
||||||
self.inventory.set_variable(name, agent_iface_key, agent_iface_value)
|
|
||||||
|
|
||||||
if not (isinstance(value, int) or ',' not in value):
|
if not (isinstance(value, int) or ',' not in value):
|
||||||
# split off strings with commas to a dict
|
# split off strings with commas to a dict
|
||||||
# skip over any keys that cannot be processed
|
# skip over any keys that cannot be processed
|
||||||
@@ -333,12 +264,6 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
|||||||
regex = r"[^A-Za-z0-9\_]"
|
regex = r"[^A-Za-z0-9\_]"
|
||||||
return re.sub(regex, "_", word.replace(" ", ""))
|
return re.sub(regex, "_", word.replace(" ", ""))
|
||||||
|
|
||||||
def _apply_constructable(self, name, variables):
|
|
||||||
strict = self.get_option('strict')
|
|
||||||
self._add_host_to_composed_groups(self.get_option('groups'), variables, name, strict=strict)
|
|
||||||
self._add_host_to_keyed_groups(self.get_option('keyed_groups'), variables, name, strict=strict)
|
|
||||||
self._set_composite_vars(self.get_option('compose'), variables, name, strict=strict)
|
|
||||||
|
|
||||||
def _populate(self):
|
def _populate(self):
|
||||||
|
|
||||||
self._get_auth()
|
self._get_auth()
|
||||||
@@ -370,9 +295,8 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
|||||||
self.inventory.add_child(nodes_group, node['node'])
|
self.inventory.add_child(nodes_group, node['node'])
|
||||||
|
|
||||||
# get node IP address
|
# get node IP address
|
||||||
if self.get_option("want_proxmox_nodes_ansible_host"):
|
ip = self._get_node_ip(node['node'])
|
||||||
ip = self._get_node_ip(node['node'])
|
self.inventory.set_variable(node['node'], 'ansible_host', ip)
|
||||||
self.inventory.set_variable(node['node'], 'ansible_host', ip)
|
|
||||||
|
|
||||||
# get LXC containers for this node
|
# get LXC containers for this node
|
||||||
node_lxc_group = self.to_safe('%s%s' % (self.get_option('group_prefix'), ('%s_lxc' % node['node']).lower()))
|
node_lxc_group = self.to_safe('%s%s' % (self.get_option('group_prefix'), ('%s_lxc' % node['node']).lower()))
|
||||||
@@ -394,8 +318,6 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
|||||||
if self.get_option('want_facts'):
|
if self.get_option('want_facts'):
|
||||||
self._get_vm_config(node['node'], lxc['vmid'], 'lxc', lxc['name'])
|
self._get_vm_config(node['node'], lxc['vmid'], 'lxc', lxc['name'])
|
||||||
|
|
||||||
self._apply_constructable(lxc["name"], self.inventory.get_host(lxc['name']).get_vars())
|
|
||||||
|
|
||||||
# get QEMU vm's for this node
|
# get QEMU vm's for this node
|
||||||
node_qemu_group = self.to_safe('%s%s' % (self.get_option('group_prefix'), ('%s_qemu' % node['node']).lower()))
|
node_qemu_group = self.to_safe('%s%s' % (self.get_option('group_prefix'), ('%s_qemu' % node['node']).lower()))
|
||||||
self.inventory.add_group(node_qemu_group)
|
self.inventory.add_group(node_qemu_group)
|
||||||
@@ -418,8 +340,6 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
|||||||
if self.get_option('want_facts'):
|
if self.get_option('want_facts'):
|
||||||
self._get_vm_config(node['node'], qemu['vmid'], 'qemu', qemu['name'])
|
self._get_vm_config(node['node'], qemu['vmid'], 'qemu', qemu['name'])
|
||||||
|
|
||||||
self._apply_constructable(qemu["name"], self.inventory.get_host(qemu['name']).get_vars())
|
|
||||||
|
|
||||||
# gather vm's in pools
|
# gather vm's in pools
|
||||||
for pool in self._get_pools():
|
for pool in self._get_pools():
|
||||||
if pool.get('poolid'):
|
if pool.get('poolid'):
|
||||||
|
|||||||
@@ -102,13 +102,13 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
|||||||
raise AnsibleError("plugin doesn't match this plugin")
|
raise AnsibleError("plugin doesn't match this plugin")
|
||||||
try:
|
try:
|
||||||
client_id = config['client_id']
|
client_id = config['client_id']
|
||||||
if len(client_id) != 32:
|
if client_id != 32:
|
||||||
raise AnsibleError("client_id must be 32 characters long")
|
raise AnsibleError("client_id must be 32 characters long")
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise AnsibleError("config missing client_id, a required option")
|
raise AnsibleError("config missing client_id, a required option")
|
||||||
try:
|
try:
|
||||||
client_secret = config['client_secret']
|
client_secret = config['client_secret']
|
||||||
if len(client_secret) != 64:
|
if client_secret != 64:
|
||||||
raise AnsibleError("client_secret must be 64 characters long")
|
raise AnsibleError("client_secret must be 64 characters long")
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise AnsibleError("config missing client_id, a required option")
|
raise AnsibleError("config missing client_id, a required option")
|
||||||
|
|||||||
@@ -31,9 +31,7 @@ EXAMPLES = r"""
|
|||||||
- name: Template files (explicitly skip directories in order to use the 'src' attribute)
|
- name: Template files (explicitly skip directories in order to use the 'src' attribute)
|
||||||
ansible.builtin.template:
|
ansible.builtin.template:
|
||||||
src: '{{ item.src }}'
|
src: '{{ item.src }}'
|
||||||
# Your template files should be stored with a .j2 file extension,
|
dest: /web/{{ item.path }}
|
||||||
# but should not be deployed with it. splitext|first removes it.
|
|
||||||
dest: /web/{{ item.path | splitext | first }}
|
|
||||||
mode: '{{ item.mode }}'
|
mode: '{{ item.mode }}'
|
||||||
with_community.general.filetree: web/
|
with_community.general.filetree: web/
|
||||||
when: item.state == 'file'
|
when: item.state == 'file'
|
||||||
@@ -43,7 +41,6 @@ EXAMPLES = r"""
|
|||||||
src: '{{ item.src }}'
|
src: '{{ item.src }}'
|
||||||
dest: /web/{{ item.path }}
|
dest: /web/{{ item.path }}
|
||||||
state: link
|
state: link
|
||||||
follow: false # avoid corrupting target files if the link already exists
|
|
||||||
force: yes
|
force: yes
|
||||||
mode: '{{ item.mode }}'
|
mode: '{{ item.mode }}'
|
||||||
with_community.general.filetree: web/
|
with_community.general.filetree: web/
|
||||||
|
|||||||
@@ -63,7 +63,6 @@ import os
|
|||||||
|
|
||||||
from ansible.plugins.lookup import LookupBase
|
from ansible.plugins.lookup import LookupBase
|
||||||
from ansible.utils.cmd_functions import run_cmd
|
from ansible.utils.cmd_functions import run_cmd
|
||||||
from ansible.module_utils._text import to_text
|
|
||||||
|
|
||||||
ANSIBLE_HIERA_CFG = os.getenv('ANSIBLE_HIERA_CFG', '/etc/hiera.yaml')
|
ANSIBLE_HIERA_CFG = os.getenv('ANSIBLE_HIERA_CFG', '/etc/hiera.yaml')
|
||||||
ANSIBLE_HIERA_BIN = os.getenv('ANSIBLE_HIERA_BIN', '/usr/bin/hiera')
|
ANSIBLE_HIERA_BIN = os.getenv('ANSIBLE_HIERA_BIN', '/usr/bin/hiera')
|
||||||
@@ -79,11 +78,13 @@ class Hiera(object):
|
|||||||
rc, output, err = run_cmd("{0} -c {1} {2}".format(
|
rc, output, err = run_cmd("{0} -c {1} {2}".format(
|
||||||
ANSIBLE_HIERA_BIN, ANSIBLE_HIERA_CFG, hiera_key[0]))
|
ANSIBLE_HIERA_BIN, ANSIBLE_HIERA_CFG, hiera_key[0]))
|
||||||
|
|
||||||
return to_text(output.strip())
|
return output.strip()
|
||||||
|
|
||||||
|
|
||||||
class LookupModule(LookupBase):
|
class LookupModule(LookupBase):
|
||||||
def run(self, terms, variables=''):
|
def run(self, terms, variables=''):
|
||||||
hiera = Hiera()
|
hiera = Hiera()
|
||||||
ret = [hiera.get(terms)]
|
ret = []
|
||||||
|
|
||||||
|
ret.append(hiera.get(terms))
|
||||||
return ret
|
return ret
|
||||||
|
|||||||
871
plugins/module_utils/_ovirt.py
Normal file
871
plugins/module_utils/_ovirt.py
Normal file
@@ -0,0 +1,871 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# This file is part of Ansible
|
||||||
|
#
|
||||||
|
# Ansible is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Ansible is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
import inspect
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
|
||||||
|
from abc import ABCMeta, abstractmethod
|
||||||
|
from datetime import datetime
|
||||||
|
from distutils.version import LooseVersion
|
||||||
|
|
||||||
|
from ansible_collections.community.general.plugins.module_utils.cloud import CloudRetry
|
||||||
|
from ansible.module_utils.common._collections_compat import Mapping
|
||||||
|
|
||||||
|
try:
|
||||||
|
from enum import Enum # enum is a ovirtsdk4 requirement
|
||||||
|
import ovirtsdk4 as sdk
|
||||||
|
import ovirtsdk4.version as sdk_version
|
||||||
|
import ovirtsdk4.types as otypes
|
||||||
|
HAS_SDK = LooseVersion(sdk_version.VERSION) >= LooseVersion('4.3.0')
|
||||||
|
except ImportError:
|
||||||
|
HAS_SDK = False
|
||||||
|
|
||||||
|
|
||||||
|
BYTES_MAP = {
|
||||||
|
'kib': 2**10,
|
||||||
|
'mib': 2**20,
|
||||||
|
'gib': 2**30,
|
||||||
|
'tib': 2**40,
|
||||||
|
'pib': 2**50,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def check_sdk(module):
|
||||||
|
if not HAS_SDK:
|
||||||
|
module.fail_json(
|
||||||
|
msg='ovirtsdk4 version 4.3.0 or higher is required for this module'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_dict_of_struct(struct, connection=None, fetch_nested=False, attributes=None):
|
||||||
|
"""
|
||||||
|
Convert SDK Struct type into dictionary.
|
||||||
|
"""
|
||||||
|
res = {}
|
||||||
|
|
||||||
|
def resolve_href(value):
|
||||||
|
# Fetch nested values of struct:
|
||||||
|
try:
|
||||||
|
value = connection.follow_link(value)
|
||||||
|
except sdk.Error:
|
||||||
|
value = None
|
||||||
|
nested_obj = dict(
|
||||||
|
(attr, convert_value(getattr(value, attr)))
|
||||||
|
for attr in attributes if getattr(value, attr, None) is not None
|
||||||
|
)
|
||||||
|
nested_obj['id'] = getattr(value, 'id', None)
|
||||||
|
nested_obj['href'] = getattr(value, 'href', None)
|
||||||
|
return nested_obj
|
||||||
|
|
||||||
|
def remove_underscore(val):
|
||||||
|
if val.startswith('_'):
|
||||||
|
val = val[1:]
|
||||||
|
remove_underscore(val)
|
||||||
|
return val
|
||||||
|
|
||||||
|
def convert_value(value):
|
||||||
|
nested = False
|
||||||
|
|
||||||
|
if isinstance(value, sdk.Struct):
|
||||||
|
if not fetch_nested or not value.href:
|
||||||
|
return get_dict_of_struct(value)
|
||||||
|
return resolve_href(value)
|
||||||
|
|
||||||
|
elif isinstance(value, Enum) or isinstance(value, datetime):
|
||||||
|
return str(value)
|
||||||
|
elif isinstance(value, list) or isinstance(value, sdk.List):
|
||||||
|
if isinstance(value, sdk.List) and fetch_nested and value.href:
|
||||||
|
try:
|
||||||
|
value = connection.follow_link(value)
|
||||||
|
nested = True
|
||||||
|
except sdk.Error:
|
||||||
|
value = []
|
||||||
|
|
||||||
|
ret = []
|
||||||
|
for i in value:
|
||||||
|
if isinstance(i, sdk.Struct):
|
||||||
|
if not nested and fetch_nested and i.href:
|
||||||
|
ret.append(resolve_href(i))
|
||||||
|
elif not nested:
|
||||||
|
ret.append(get_dict_of_struct(i))
|
||||||
|
else:
|
||||||
|
nested_obj = dict(
|
||||||
|
(attr, convert_value(getattr(i, attr)))
|
||||||
|
for attr in attributes if getattr(i, attr, None)
|
||||||
|
)
|
||||||
|
nested_obj['id'] = getattr(i, 'id', None)
|
||||||
|
ret.append(nested_obj)
|
||||||
|
elif isinstance(i, Enum):
|
||||||
|
ret.append(str(i))
|
||||||
|
else:
|
||||||
|
ret.append(i)
|
||||||
|
return ret
|
||||||
|
else:
|
||||||
|
return value
|
||||||
|
|
||||||
|
if struct is not None:
|
||||||
|
for key, value in struct.__dict__.items():
|
||||||
|
if value is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
key = remove_underscore(key)
|
||||||
|
res[key] = convert_value(value)
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
def engine_version(connection):
|
||||||
|
"""
|
||||||
|
Return string representation of oVirt engine version.
|
||||||
|
"""
|
||||||
|
engine_api = connection.system_service().get()
|
||||||
|
engine_version = engine_api.product_info.version
|
||||||
|
return '%s.%s' % (engine_version.major, engine_version.minor)
|
||||||
|
|
||||||
|
|
||||||
|
def create_connection(auth):
|
||||||
|
"""
|
||||||
|
Create a connection to Python SDK, from task `auth` parameter.
|
||||||
|
If user doesnt't have SSO token the `auth` dictionary has following parameters mandatory:
|
||||||
|
url, username, password
|
||||||
|
|
||||||
|
If user has SSO token the `auth` dictionary has following parameters mandatory:
|
||||||
|
url, token
|
||||||
|
|
||||||
|
The `ca_file` parameter is mandatory in case user want to use secure connection,
|
||||||
|
in case user want to use insecure connection, it's mandatory to send insecure=True.
|
||||||
|
|
||||||
|
:param auth: dictionary which contains needed values for connection creation
|
||||||
|
:return: Python SDK connection
|
||||||
|
"""
|
||||||
|
|
||||||
|
url = auth.get('url')
|
||||||
|
if url is None and auth.get('hostname') is not None:
|
||||||
|
url = 'https://{0}/ovirt-engine/api'.format(auth.get('hostname'))
|
||||||
|
|
||||||
|
return sdk.Connection(
|
||||||
|
url=url,
|
||||||
|
username=auth.get('username'),
|
||||||
|
password=auth.get('password'),
|
||||||
|
ca_file=auth.get('ca_file', None),
|
||||||
|
insecure=auth.get('insecure', False),
|
||||||
|
token=auth.get('token', None),
|
||||||
|
kerberos=auth.get('kerberos', None),
|
||||||
|
headers=auth.get('headers', None),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def convert_to_bytes(param):
|
||||||
|
"""
|
||||||
|
This method convert units to bytes, which follow IEC standard.
|
||||||
|
|
||||||
|
:param param: value to be converted
|
||||||
|
"""
|
||||||
|
if param is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Get rid of whitespaces:
|
||||||
|
param = ''.join(param.split())
|
||||||
|
|
||||||
|
# Convert to bytes:
|
||||||
|
if len(param) > 3 and param[-3].lower() in ['k', 'm', 'g', 't', 'p']:
|
||||||
|
return int(param[:-3]) * BYTES_MAP.get(param[-3:].lower(), 1)
|
||||||
|
elif param.isdigit():
|
||||||
|
return int(param) * 2**10
|
||||||
|
else:
|
||||||
|
raise ValueError(
|
||||||
|
"Unsupported value(IEC supported): '{value}'".format(value=param)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def follow_link(connection, link):
|
||||||
|
"""
|
||||||
|
This method returns the entity of the element which link points to.
|
||||||
|
|
||||||
|
:param connection: connection to the Python SDK
|
||||||
|
:param link: link of the entity
|
||||||
|
:return: entity which link points to
|
||||||
|
"""
|
||||||
|
|
||||||
|
if link:
|
||||||
|
return connection.follow_link(link)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_link_name(connection, link):
|
||||||
|
"""
|
||||||
|
This method returns the name of the element which link points to.
|
||||||
|
|
||||||
|
:param connection: connection to the Python SDK
|
||||||
|
:param link: link of the entity
|
||||||
|
:return: name of the entity, which link points to
|
||||||
|
"""
|
||||||
|
|
||||||
|
if link:
|
||||||
|
return connection.follow_link(link).name
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def equal(param1, param2, ignore_case=False):
|
||||||
|
"""
|
||||||
|
Compare two parameters and return if they are equal.
|
||||||
|
This parameter doesn't run equal operation if first parameter is None.
|
||||||
|
With this approach we don't run equal operation in case user don't
|
||||||
|
specify parameter in their task.
|
||||||
|
|
||||||
|
:param param1: user inputted parameter
|
||||||
|
:param param2: value of entity parameter
|
||||||
|
:return: True if parameters are equal or first parameter is None, otherwise False
|
||||||
|
"""
|
||||||
|
if param1 is not None:
|
||||||
|
if ignore_case:
|
||||||
|
return param1.lower() == param2.lower()
|
||||||
|
return param1 == param2
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def search_by_attributes(service, list_params=None, **kwargs):
|
||||||
|
"""
|
||||||
|
Search for the entity by attributes. Nested entities don't support search
|
||||||
|
via REST, so in case using search for nested entity we return all entities
|
||||||
|
and filter them by specified attributes.
|
||||||
|
"""
|
||||||
|
list_params = list_params or {}
|
||||||
|
# Check if 'list' method support search(look for search parameter):
|
||||||
|
if 'search' in inspect.getargspec(service.list)[0]:
|
||||||
|
res = service.list(
|
||||||
|
# There must be double quotes around name, because some oVirt resources it's possible to create then with space in name.
|
||||||
|
search=' and '.join('{0}="{1}"'.format(k, v) for k, v in kwargs.items()),
|
||||||
|
**list_params
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
res = [
|
||||||
|
e for e in service.list(**list_params) if len([
|
||||||
|
k for k, v in kwargs.items() if getattr(e, k, None) == v
|
||||||
|
]) == len(kwargs)
|
||||||
|
]
|
||||||
|
|
||||||
|
res = res or [None]
|
||||||
|
return res[0]
|
||||||
|
|
||||||
|
|
||||||
|
def search_by_name(service, name, **kwargs):
|
||||||
|
"""
|
||||||
|
Search for the entity by its name. Nested entities don't support search
|
||||||
|
via REST, so in case using search for nested entity we return all entities
|
||||||
|
and filter them by name.
|
||||||
|
|
||||||
|
:param service: service of the entity
|
||||||
|
:param name: name of the entity
|
||||||
|
:return: Entity object returned by Python SDK
|
||||||
|
"""
|
||||||
|
# Check if 'list' method support search(look for search parameter):
|
||||||
|
if 'search' in inspect.getargspec(service.list)[0]:
|
||||||
|
res = service.list(
|
||||||
|
# There must be double quotes around name, because some oVirt resources it's possible to create then with space in name.
|
||||||
|
search='name="{name}"'.format(name=name)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
res = [e for e in service.list() if e.name == name]
|
||||||
|
|
||||||
|
if kwargs:
|
||||||
|
res = [
|
||||||
|
e for e in service.list() if len([
|
||||||
|
k for k, v in kwargs.items() if getattr(e, k, None) == v
|
||||||
|
]) == len(kwargs)
|
||||||
|
]
|
||||||
|
|
||||||
|
res = res or [None]
|
||||||
|
return res[0]
|
||||||
|
|
||||||
|
|
||||||
|
def get_entity(service, get_params=None):
|
||||||
|
"""
|
||||||
|
Ignore SDK Error in case of getting an entity from service.
|
||||||
|
"""
|
||||||
|
entity = None
|
||||||
|
try:
|
||||||
|
if get_params is not None:
|
||||||
|
entity = service.get(**get_params)
|
||||||
|
else:
|
||||||
|
entity = service.get()
|
||||||
|
except sdk.Error:
|
||||||
|
# We can get here 404, we should ignore it, in case
|
||||||
|
# of removing entity for example.
|
||||||
|
pass
|
||||||
|
return entity
|
||||||
|
|
||||||
|
|
||||||
|
def get_id_by_name(service, name, raise_error=True, ignore_case=False):
|
||||||
|
"""
|
||||||
|
Search an entity ID by it's name.
|
||||||
|
"""
|
||||||
|
entity = search_by_name(service, name)
|
||||||
|
|
||||||
|
if entity is not None:
|
||||||
|
return entity.id
|
||||||
|
|
||||||
|
if raise_error:
|
||||||
|
raise Exception("Entity '%s' was not found." % name)
|
||||||
|
|
||||||
|
|
||||||
|
def wait(
|
||||||
|
service,
|
||||||
|
condition,
|
||||||
|
fail_condition=lambda e: False,
|
||||||
|
timeout=180,
|
||||||
|
wait=True,
|
||||||
|
poll_interval=3,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Wait until entity fulfill expected condition.
|
||||||
|
|
||||||
|
:param service: service of the entity
|
||||||
|
:param condition: condition to be fulfilled
|
||||||
|
:param fail_condition: if this condition is true, raise Exception
|
||||||
|
:param timeout: max time to wait in seconds
|
||||||
|
:param wait: if True wait for condition, if False don't wait
|
||||||
|
:param poll_interval: Number of seconds we should wait until next condition check
|
||||||
|
"""
|
||||||
|
# Wait until the desired state of the entity:
|
||||||
|
if wait:
|
||||||
|
start = time.time()
|
||||||
|
while time.time() < start + timeout:
|
||||||
|
# Exit if the condition of entity is valid:
|
||||||
|
entity = get_entity(service)
|
||||||
|
if condition(entity):
|
||||||
|
return
|
||||||
|
elif fail_condition(entity):
|
||||||
|
raise Exception("Error while waiting on result state of the entity.")
|
||||||
|
|
||||||
|
# Sleep for `poll_interval` seconds if none of the conditions apply:
|
||||||
|
time.sleep(float(poll_interval))
|
||||||
|
|
||||||
|
raise Exception("Timeout exceed while waiting on result state of the entity.")
|
||||||
|
|
||||||
|
|
||||||
|
def __get_auth_dict():
|
||||||
|
OVIRT_URL = os.environ.get('OVIRT_URL')
|
||||||
|
OVIRT_HOSTNAME = os.environ.get('OVIRT_HOSTNAME')
|
||||||
|
OVIRT_USERNAME = os.environ.get('OVIRT_USERNAME')
|
||||||
|
OVIRT_PASSWORD = os.environ.get('OVIRT_PASSWORD')
|
||||||
|
OVIRT_TOKEN = os.environ.get('OVIRT_TOKEN')
|
||||||
|
OVIRT_CAFILE = os.environ.get('OVIRT_CAFILE')
|
||||||
|
OVIRT_INSECURE = OVIRT_CAFILE is None
|
||||||
|
|
||||||
|
env_vars = None
|
||||||
|
if OVIRT_URL is None and OVIRT_HOSTNAME is not None:
|
||||||
|
OVIRT_URL = 'https://{0}/ovirt-engine/api'.format(OVIRT_HOSTNAME)
|
||||||
|
if OVIRT_URL and ((OVIRT_USERNAME and OVIRT_PASSWORD) or OVIRT_TOKEN):
|
||||||
|
env_vars = {
|
||||||
|
'url': OVIRT_URL,
|
||||||
|
'username': OVIRT_USERNAME,
|
||||||
|
'password': OVIRT_PASSWORD,
|
||||||
|
'insecure': OVIRT_INSECURE,
|
||||||
|
'token': OVIRT_TOKEN,
|
||||||
|
'ca_file': OVIRT_CAFILE,
|
||||||
|
}
|
||||||
|
if env_vars is not None:
|
||||||
|
auth = dict(default=env_vars, type='dict')
|
||||||
|
else:
|
||||||
|
auth = dict(required=True, type='dict')
|
||||||
|
|
||||||
|
return auth
|
||||||
|
|
||||||
|
|
||||||
|
def ovirt_info_full_argument_spec(**kwargs):
|
||||||
|
"""
|
||||||
|
Extend parameters of info module with parameters which are common to all
|
||||||
|
oVirt info modules.
|
||||||
|
|
||||||
|
:param kwargs: kwargs to be extended
|
||||||
|
:return: extended dictionary with common parameters
|
||||||
|
"""
|
||||||
|
spec = dict(
|
||||||
|
auth=__get_auth_dict(),
|
||||||
|
fetch_nested=dict(default=False, type='bool'),
|
||||||
|
nested_attributes=dict(type='list', default=list()),
|
||||||
|
)
|
||||||
|
spec.update(kwargs)
|
||||||
|
return spec
|
||||||
|
|
||||||
|
|
||||||
|
# Left for third-party module compatibility
|
||||||
|
def ovirt_facts_full_argument_spec(**kwargs):
|
||||||
|
"""
|
||||||
|
This is deprecated. Please use ovirt_info_full_argument_spec instead!
|
||||||
|
|
||||||
|
:param kwargs: kwargs to be extended
|
||||||
|
:return: extended dictionary with common parameters
|
||||||
|
"""
|
||||||
|
return ovirt_info_full_argument_spec(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def ovirt_full_argument_spec(**kwargs):
|
||||||
|
"""
|
||||||
|
Extend parameters of module with parameters which are common to all oVirt modules.
|
||||||
|
|
||||||
|
:param kwargs: kwargs to be extended
|
||||||
|
:return: extended dictionary with common parameters
|
||||||
|
"""
|
||||||
|
spec = dict(
|
||||||
|
auth=__get_auth_dict(),
|
||||||
|
timeout=dict(default=180, type='int'),
|
||||||
|
wait=dict(default=True, type='bool'),
|
||||||
|
poll_interval=dict(default=3, type='int'),
|
||||||
|
fetch_nested=dict(default=False, type='bool'),
|
||||||
|
nested_attributes=dict(type='list', default=list()),
|
||||||
|
)
|
||||||
|
spec.update(kwargs)
|
||||||
|
return spec
|
||||||
|
|
||||||
|
|
||||||
|
def check_params(module):
|
||||||
|
"""
|
||||||
|
Most modules must have either `name` or `id` specified.
|
||||||
|
"""
|
||||||
|
if module.params.get('name') is None and module.params.get('id') is None:
|
||||||
|
module.fail_json(msg='"name" or "id" is required')
|
||||||
|
|
||||||
|
|
||||||
|
def engine_supported(connection, version):
|
||||||
|
return LooseVersion(engine_version(connection)) >= LooseVersion(version)
|
||||||
|
|
||||||
|
|
||||||
|
def check_support(version, connection, module, params):
|
||||||
|
"""
|
||||||
|
Check if parameters used by user are supported by oVirt Python SDK
|
||||||
|
and oVirt engine.
|
||||||
|
"""
|
||||||
|
api_version = LooseVersion(engine_version(connection))
|
||||||
|
version = LooseVersion(version)
|
||||||
|
for param in params:
|
||||||
|
if module.params.get(param) is not None:
|
||||||
|
return LooseVersion(sdk_version.VERSION) >= version and api_version >= version
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class BaseModule(object):
|
||||||
|
"""
|
||||||
|
This is base class for oVirt modules. oVirt modules should inherit this
|
||||||
|
class and override method to customize specific needs of the module.
|
||||||
|
The only abstract method of this class is `build_entity`, which must
|
||||||
|
to be implemented in child class.
|
||||||
|
"""
|
||||||
|
__metaclass__ = ABCMeta
|
||||||
|
|
||||||
|
def __init__(self, connection, module, service, changed=False):
|
||||||
|
self._connection = connection
|
||||||
|
self._module = module
|
||||||
|
self._service = service
|
||||||
|
self._changed = changed
|
||||||
|
self._diff = {'after': dict(), 'before': dict()}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def changed(self):
|
||||||
|
return self._changed
|
||||||
|
|
||||||
|
@changed.setter
|
||||||
|
def changed(self, changed):
|
||||||
|
if not self._changed:
|
||||||
|
self._changed = changed
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def build_entity(self):
|
||||||
|
"""
|
||||||
|
This method should return oVirt Python SDK type, which we want to
|
||||||
|
create or update, initialized by values passed by Ansible module.
|
||||||
|
|
||||||
|
For example if we want to create VM, we will return following:
|
||||||
|
types.Vm(name=self._module.params['vm_name'])
|
||||||
|
|
||||||
|
:return: Specific instance of sdk.Struct.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def param(self, name, default=None):
|
||||||
|
"""
|
||||||
|
Return a module parameter specified by it's name.
|
||||||
|
"""
|
||||||
|
return self._module.params.get(name, default)
|
||||||
|
|
||||||
|
def update_check(self, entity):
|
||||||
|
"""
|
||||||
|
This method handle checks whether the entity values are same as values
|
||||||
|
passed to ansible module. By default we don't compare any values.
|
||||||
|
|
||||||
|
:param entity: Entity we want to compare with Ansible module values.
|
||||||
|
:return: True if values are same, so we don't need to update the entity.
|
||||||
|
"""
|
||||||
|
return True
|
||||||
|
|
||||||
|
def pre_create(self, entity):
|
||||||
|
"""
|
||||||
|
This method is called right before entity is created.
|
||||||
|
|
||||||
|
:param entity: Entity to be created or updated.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def post_create(self, entity):
|
||||||
|
"""
|
||||||
|
This method is called right after entity is created.
|
||||||
|
|
||||||
|
:param entity: Entity which was created.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def post_update(self, entity):
|
||||||
|
"""
|
||||||
|
This method is called right after entity is updated.
|
||||||
|
|
||||||
|
:param entity: Entity which was updated.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def diff_update(self, after, update):
|
||||||
|
for k, v in update.items():
|
||||||
|
if isinstance(v, Mapping):
|
||||||
|
after[k] = self.diff_update(after.get(k, dict()), v)
|
||||||
|
else:
|
||||||
|
after[k] = update[k]
|
||||||
|
return after
|
||||||
|
|
||||||
|
def create(
|
||||||
|
self,
|
||||||
|
entity=None,
|
||||||
|
result_state=None,
|
||||||
|
fail_condition=lambda e: False,
|
||||||
|
search_params=None,
|
||||||
|
update_params=None,
|
||||||
|
_wait=None,
|
||||||
|
force_create=False,
|
||||||
|
**kwargs
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Method which is called when state of the entity is 'present'. If user
|
||||||
|
don't provide `entity` parameter the entity is searched using
|
||||||
|
`search_params` parameter. If entity is found it's updated, whether
|
||||||
|
the entity should be updated is checked by `update_check` method.
|
||||||
|
The corresponding updated entity is build by `build_entity` method.
|
||||||
|
|
||||||
|
Function executed after entity is created can optionally be specified
|
||||||
|
in `post_create` parameter. Function executed after entity is updated
|
||||||
|
can optionally be specified in `post_update` parameter.
|
||||||
|
|
||||||
|
:param entity: Entity we want to update, if exists.
|
||||||
|
:param result_state: State which should entity has in order to finish task.
|
||||||
|
:param fail_condition: Function which checks incorrect state of entity, if it returns `True` Exception is raised.
|
||||||
|
:param search_params: Dictionary of parameters to be used for search.
|
||||||
|
:param update_params: The params which should be passed to update method.
|
||||||
|
:param kwargs: Additional parameters passed when creating entity.
|
||||||
|
:return: Dictionary with values returned by Ansible module.
|
||||||
|
"""
|
||||||
|
if entity is None and not force_create:
|
||||||
|
entity = self.search_entity(search_params)
|
||||||
|
|
||||||
|
self.pre_create(entity)
|
||||||
|
|
||||||
|
if entity:
|
||||||
|
# Entity exists, so update it:
|
||||||
|
entity_service = self._service.service(entity.id)
|
||||||
|
if not self.update_check(entity):
|
||||||
|
new_entity = self.build_entity()
|
||||||
|
if not self._module.check_mode:
|
||||||
|
update_params = update_params or {}
|
||||||
|
updated_entity = entity_service.update(
|
||||||
|
new_entity,
|
||||||
|
**update_params
|
||||||
|
)
|
||||||
|
self.post_update(entity)
|
||||||
|
|
||||||
|
# Update diffs only if user specified --diff parameter,
|
||||||
|
# so we don't useless overload API:
|
||||||
|
if self._module._diff:
|
||||||
|
before = get_dict_of_struct(
|
||||||
|
entity,
|
||||||
|
self._connection,
|
||||||
|
fetch_nested=True,
|
||||||
|
attributes=['name'],
|
||||||
|
)
|
||||||
|
after = before.copy()
|
||||||
|
self.diff_update(after, get_dict_of_struct(new_entity))
|
||||||
|
self._diff['before'] = before
|
||||||
|
self._diff['after'] = after
|
||||||
|
|
||||||
|
self.changed = True
|
||||||
|
else:
|
||||||
|
# Entity don't exists, so create it:
|
||||||
|
if not self._module.check_mode:
|
||||||
|
entity = self._service.add(
|
||||||
|
self.build_entity(),
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
self.post_create(entity)
|
||||||
|
self.changed = True
|
||||||
|
|
||||||
|
if not self._module.check_mode:
|
||||||
|
# Wait for the entity to be created and to be in the defined state:
|
||||||
|
entity_service = self._service.service(entity.id)
|
||||||
|
|
||||||
|
def state_condition(entity):
|
||||||
|
return entity
|
||||||
|
|
||||||
|
if result_state:
|
||||||
|
|
||||||
|
def state_condition(entity):
|
||||||
|
return entity and entity.status == result_state
|
||||||
|
|
||||||
|
wait(
|
||||||
|
service=entity_service,
|
||||||
|
condition=state_condition,
|
||||||
|
fail_condition=fail_condition,
|
||||||
|
wait=_wait if _wait is not None else self._module.params['wait'],
|
||||||
|
timeout=self._module.params['timeout'],
|
||||||
|
poll_interval=self._module.params['poll_interval'],
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
'changed': self.changed,
|
||||||
|
'id': getattr(entity, 'id', None),
|
||||||
|
type(entity).__name__.lower(): get_dict_of_struct(
|
||||||
|
struct=entity,
|
||||||
|
connection=self._connection,
|
||||||
|
fetch_nested=self._module.params.get('fetch_nested'),
|
||||||
|
attributes=self._module.params.get('nested_attributes'),
|
||||||
|
),
|
||||||
|
'diff': self._diff,
|
||||||
|
}
|
||||||
|
|
||||||
|
def pre_remove(self, entity):
|
||||||
|
"""
|
||||||
|
This method is called right before entity is removed.
|
||||||
|
|
||||||
|
:param entity: Entity which we want to remove.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def entity_name(self, entity):
|
||||||
|
return "{e_type} '{e_name}'".format(
|
||||||
|
e_type=type(entity).__name__.lower(),
|
||||||
|
e_name=getattr(entity, 'name', None),
|
||||||
|
)
|
||||||
|
|
||||||
|
def remove(self, entity=None, search_params=None, **kwargs):
|
||||||
|
"""
|
||||||
|
Method which is called when state of the entity is 'absent'. If user
|
||||||
|
don't provide `entity` parameter the entity is searched using
|
||||||
|
`search_params` parameter. If entity is found it's removed.
|
||||||
|
|
||||||
|
Function executed before remove is executed can optionally be specified
|
||||||
|
in `pre_remove` parameter.
|
||||||
|
|
||||||
|
:param entity: Entity we want to remove.
|
||||||
|
:param search_params: Dictionary of parameters to be used for search.
|
||||||
|
:param kwargs: Additional parameters passed when removing entity.
|
||||||
|
:return: Dictionary with values returned by Ansible module.
|
||||||
|
"""
|
||||||
|
if entity is None:
|
||||||
|
entity = self.search_entity(search_params)
|
||||||
|
|
||||||
|
if entity is None:
|
||||||
|
return {
|
||||||
|
'changed': self.changed,
|
||||||
|
'msg': "Entity wasn't found."
|
||||||
|
}
|
||||||
|
|
||||||
|
self.pre_remove(entity)
|
||||||
|
|
||||||
|
entity_service = self._service.service(entity.id)
|
||||||
|
if not self._module.check_mode:
|
||||||
|
entity_service.remove(**kwargs)
|
||||||
|
wait(
|
||||||
|
service=entity_service,
|
||||||
|
condition=lambda entity: not entity,
|
||||||
|
wait=self._module.params['wait'],
|
||||||
|
timeout=self._module.params['timeout'],
|
||||||
|
poll_interval=self._module.params['poll_interval'],
|
||||||
|
)
|
||||||
|
self.changed = True
|
||||||
|
|
||||||
|
return {
|
||||||
|
'changed': self.changed,
|
||||||
|
'id': entity.id,
|
||||||
|
type(entity).__name__.lower(): get_dict_of_struct(
|
||||||
|
struct=entity,
|
||||||
|
connection=self._connection,
|
||||||
|
fetch_nested=self._module.params.get('fetch_nested'),
|
||||||
|
attributes=self._module.params.get('nested_attributes'),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
def action(
|
||||||
|
self,
|
||||||
|
action,
|
||||||
|
entity=None,
|
||||||
|
action_condition=lambda e: e,
|
||||||
|
wait_condition=lambda e: e,
|
||||||
|
fail_condition=lambda e: False,
|
||||||
|
pre_action=lambda e: e,
|
||||||
|
post_action=lambda e: None,
|
||||||
|
search_params=None,
|
||||||
|
**kwargs
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
This method is executed when we want to change the state of some oVirt
|
||||||
|
entity. The action to be executed on oVirt service is specified by
|
||||||
|
`action` parameter. Whether the action should be executed can be
|
||||||
|
specified by passing `action_condition` parameter. State which the
|
||||||
|
entity should be in after execution of the action can be specified
|
||||||
|
by `wait_condition` parameter.
|
||||||
|
|
||||||
|
Function executed before an action on entity can optionally be specified
|
||||||
|
in `pre_action` parameter. Function executed after an action on entity can
|
||||||
|
optionally be specified in `post_action` parameter.
|
||||||
|
|
||||||
|
:param action: Action which should be executed by service on entity.
|
||||||
|
:param entity: Entity we want to run action on.
|
||||||
|
:param action_condition: Function which is executed when checking if action should be executed.
|
||||||
|
:param fail_condition: Function which checks incorrect state of entity, if it returns `True` Exception is raised.
|
||||||
|
:param wait_condition: Function which is executed when waiting on result state.
|
||||||
|
:param pre_action: Function which is executed before running the action.
|
||||||
|
:param post_action: Function which is executed after running the action.
|
||||||
|
:param search_params: Dictionary of parameters to be used for search.
|
||||||
|
:param kwargs: Additional parameters passed to action.
|
||||||
|
:return: Dictionary with values returned by Ansible module.
|
||||||
|
"""
|
||||||
|
if entity is None:
|
||||||
|
entity = self.search_entity(search_params)
|
||||||
|
|
||||||
|
entity = pre_action(entity)
|
||||||
|
|
||||||
|
if entity is None:
|
||||||
|
self._module.fail_json(
|
||||||
|
msg="Entity not found, can't run action '{0}'.".format(
|
||||||
|
action
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
entity_service = self._service.service(entity.id)
|
||||||
|
entity = entity_service.get()
|
||||||
|
if action_condition(entity):
|
||||||
|
if not self._module.check_mode:
|
||||||
|
getattr(entity_service, action)(**kwargs)
|
||||||
|
self.changed = True
|
||||||
|
|
||||||
|
post_action(entity)
|
||||||
|
|
||||||
|
wait(
|
||||||
|
service=self._service.service(entity.id),
|
||||||
|
condition=wait_condition,
|
||||||
|
fail_condition=fail_condition,
|
||||||
|
wait=self._module.params['wait'],
|
||||||
|
timeout=self._module.params['timeout'],
|
||||||
|
poll_interval=self._module.params['poll_interval'],
|
||||||
|
)
|
||||||
|
return {
|
||||||
|
'changed': self.changed,
|
||||||
|
'id': entity.id,
|
||||||
|
type(entity).__name__.lower(): get_dict_of_struct(
|
||||||
|
struct=entity,
|
||||||
|
connection=self._connection,
|
||||||
|
fetch_nested=self._module.params.get('fetch_nested'),
|
||||||
|
attributes=self._module.params.get('nested_attributes'),
|
||||||
|
),
|
||||||
|
'diff': self._diff,
|
||||||
|
}
|
||||||
|
|
||||||
|
def wait_for_import(self, condition=lambda e: True):
|
||||||
|
if self._module.params['wait']:
|
||||||
|
start = time.time()
|
||||||
|
timeout = self._module.params['timeout']
|
||||||
|
poll_interval = self._module.params['poll_interval']
|
||||||
|
while time.time() < start + timeout:
|
||||||
|
entity = self.search_entity()
|
||||||
|
if entity and condition(entity):
|
||||||
|
return entity
|
||||||
|
time.sleep(poll_interval)
|
||||||
|
|
||||||
|
def search_entity(self, search_params=None, list_params=None):
|
||||||
|
"""
|
||||||
|
Always first try to search by `ID`, if ID isn't specified,
|
||||||
|
check if user constructed special search in `search_params`,
|
||||||
|
if not search by `name`.
|
||||||
|
"""
|
||||||
|
entity = None
|
||||||
|
|
||||||
|
if 'id' in self._module.params and self._module.params['id'] is not None:
|
||||||
|
entity = get_entity(self._service.service(self._module.params['id']), get_params=list_params)
|
||||||
|
elif search_params is not None:
|
||||||
|
entity = search_by_attributes(self._service, list_params=list_params, **search_params)
|
||||||
|
elif self._module.params.get('name') is not None:
|
||||||
|
entity = search_by_attributes(self._service, list_params=list_params, name=self._module.params['name'])
|
||||||
|
|
||||||
|
return entity
|
||||||
|
|
||||||
|
def _get_major(self, full_version):
|
||||||
|
if full_version is None or full_version == "":
|
||||||
|
return None
|
||||||
|
if isinstance(full_version, otypes.Version):
|
||||||
|
return int(full_version.major)
|
||||||
|
return int(full_version.split('.')[0])
|
||||||
|
|
||||||
|
def _get_minor(self, full_version):
|
||||||
|
if full_version is None or full_version == "":
|
||||||
|
return None
|
||||||
|
if isinstance(full_version, otypes.Version):
|
||||||
|
return int(full_version.minor)
|
||||||
|
return int(full_version.split('.')[1])
|
||||||
|
|
||||||
|
|
||||||
|
def _sdk4_error_maybe():
|
||||||
|
"""
|
||||||
|
Allow for ovirtsdk4 not being installed.
|
||||||
|
"""
|
||||||
|
if HAS_SDK:
|
||||||
|
return sdk.Error
|
||||||
|
return type(None)
|
||||||
|
|
||||||
|
|
||||||
|
class OvirtRetry(CloudRetry):
|
||||||
|
base_class = _sdk4_error_maybe()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def status_code_from_exception(error):
|
||||||
|
return error.code
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def found(response_code, catch_extra_error_codes=None):
|
||||||
|
# This is a list of error codes to retry.
|
||||||
|
retry_on = [
|
||||||
|
# HTTP status: Conflict
|
||||||
|
409,
|
||||||
|
]
|
||||||
|
if catch_extra_error_codes:
|
||||||
|
retry_on.extend(catch_extra_error_codes)
|
||||||
|
|
||||||
|
return response_code in retry_on
|
||||||
@@ -30,16 +30,12 @@ from __future__ import absolute_import, division, print_function
|
|||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import traceback
|
|
||||||
|
|
||||||
from ansible.module_utils.urls import open_url
|
from ansible.module_utils.urls import open_url
|
||||||
from ansible.module_utils.six.moves.urllib.parse import urlencode
|
from ansible.module_utils.six.moves.urllib.parse import urlencode
|
||||||
from ansible.module_utils.six.moves.urllib.error import HTTPError
|
from ansible.module_utils.six.moves.urllib.error import HTTPError
|
||||||
from ansible.module_utils._text import to_native
|
from ansible.module_utils._text import to_native
|
||||||
|
|
||||||
URL_REALMS = "{url}/admin/realms"
|
|
||||||
URL_REALM = "{url}/admin/realms/{realm}"
|
|
||||||
|
|
||||||
URL_TOKEN = "{url}/realms/{realm}/protocol/openid-connect/token"
|
URL_TOKEN = "{url}/realms/{realm}/protocol/openid-connect/token"
|
||||||
URL_CLIENT = "{url}/admin/realms/{realm}/clients/{id}"
|
URL_CLIENT = "{url}/admin/realms/{realm}/clients/{id}"
|
||||||
URL_CLIENTS = "{url}/admin/realms/{realm}/clients"
|
URL_CLIENTS = "{url}/admin/realms/{realm}/clients"
|
||||||
@@ -61,12 +57,11 @@ def keycloak_argument_spec():
|
|||||||
return dict(
|
return dict(
|
||||||
auth_keycloak_url=dict(type='str', aliases=['url'], required=True, no_log=False),
|
auth_keycloak_url=dict(type='str', aliases=['url'], required=True, no_log=False),
|
||||||
auth_client_id=dict(type='str', default='admin-cli'),
|
auth_client_id=dict(type='str', default='admin-cli'),
|
||||||
auth_realm=dict(type='str'),
|
auth_realm=dict(type='str', required=True),
|
||||||
auth_client_secret=dict(type='str', default=None, no_log=True),
|
auth_client_secret=dict(type='str', default=None, no_log=True),
|
||||||
auth_username=dict(type='str', aliases=['username']),
|
auth_username=dict(type='str', aliases=['username'], required=True),
|
||||||
auth_password=dict(type='str', aliases=['password'], no_log=True),
|
auth_password=dict(type='str', aliases=['password'], required=True, no_log=True),
|
||||||
validate_certs=dict(type='bool', default=True),
|
validate_certs=dict(type='bool', default=True)
|
||||||
token=dict(type='str', no_log=True),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -78,58 +73,41 @@ class KeycloakError(Exception):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def get_token(module_params):
|
def get_token(base_url, validate_certs, auth_realm, client_id,
|
||||||
""" Obtains connection header with token for the authentication,
|
auth_username, auth_password, client_secret):
|
||||||
token already given or obtained from credentials
|
|
||||||
:param module_params: parameters of the module
|
|
||||||
:return: connection header
|
|
||||||
"""
|
|
||||||
token = module_params.get('token')
|
|
||||||
base_url = module_params.get('auth_keycloak_url')
|
|
||||||
|
|
||||||
if not base_url.lower().startswith(('http', 'https')):
|
if not base_url.lower().startswith(('http', 'https')):
|
||||||
raise KeycloakError("auth_url '%s' should either start with 'http' or 'https'." % base_url)
|
raise KeycloakError("auth_url '%s' should either start with 'http' or 'https'." % base_url)
|
||||||
|
auth_url = URL_TOKEN.format(url=base_url, realm=auth_realm)
|
||||||
if token is None:
|
temp_payload = {
|
||||||
base_url = module_params.get('auth_keycloak_url')
|
'grant_type': 'password',
|
||||||
validate_certs = module_params.get('validate_certs')
|
'client_id': client_id,
|
||||||
auth_realm = module_params.get('auth_realm')
|
'client_secret': client_secret,
|
||||||
client_id = module_params.get('auth_client_id')
|
'username': auth_username,
|
||||||
auth_username = module_params.get('auth_username')
|
'password': auth_password,
|
||||||
auth_password = module_params.get('auth_password')
|
|
||||||
client_secret = module_params.get('auth_client_secret')
|
|
||||||
auth_url = URL_TOKEN.format(url=base_url, realm=auth_realm)
|
|
||||||
temp_payload = {
|
|
||||||
'grant_type': 'password',
|
|
||||||
'client_id': client_id,
|
|
||||||
'client_secret': client_secret,
|
|
||||||
'username': auth_username,
|
|
||||||
'password': auth_password,
|
|
||||||
}
|
|
||||||
# Remove empty items, for instance missing client_secret
|
|
||||||
payload = dict(
|
|
||||||
(k, v) for k, v in temp_payload.items() if v is not None)
|
|
||||||
try:
|
|
||||||
r = json.loads(to_native(open_url(auth_url, method='POST',
|
|
||||||
validate_certs=validate_certs,
|
|
||||||
data=urlencode(payload)).read()))
|
|
||||||
except ValueError as e:
|
|
||||||
raise KeycloakError(
|
|
||||||
'API returned invalid JSON when trying to obtain access token from %s: %s'
|
|
||||||
% (auth_url, str(e)))
|
|
||||||
except Exception as e:
|
|
||||||
raise KeycloakError('Could not obtain access token from %s: %s'
|
|
||||||
% (auth_url, str(e)))
|
|
||||||
|
|
||||||
try:
|
|
||||||
token = r['access_token']
|
|
||||||
except KeyError:
|
|
||||||
raise KeycloakError(
|
|
||||||
'Could not obtain access token from %s' % auth_url)
|
|
||||||
return {
|
|
||||||
'Authorization': 'Bearer ' + token,
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}
|
}
|
||||||
|
# Remove empty items, for instance missing client_secret
|
||||||
|
payload = dict(
|
||||||
|
(k, v) for k, v in temp_payload.items() if v is not None)
|
||||||
|
try:
|
||||||
|
r = json.loads(to_native(open_url(auth_url, method='POST',
|
||||||
|
validate_certs=validate_certs,
|
||||||
|
data=urlencode(payload)).read()))
|
||||||
|
except ValueError as e:
|
||||||
|
raise KeycloakError(
|
||||||
|
'API returned invalid JSON when trying to obtain access token from %s: %s'
|
||||||
|
% (auth_url, str(e)))
|
||||||
|
except Exception as e:
|
||||||
|
raise KeycloakError('Could not obtain access token from %s: %s'
|
||||||
|
% (auth_url, str(e)))
|
||||||
|
|
||||||
|
try:
|
||||||
|
return {
|
||||||
|
'Authorization': 'Bearer ' + r['access_token'],
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
except KeyError:
|
||||||
|
raise KeycloakError(
|
||||||
|
'Could not obtain access token from %s' % auth_url)
|
||||||
|
|
||||||
|
|
||||||
class KeycloakAPI(object):
|
class KeycloakAPI(object):
|
||||||
@@ -142,75 +120,6 @@ class KeycloakAPI(object):
|
|||||||
self.validate_certs = self.module.params.get('validate_certs')
|
self.validate_certs = self.module.params.get('validate_certs')
|
||||||
self.restheaders = connection_header
|
self.restheaders = connection_header
|
||||||
|
|
||||||
def get_realm_by_id(self, realm='master'):
|
|
||||||
""" Obtain realm representation by id
|
|
||||||
|
|
||||||
:param realm: realm id
|
|
||||||
:return: dict of real, representation or None if none matching exist
|
|
||||||
"""
|
|
||||||
realm_url = URL_REALM.format(url=self.baseurl, realm=realm)
|
|
||||||
|
|
||||||
try:
|
|
||||||
return json.loads(to_native(open_url(realm_url, method='GET', headers=self.restheaders,
|
|
||||||
validate_certs=self.validate_certs).read()))
|
|
||||||
|
|
||||||
except HTTPError as e:
|
|
||||||
if e.code == 404:
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
self.module.fail_json(msg='Could not obtain realm %s: %s' % (realm, str(e)),
|
|
||||||
exception=traceback.format_exc())
|
|
||||||
except ValueError as e:
|
|
||||||
self.module.fail_json(msg='API returned incorrect JSON when trying to obtain realm %s: %s' % (realm, str(e)),
|
|
||||||
exception=traceback.format_exc())
|
|
||||||
except Exception as e:
|
|
||||||
self.module.fail_json(msg='Could not obtain realm %s: %s' % (realm, str(e)),
|
|
||||||
exception=traceback.format_exc())
|
|
||||||
|
|
||||||
def update_realm(self, realmrep, realm="master"):
|
|
||||||
""" Update an existing realm
|
|
||||||
:param realmrep: corresponding (partial/full) realm representation with updates
|
|
||||||
:param realm: realm to be updated in Keycloak
|
|
||||||
:return: HTTPResponse object on success
|
|
||||||
"""
|
|
||||||
realm_url = URL_REALM.format(url=self.baseurl, realm=realm)
|
|
||||||
|
|
||||||
try:
|
|
||||||
return open_url(realm_url, method='PUT', headers=self.restheaders,
|
|
||||||
data=json.dumps(realmrep), validate_certs=self.validate_certs)
|
|
||||||
except Exception as e:
|
|
||||||
self.module.fail_json(msg='Could not update realm %s: %s' % (realm, str(e)),
|
|
||||||
exception=traceback.format_exc())
|
|
||||||
|
|
||||||
def create_realm(self, realmrep):
|
|
||||||
""" Create a realm in keycloak
|
|
||||||
:param realmrep: Realm representation of realm to be created.
|
|
||||||
:return: HTTPResponse object on success
|
|
||||||
"""
|
|
||||||
realm_url = URL_REALMS.format(url=self.baseurl)
|
|
||||||
|
|
||||||
try:
|
|
||||||
return open_url(realm_url, method='POST', headers=self.restheaders,
|
|
||||||
data=json.dumps(realmrep), validate_certs=self.validate_certs)
|
|
||||||
except Exception as e:
|
|
||||||
self.module.fail_json(msg='Could not create realm %s: %s' % (realmrep['id'], str(e)),
|
|
||||||
exception=traceback.format_exc())
|
|
||||||
|
|
||||||
def delete_realm(self, realm="master"):
|
|
||||||
""" Delete a realm from Keycloak
|
|
||||||
|
|
||||||
:param realm: realm to be deleted
|
|
||||||
:return: HTTPResponse object on success
|
|
||||||
"""
|
|
||||||
realm_url = URL_REALM.format(url=self.baseurl, realm=realm)
|
|
||||||
|
|
||||||
try:
|
|
||||||
return open_url(realm_url, method='DELETE', headers=self.restheaders,
|
|
||||||
validate_certs=self.validate_certs)
|
|
||||||
except Exception as e:
|
|
||||||
self.module.fail_json(msg='Could not delete realm %s: %s' % (realm, str(e)),
|
|
||||||
exception=traceback.format_exc())
|
|
||||||
|
|
||||||
def get_clients(self, realm='master', filter=None):
|
def get_clients(self, realm='master', filter=None):
|
||||||
""" Obtains client representations for clients in a realm
|
""" Obtains client representations for clients in a realm
|
||||||
|
|
||||||
|
|||||||
@@ -119,9 +119,9 @@ class IPAClient(object):
|
|||||||
data = dict(method=method)
|
data = dict(method=method)
|
||||||
|
|
||||||
# TODO: We should probably handle this a little better.
|
# TODO: We should probably handle this a little better.
|
||||||
if method in ('ping', 'config_show', 'otpconfig_show'):
|
if method in ('ping', 'config_show'):
|
||||||
data['params'] = [[], {}]
|
data['params'] = [[], {}]
|
||||||
elif method in ('config_mod', 'otpconfig_mod'):
|
elif method == 'config_mod':
|
||||||
data['params'] = [[], item]
|
data['params'] = [[], item]
|
||||||
else:
|
else:
|
||||||
data['params'] = [[name], item]
|
data['params'] = [[name], item]
|
||||||
|
|||||||
@@ -87,12 +87,11 @@ def not_in_host_file(self, host):
|
|||||||
user_host_file = "~/.ssh/known_hosts"
|
user_host_file = "~/.ssh/known_hosts"
|
||||||
user_host_file = os.path.expanduser(user_host_file)
|
user_host_file = os.path.expanduser(user_host_file)
|
||||||
|
|
||||||
host_file_list = [
|
host_file_list = []
|
||||||
user_host_file,
|
host_file_list.append(user_host_file)
|
||||||
"/etc/ssh/ssh_known_hosts",
|
host_file_list.append("/etc/ssh/ssh_known_hosts")
|
||||||
"/etc/ssh/ssh_known_hosts2",
|
host_file_list.append("/etc/ssh/ssh_known_hosts2")
|
||||||
"/etc/openssh/ssh_known_hosts",
|
host_file_list.append("/etc/openssh/ssh_known_hosts")
|
||||||
]
|
|
||||||
|
|
||||||
hfiles_not_found = 0
|
hfiles_not_found = 0
|
||||||
for hf in host_file_list:
|
for hf in host_file_list:
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ from functools import partial, wraps
|
|||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
from ansible.module_utils.common.dict_transformations import dict_merge
|
|
||||||
|
|
||||||
|
|
||||||
class ModuleHelperException(Exception):
|
class ModuleHelperException(Exception):
|
||||||
@@ -25,12 +24,12 @@ class ModuleHelperException(Exception):
|
|||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.msg = self._get_remove('msg', kwargs) or "Module failed with exception: {0}".format(self)
|
self.msg = self._get_remove('msg', kwargs) or "Module failed with exception: {0}".format(self)
|
||||||
self.update_output = self._get_remove('update_output', kwargs) or {}
|
self.update_output = self._get_remove('update_output', kwargs) or {}
|
||||||
super(ModuleHelperException, self).__init__(*args)
|
super(ModuleHelperException, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class ArgFormat(object):
|
class ArgFormat(object):
|
||||||
"""
|
"""
|
||||||
Argument formatter for use as a command line parameter. Used in CmdMixin.
|
Argument formatter
|
||||||
"""
|
"""
|
||||||
BOOLEAN = 0
|
BOOLEAN = 0
|
||||||
PRINTF = 1
|
PRINTF = 1
|
||||||
@@ -51,8 +50,7 @@ class ArgFormat(object):
|
|||||||
|
|
||||||
def __init__(self, name, fmt=None, style=FORMAT, stars=0):
|
def __init__(self, name, fmt=None, style=FORMAT, stars=0):
|
||||||
"""
|
"""
|
||||||
Creates a CLI-formatter for one specific argument. The argument may be a module parameter or just a named parameter for
|
Creates a new formatter
|
||||||
the CLI command execution.
|
|
||||||
:param name: Name of the argument to be formatted
|
:param name: Name of the argument to be formatted
|
||||||
:param fmt: Either a str to be formatted (using or not printf-style) or a callable that does that
|
:param fmt: Either a str to be formatted (using or not printf-style) or a callable that does that
|
||||||
:param style: Whether arg_format (as str) should use printf-style formatting.
|
:param style: Whether arg_format (as str) should use printf-style formatting.
|
||||||
@@ -101,27 +99,18 @@ class ArgFormat(object):
|
|||||||
return [str(p) for p in func(value)]
|
return [str(p) for p in func(value)]
|
||||||
|
|
||||||
|
|
||||||
def cause_changes(on_success=None, on_failure=None):
|
def cause_changes(func, on_success=True, on_failure=False):
|
||||||
|
@wraps(func)
|
||||||
def deco(func):
|
def wrapper(self, *args, **kwargs):
|
||||||
if on_success is None and on_failure is None:
|
try:
|
||||||
return func
|
func(*args, **kwargs)
|
||||||
|
if on_success:
|
||||||
@wraps(func)
|
self.changed = True
|
||||||
def wrapper(*args, **kwargs):
|
except Exception as e:
|
||||||
try:
|
if on_failure:
|
||||||
self = args[0]
|
self.changed = True
|
||||||
func(*args, **kwargs)
|
raise
|
||||||
if on_success is not None:
|
return wrapper
|
||||||
self.changed = on_success
|
|
||||||
except Exception:
|
|
||||||
if on_failure is not None:
|
|
||||||
self.changed = on_failure
|
|
||||||
raise
|
|
||||||
|
|
||||||
return wrapper
|
|
||||||
|
|
||||||
return deco
|
|
||||||
|
|
||||||
|
|
||||||
def module_fails_on_exception(func):
|
def module_fails_on_exception(func):
|
||||||
@@ -134,12 +123,11 @@ def module_fails_on_exception(func):
|
|||||||
except ModuleHelperException as e:
|
except ModuleHelperException as e:
|
||||||
if e.update_output:
|
if e.update_output:
|
||||||
self.update_output(e.update_output)
|
self.update_output(e.update_output)
|
||||||
self.module.fail_json(msg=e.msg, exception=traceback.format_exc(),
|
self.module.fail_json(changed=False, msg=e.msg, exception=traceback.format_exc(), output=self.output, vars=self.vars)
|
||||||
output=self.output, vars=self.vars.output(), **self.output)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
msg = "Module failed with exception: {0}".format(str(e).strip())
|
self.vars.msg = "Module failed with exception: {0}".format(str(e).strip())
|
||||||
self.module.fail_json(msg=msg, exception=traceback.format_exc(),
|
self.vars.exception = traceback.format_exc()
|
||||||
output=self.output, vars=self.vars.output(), **self.output)
|
self.module.fail_json(changed=False, msg=self.vars.msg, exception=self.vars.exception, output=self.output, vars=self.vars)
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
@@ -153,7 +141,7 @@ class DependencyCtxMgr(object):
|
|||||||
self.exc_tb = None
|
self.exc_tb = None
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
return self
|
pass
|
||||||
|
|
||||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||||
self.has_it = exc_type is None
|
self.has_it = exc_type is None
|
||||||
@@ -167,157 +155,32 @@ class DependencyCtxMgr(object):
|
|||||||
return self.msg or str(self.exc_val)
|
return self.msg or str(self.exc_val)
|
||||||
|
|
||||||
|
|
||||||
class VarMeta(object):
|
|
||||||
NOTHING = object()
|
|
||||||
|
|
||||||
def __init__(self, diff=False, output=True, change=None, fact=False):
|
|
||||||
self.init = False
|
|
||||||
self.initial_value = None
|
|
||||||
self.value = None
|
|
||||||
|
|
||||||
self.diff = diff
|
|
||||||
self.change = diff if change is None else change
|
|
||||||
self.output = output
|
|
||||||
self.fact = fact
|
|
||||||
|
|
||||||
def set(self, diff=None, output=None, change=None, fact=None, initial_value=NOTHING):
|
|
||||||
if diff is not None:
|
|
||||||
self.diff = diff
|
|
||||||
if output is not None:
|
|
||||||
self.output = output
|
|
||||||
if change is not None:
|
|
||||||
self.change = change
|
|
||||||
if fact is not None:
|
|
||||||
self.fact = fact
|
|
||||||
if initial_value is not self.NOTHING:
|
|
||||||
self.initial_value = initial_value
|
|
||||||
|
|
||||||
def set_value(self, value):
|
|
||||||
if not self.init:
|
|
||||||
self.initial_value = value
|
|
||||||
self.init = True
|
|
||||||
self.value = value
|
|
||||||
return self
|
|
||||||
|
|
||||||
@property
|
|
||||||
def has_changed(self):
|
|
||||||
return self.change and (self.initial_value != self.value)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def diff_result(self):
|
|
||||||
return None if not (self.diff and self.has_changed) else {
|
|
||||||
'before': self.initial_value,
|
|
||||||
'after': self.value,
|
|
||||||
}
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "<VarMeta: value={0}, initial={1}, diff={2}, output={3}, change={4}>".format(
|
|
||||||
self.value, self.initial_value, self.diff, self.output, self.change
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class ModuleHelper(object):
|
class ModuleHelper(object):
|
||||||
_output_conflict_list = ('msg', 'exception', 'output', 'vars', 'changed')
|
|
||||||
_dependencies = []
|
_dependencies = []
|
||||||
module = None
|
module = {}
|
||||||
facts_name = None
|
facts_name = None
|
||||||
output_params = ()
|
|
||||||
diff_params = ()
|
|
||||||
change_params = ()
|
|
||||||
facts_params = ()
|
|
||||||
|
|
||||||
class VarDict(object):
|
|
||||||
def __init__(self):
|
|
||||||
self._data = dict()
|
|
||||||
self._meta = dict()
|
|
||||||
|
|
||||||
def __getitem__(self, item):
|
|
||||||
return self._data[item]
|
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
|
||||||
self.set(key, value)
|
|
||||||
|
|
||||||
|
class AttrDict(dict):
|
||||||
def __getattr__(self, item):
|
def __getattr__(self, item):
|
||||||
try:
|
return self[item]
|
||||||
return self._data[item]
|
|
||||||
except KeyError:
|
|
||||||
return getattr(self._data, item)
|
|
||||||
|
|
||||||
def __setattr__(self, key, value):
|
|
||||||
if key in ('_data', '_meta'):
|
|
||||||
super(ModuleHelper.VarDict, self).__setattr__(key, value)
|
|
||||||
else:
|
|
||||||
self.set(key, value)
|
|
||||||
|
|
||||||
def meta(self, name):
|
|
||||||
return self._meta[name]
|
|
||||||
|
|
||||||
def set_meta(self, name, **kwargs):
|
|
||||||
self.meta(name).set(**kwargs)
|
|
||||||
|
|
||||||
def set(self, name, value, **kwargs):
|
|
||||||
if name in ('_data', '_meta'):
|
|
||||||
raise ValueError("Names _data and _meta are reserved for use by ModuleHelper")
|
|
||||||
self._data[name] = value
|
|
||||||
if name in self._meta:
|
|
||||||
meta = self.meta(name)
|
|
||||||
else:
|
|
||||||
meta = VarMeta(**kwargs)
|
|
||||||
meta.set_value(value)
|
|
||||||
self._meta[name] = meta
|
|
||||||
|
|
||||||
def output(self):
|
|
||||||
return dict((k, v) for k, v in self._data.items() if self.meta(k).output)
|
|
||||||
|
|
||||||
def diff(self):
|
|
||||||
diff_results = [(k, self.meta(k).diff_result) for k in self._data]
|
|
||||||
diff_results = [dr for dr in diff_results if dr[1] is not None]
|
|
||||||
if diff_results:
|
|
||||||
before = dict((dr[0], dr[1]['before']) for dr in diff_results)
|
|
||||||
after = dict((dr[0], dr[1]['after']) for dr in diff_results)
|
|
||||||
return {'before': before, 'after': after}
|
|
||||||
return None
|
|
||||||
|
|
||||||
def facts(self):
|
|
||||||
facts_result = dict((k, v) for k, v in self._data.items() if self._meta[k].fact)
|
|
||||||
return facts_result if facts_result else None
|
|
||||||
|
|
||||||
def change_vars(self):
|
|
||||||
return [v for v in self._data if self.meta(v).change]
|
|
||||||
|
|
||||||
def has_changed(self, v):
|
|
||||||
return self._meta[v].has_changed
|
|
||||||
|
|
||||||
def __init__(self, module=None):
|
def __init__(self, module=None):
|
||||||
self.vars = ModuleHelper.VarDict()
|
self.vars = ModuleHelper.AttrDict()
|
||||||
|
self.output_dict = dict()
|
||||||
|
self.facts_dict = dict()
|
||||||
self._changed = False
|
self._changed = False
|
||||||
|
|
||||||
if module:
|
if module:
|
||||||
self.module = module
|
self.module = module
|
||||||
|
|
||||||
if not isinstance(self.module, AnsibleModule):
|
if isinstance(self.module, dict):
|
||||||
self.module = AnsibleModule(**self.module)
|
self.module = AnsibleModule(**self.module)
|
||||||
|
|
||||||
for name, value in self.module.params.items():
|
|
||||||
self.vars.set(
|
|
||||||
name, value,
|
|
||||||
diff=name in self.diff_params,
|
|
||||||
output=name in self.output_params,
|
|
||||||
change=None if not self.change_params else name in self.change_params,
|
|
||||||
fact=name in self.facts_params,
|
|
||||||
)
|
|
||||||
|
|
||||||
def update_vars(self, meta=None, **kwargs):
|
|
||||||
if meta is None:
|
|
||||||
meta = {}
|
|
||||||
for k, v in kwargs.items():
|
|
||||||
self.vars.set(k, v, **meta)
|
|
||||||
|
|
||||||
def update_output(self, **kwargs):
|
def update_output(self, **kwargs):
|
||||||
self.update_vars(meta={"output": True}, **kwargs)
|
self.output_dict.update(kwargs)
|
||||||
|
|
||||||
def update_facts(self, **kwargs):
|
def update_facts(self, **kwargs):
|
||||||
self.update_vars(meta={"fact": True}, **kwargs)
|
self.facts_dict.update(kwargs)
|
||||||
|
|
||||||
def __init_module__(self):
|
def __init_module__(self):
|
||||||
pass
|
pass
|
||||||
@@ -328,9 +191,6 @@ class ModuleHelper(object):
|
|||||||
def __quit_module__(self):
|
def __quit_module__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _vars_changed(self):
|
|
||||||
return any(self.vars.has_changed(v) for v in self.vars.change_vars())
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def changed(self):
|
def changed(self):
|
||||||
return self._changed
|
return self._changed
|
||||||
@@ -339,25 +199,12 @@ class ModuleHelper(object):
|
|||||||
def changed(self, value):
|
def changed(self, value):
|
||||||
self._changed = value
|
self._changed = value
|
||||||
|
|
||||||
def has_changed(self):
|
|
||||||
return self.changed or self._vars_changed()
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def output(self):
|
def output(self):
|
||||||
result = dict(self.vars.output())
|
result = dict(self.vars)
|
||||||
|
result.update(self.output_dict)
|
||||||
if self.facts_name:
|
if self.facts_name:
|
||||||
facts = self.vars.facts()
|
result['ansible_facts'] = {self.facts_name: self.facts_dict}
|
||||||
if facts is not None:
|
|
||||||
result['ansible_facts'] = {self.facts_name: facts}
|
|
||||||
if self.module._diff:
|
|
||||||
diff = result.get('diff', {})
|
|
||||||
vars_diff = self.vars.diff() or {}
|
|
||||||
result['diff'] = dict_merge(dict(diff), vars_diff)
|
|
||||||
|
|
||||||
for varname in result:
|
|
||||||
if varname in self._output_conflict_list:
|
|
||||||
result["_" + varname] = result[varname]
|
|
||||||
del result[varname]
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@module_fails_on_exception
|
@module_fails_on_exception
|
||||||
@@ -366,7 +213,7 @@ class ModuleHelper(object):
|
|||||||
self.__init_module__()
|
self.__init_module__()
|
||||||
self.__run__()
|
self.__run__()
|
||||||
self.__quit_module__()
|
self.__quit_module__()
|
||||||
self.module.exit_json(changed=self.has_changed(), **self.output)
|
self.module.exit_json(changed=self.changed, **self.output_dict)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def dependency(cls, name, msg):
|
def dependency(cls, name, msg):
|
||||||
@@ -377,9 +224,9 @@ class ModuleHelper(object):
|
|||||||
for d in self._dependencies:
|
for d in self._dependencies:
|
||||||
if not d.has_it:
|
if not d.has_it:
|
||||||
self.module.fail_json(changed=False,
|
self.module.fail_json(changed=False,
|
||||||
exception="\n".join(traceback.format_exception(d.exc_type, d.exc_val, d.exc_tb)),
|
exception=d.exc_val.__traceback__.format_exc(),
|
||||||
msg=d.text,
|
msg=d.text,
|
||||||
**self.output)
|
**self.output_dict)
|
||||||
|
|
||||||
|
|
||||||
class StateMixin(object):
|
class StateMixin(object):
|
||||||
@@ -485,7 +332,7 @@ class CmdMixin(object):
|
|||||||
return rc, out, err
|
return rc, out, err
|
||||||
|
|
||||||
def run_command(self, extra_params=None, params=None, *args, **kwargs):
|
def run_command(self, extra_params=None, params=None, *args, **kwargs):
|
||||||
self.vars.cmd_args = self._calculate_args(extra_params, params)
|
self.vars['cmd_args'] = self._calculate_args(extra_params, params)
|
||||||
options = dict(self.run_command_fixed_options)
|
options = dict(self.run_command_fixed_options)
|
||||||
env_update = dict(options.get('environ_update', {}))
|
env_update = dict(options.get('environ_update', {}))
|
||||||
options['check_rc'] = options.get('check_rc', self.check_rc)
|
options['check_rc'] = options.get('check_rc', self.check_rc)
|
||||||
@@ -494,7 +341,7 @@ class CmdMixin(object):
|
|||||||
self.update_output(force_lang=self.force_lang)
|
self.update_output(force_lang=self.force_lang)
|
||||||
options['environ_update'] = env_update
|
options['environ_update'] = env_update
|
||||||
options.update(kwargs)
|
options.update(kwargs)
|
||||||
rc, out, err = self.module.run_command(self.vars.cmd_args, *args, **options)
|
rc, out, err = self.module.run_command(self.vars['cmd_args'], *args, **options)
|
||||||
self.update_output(rc=rc, stdout=out, stderr=err)
|
self.update_output(rc=rc, stdout=out, stderr=err)
|
||||||
return self.process_command_output(rc, out, err)
|
return self.process_command_output(rc, out, err)
|
||||||
|
|
||||||
|
|||||||
@@ -57,34 +57,6 @@ def _get_pritunl_organizations(api_token, api_secret, base_url, validate_certs=T
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _delete_pritunl_organization(
|
|
||||||
api_token, api_secret, base_url, organization_id, validate_certs=True
|
|
||||||
):
|
|
||||||
return pritunl_auth_request(
|
|
||||||
base_url=base_url,
|
|
||||||
api_token=api_token,
|
|
||||||
api_secret=api_secret,
|
|
||||||
method="DELETE",
|
|
||||||
path="/organization/%s" % (organization_id),
|
|
||||||
validate_certs=validate_certs,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def _post_pritunl_organization(
|
|
||||||
api_token, api_secret, base_url, organization_data, validate_certs=True
|
|
||||||
):
|
|
||||||
return pritunl_auth_request(
|
|
||||||
api_token=api_token,
|
|
||||||
api_secret=api_secret,
|
|
||||||
base_url=base_url,
|
|
||||||
method="POST",
|
|
||||||
path="/organization/%s",
|
|
||||||
headers={"Content-Type": "application/json"},
|
|
||||||
data=json.dumps(organization_data),
|
|
||||||
validate_certs=validate_certs,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def _get_pritunl_users(
|
def _get_pritunl_users(
|
||||||
api_token, api_secret, base_url, organization_id, validate_certs=True
|
api_token, api_secret, base_url, organization_id, validate_certs=True
|
||||||
):
|
):
|
||||||
@@ -207,29 +179,6 @@ def list_pritunl_users(
|
|||||||
return users
|
return users
|
||||||
|
|
||||||
|
|
||||||
def post_pritunl_organization(
|
|
||||||
api_token,
|
|
||||||
api_secret,
|
|
||||||
base_url,
|
|
||||||
organization_name,
|
|
||||||
validate_certs=True,
|
|
||||||
):
|
|
||||||
response = _post_pritunl_organization(
|
|
||||||
api_token=api_token,
|
|
||||||
api_secret=api_secret,
|
|
||||||
base_url=base_url,
|
|
||||||
organization_data={"name": organization_name},
|
|
||||||
validate_certs=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
if response.getcode() != 200:
|
|
||||||
raise PritunlException(
|
|
||||||
"Could not add organization %s to Pritunl" % (organization_name)
|
|
||||||
)
|
|
||||||
# The user PUT request returns the updated user object
|
|
||||||
return json.loads(response.read())
|
|
||||||
|
|
||||||
|
|
||||||
def post_pritunl_user(
|
def post_pritunl_user(
|
||||||
api_token,
|
api_token,
|
||||||
api_secret,
|
api_secret,
|
||||||
@@ -278,25 +227,6 @@ def post_pritunl_user(
|
|||||||
return json.loads(response.read())
|
return json.loads(response.read())
|
||||||
|
|
||||||
|
|
||||||
def delete_pritunl_organization(
|
|
||||||
api_token, api_secret, base_url, organization_id, validate_certs=True
|
|
||||||
):
|
|
||||||
response = _delete_pritunl_organization(
|
|
||||||
api_token=api_token,
|
|
||||||
api_secret=api_secret,
|
|
||||||
base_url=base_url,
|
|
||||||
organization_id=organization_id,
|
|
||||||
validate_certs=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
if response.getcode() != 200:
|
|
||||||
raise PritunlException(
|
|
||||||
"Could not remove organization %s from Pritunl" % (organization_id)
|
|
||||||
)
|
|
||||||
|
|
||||||
return json.loads(response.read())
|
|
||||||
|
|
||||||
|
|
||||||
def delete_pritunl_user(
|
def delete_pritunl_user(
|
||||||
api_token, api_secret, base_url, organization_id, user_id, validate_certs=True
|
api_token, api_secret, base_url, organization_id, user_id, validate_certs=True
|
||||||
):
|
):
|
||||||
|
|||||||
@@ -19,10 +19,11 @@ PATCH_HEADERS = {'content-type': 'application/json', 'accept': 'application/json
|
|||||||
'OData-Version': '4.0'}
|
'OData-Version': '4.0'}
|
||||||
DELETE_HEADERS = {'accept': 'application/json', 'OData-Version': '4.0'}
|
DELETE_HEADERS = {'accept': 'application/json', 'OData-Version': '4.0'}
|
||||||
|
|
||||||
FAIL_MSG = 'Issuing a data modification command without specifying the '\
|
DEPRECATE_MSG = 'Issuing a data modification command without specifying the '\
|
||||||
'ID of the target %(resource)s resource when there is more '\
|
'ID of the target %(resource)s resource when there is more '\
|
||||||
'than one %(resource)s is no longer allowed. Use the `resource_id` '\
|
'than one %(resource)s will use the first one in the '\
|
||||||
'option to specify the target %(resource)s ID.'
|
'collection. Use the `resource_id` option to specify the '\
|
||||||
|
'target %(resource)s ID'
|
||||||
|
|
||||||
|
|
||||||
class RedfishUtils(object):
|
class RedfishUtils(object):
|
||||||
@@ -266,7 +267,8 @@ class RedfishUtils(object):
|
|||||||
'ret': False,
|
'ret': False,
|
||||||
'msg': "System resource %s not found" % self.resource_id}
|
'msg': "System resource %s not found" % self.resource_id}
|
||||||
elif len(self.systems_uris) > 1:
|
elif len(self.systems_uris) > 1:
|
||||||
self.module.fail_json(msg=FAIL_MSG % {'resource': 'System'})
|
self.module.deprecate(DEPRECATE_MSG % {'resource': 'System'},
|
||||||
|
version='3.0.0', collection_name='community.general') # was Ansible 2.14
|
||||||
return {'ret': True}
|
return {'ret': True}
|
||||||
|
|
||||||
def _find_updateservice_resource(self):
|
def _find_updateservice_resource(self):
|
||||||
@@ -316,7 +318,8 @@ class RedfishUtils(object):
|
|||||||
'ret': False,
|
'ret': False,
|
||||||
'msg': "Chassis resource %s not found" % self.resource_id}
|
'msg': "Chassis resource %s not found" % self.resource_id}
|
||||||
elif len(self.chassis_uris) > 1:
|
elif len(self.chassis_uris) > 1:
|
||||||
self.module.fail_json(msg=FAIL_MSG % {'resource': 'Chassis'})
|
self.module.deprecate(DEPRECATE_MSG % {'resource': 'Chassis'},
|
||||||
|
version='3.0.0', collection_name='community.general') # was Ansible 2.14
|
||||||
return {'ret': True}
|
return {'ret': True}
|
||||||
|
|
||||||
def _find_managers_resource(self):
|
def _find_managers_resource(self):
|
||||||
@@ -345,7 +348,8 @@ class RedfishUtils(object):
|
|||||||
'ret': False,
|
'ret': False,
|
||||||
'msg': "Manager resource %s not found" % self.resource_id}
|
'msg': "Manager resource %s not found" % self.resource_id}
|
||||||
elif len(self.manager_uris) > 1:
|
elif len(self.manager_uris) > 1:
|
||||||
self.module.fail_json(msg=FAIL_MSG % {'resource': 'Manager'})
|
self.module.deprecate(DEPRECATE_MSG % {'resource': 'Manager'},
|
||||||
|
version='3.0.0', collection_name='community.general') # was Ansible 2.14
|
||||||
return {'ret': True}
|
return {'ret': True}
|
||||||
|
|
||||||
def _get_all_action_info_values(self, action):
|
def _get_all_action_info_values(self, action):
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
#
|
||||||
|
# Dell EMC OpenManage Ansible Modules
|
||||||
|
# Version 1.0
|
||||||
|
# Copyright (C) 2018 Dell Inc.
|
||||||
|
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
# All rights reserved. Dell, EMC, and other trademarks are trademarks of Dell Inc. or its subsidiaries.
|
||||||
|
# Other trademarks may be trademarks of their respective owners.
|
||||||
|
#
|
||||||
|
|
||||||
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
try:
|
||||||
|
from omsdk.sdkinfra import sdkinfra
|
||||||
|
from omsdk.sdkcreds import UserCredentials
|
||||||
|
from omsdk.sdkfile import FileOnShare, file_share_manager
|
||||||
|
from omsdk.sdkprotopref import ProtoPreference, ProtocolEnum
|
||||||
|
from omsdk.http.sdkwsmanbase import WsManOptions
|
||||||
|
HAS_OMSDK = True
|
||||||
|
except ImportError:
|
||||||
|
HAS_OMSDK = False
|
||||||
|
|
||||||
|
|
||||||
|
class iDRACConnection:
|
||||||
|
|
||||||
|
def __init__(self, module_params):
|
||||||
|
if not HAS_OMSDK:
|
||||||
|
raise ImportError("Dell EMC OMSDK library is required for this module")
|
||||||
|
self.idrac_ip = module_params['idrac_ip']
|
||||||
|
self.idrac_user = module_params['idrac_user']
|
||||||
|
self.idrac_pwd = module_params['idrac_password']
|
||||||
|
self.idrac_port = module_params['idrac_port']
|
||||||
|
if not all((self.idrac_ip, self.idrac_user, self.idrac_pwd)):
|
||||||
|
raise ValueError("hostname, username and password required")
|
||||||
|
self.handle = None
|
||||||
|
self.creds = UserCredentials(self.idrac_user, self.idrac_pwd)
|
||||||
|
self.pOp = WsManOptions(port=self.idrac_port)
|
||||||
|
self.sdk = sdkinfra()
|
||||||
|
if self.sdk is None:
|
||||||
|
msg = "Could not initialize iDRAC drivers."
|
||||||
|
raise RuntimeError(msg)
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
self.sdk.importPath()
|
||||||
|
self.handle = self.sdk.get_driver(self.sdk.driver_enum.iDRAC, self.idrac_ip, self.creds, pOptions=self.pOp)
|
||||||
|
if self.handle is None:
|
||||||
|
msg = "Could not find device driver for iDRAC with IP Address: {0}".format(self.idrac_ip)
|
||||||
|
raise RuntimeError(msg)
|
||||||
|
return self.handle
|
||||||
|
|
||||||
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||||
|
self.handle.disconnect()
|
||||||
|
return False
|
||||||
163
plugins/module_utils/remote_management/dellemc/ome.py
Normal file
163
plugins/module_utils/remote_management/dellemc/ome.py
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Dell EMC OpenManage Ansible Modules
|
||||||
|
# Version 1.3
|
||||||
|
# Copyright (C) 2019 Dell Inc. or its subsidiaries. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||||
|
|
||||||
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
import json
|
||||||
|
from ansible.module_utils.urls import open_url, ConnectionError, SSLValidationError
|
||||||
|
from ansible.module_utils.six.moves.urllib.error import URLError, HTTPError
|
||||||
|
from ansible.module_utils.six.moves.urllib.parse import urlencode
|
||||||
|
|
||||||
|
SESSION_RESOURCE_COLLECTION = {
|
||||||
|
"SESSION": "SessionService/Sessions",
|
||||||
|
"SESSION_ID": "SessionService/Sessions('{Id}')",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class OpenURLResponse(object):
|
||||||
|
"""Handles HTTPResponse"""
|
||||||
|
|
||||||
|
def __init__(self, resp):
|
||||||
|
self.body = None
|
||||||
|
self.resp = resp
|
||||||
|
if self.resp:
|
||||||
|
self.body = self.resp.read()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def json_data(self):
|
||||||
|
try:
|
||||||
|
return json.loads(self.body)
|
||||||
|
except ValueError:
|
||||||
|
raise ValueError("Unable to parse json")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def status_code(self):
|
||||||
|
return self.resp.getcode()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def success(self):
|
||||||
|
return self.status_code in (200, 201, 202, 204)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def token_header(self):
|
||||||
|
return self.resp.headers.get('X-Auth-Token')
|
||||||
|
|
||||||
|
|
||||||
|
class RestOME(object):
|
||||||
|
"""Handles OME API requests"""
|
||||||
|
|
||||||
|
def __init__(self, module_params=None, req_session=False):
|
||||||
|
self.module_params = module_params
|
||||||
|
self.hostname = self.module_params["hostname"]
|
||||||
|
self.username = self.module_params["username"]
|
||||||
|
self.password = self.module_params["password"]
|
||||||
|
self.port = self.module_params["port"]
|
||||||
|
self.req_session = req_session
|
||||||
|
self.session_id = None
|
||||||
|
self.protocol = 'https'
|
||||||
|
self._headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}
|
||||||
|
|
||||||
|
def _get_base_url(self):
|
||||||
|
"""builds base url"""
|
||||||
|
return '{0}://{1}:{2}/api'.format(self.protocol, self.hostname, self.port)
|
||||||
|
|
||||||
|
def _build_url(self, path, query_param=None):
|
||||||
|
"""builds complete url"""
|
||||||
|
url = path
|
||||||
|
base_uri = self._get_base_url()
|
||||||
|
if path:
|
||||||
|
url = '{0}/{1}'.format(base_uri, path)
|
||||||
|
if query_param:
|
||||||
|
url += "?{0}".format(urlencode(query_param))
|
||||||
|
return url
|
||||||
|
|
||||||
|
def _url_common_args_spec(self, method, api_timeout, headers=None):
|
||||||
|
"""Creates an argument common spec"""
|
||||||
|
req_header = self._headers
|
||||||
|
if headers:
|
||||||
|
req_header.update(headers)
|
||||||
|
url_kwargs = {
|
||||||
|
"method": method,
|
||||||
|
"validate_certs": False,
|
||||||
|
"use_proxy": True,
|
||||||
|
"headers": req_header,
|
||||||
|
"timeout": api_timeout,
|
||||||
|
"follow_redirects": 'all',
|
||||||
|
}
|
||||||
|
return url_kwargs
|
||||||
|
|
||||||
|
def _args_without_session(self, method, api_timeout=30, headers=None):
|
||||||
|
"""Creates an argument spec in case of basic authentication"""
|
||||||
|
req_header = self._headers
|
||||||
|
if headers:
|
||||||
|
req_header.update(headers)
|
||||||
|
url_kwargs = self._url_common_args_spec(method, api_timeout, headers=headers)
|
||||||
|
url_kwargs["url_username"] = self.username
|
||||||
|
url_kwargs["url_password"] = self.password
|
||||||
|
url_kwargs["force_basic_auth"] = True
|
||||||
|
return url_kwargs
|
||||||
|
|
||||||
|
def _args_with_session(self, method, api_timeout=30, headers=None):
|
||||||
|
"""Creates an argument spec, in case of authentication with session"""
|
||||||
|
url_kwargs = self._url_common_args_spec(method, api_timeout, headers=headers)
|
||||||
|
url_kwargs["force_basic_auth"] = False
|
||||||
|
return url_kwargs
|
||||||
|
|
||||||
|
def invoke_request(self, method, path, data=None, query_param=None, headers=None,
|
||||||
|
api_timeout=30, dump=True):
|
||||||
|
"""
|
||||||
|
Sends a request via open_url
|
||||||
|
Returns :class:`OpenURLResponse` object.
|
||||||
|
:arg method: HTTP verb to use for the request
|
||||||
|
:arg path: path to request without query parameter
|
||||||
|
:arg data: (optional) Payload to send with the request
|
||||||
|
:arg query_param: (optional) Dictionary of query parameter to send with request
|
||||||
|
:arg headers: (optional) Dictionary of HTTP Headers to send with the
|
||||||
|
request
|
||||||
|
:arg api_timeout: (optional) How long to wait for the server to send
|
||||||
|
data before giving up
|
||||||
|
:arg dump: (Optional) boolean value for dumping payload data.
|
||||||
|
:returns: OpenURLResponse
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if 'X-Auth-Token' in self._headers:
|
||||||
|
url_kwargs = self._args_with_session(method, api_timeout, headers=headers)
|
||||||
|
else:
|
||||||
|
url_kwargs = self._args_without_session(method, api_timeout, headers=headers)
|
||||||
|
if data and dump:
|
||||||
|
data = json.dumps(data)
|
||||||
|
url = self._build_url(path, query_param=query_param)
|
||||||
|
resp = open_url(url, data=data, **url_kwargs)
|
||||||
|
resp_data = OpenURLResponse(resp)
|
||||||
|
except (HTTPError, URLError, SSLValidationError, ConnectionError) as err:
|
||||||
|
raise err
|
||||||
|
return resp_data
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
"""Creates sessions by passing it to header"""
|
||||||
|
if self.req_session:
|
||||||
|
payload = {'UserName': self.username,
|
||||||
|
'Password': self.password,
|
||||||
|
'SessionType': 'API', }
|
||||||
|
path = SESSION_RESOURCE_COLLECTION["SESSION"]
|
||||||
|
resp = self.invoke_request('POST', path, data=payload)
|
||||||
|
if resp and resp.success:
|
||||||
|
self.session_id = resp.json_data.get("Id")
|
||||||
|
self._headers["X-Auth-Token"] = resp.token_header
|
||||||
|
else:
|
||||||
|
msg = "Could not create the session"
|
||||||
|
raise ConnectionError(msg)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, exc_type, exc_value, traceback):
|
||||||
|
"""Deletes a session id, which is in use for request"""
|
||||||
|
if self.session_id:
|
||||||
|
path = SESSION_RESOURCE_COLLECTION["SESSION_ID"].format(Id=self.session_id)
|
||||||
|
self.invoke_request('DELETE', path)
|
||||||
|
return False
|
||||||
@@ -20,6 +20,7 @@ except ImportError:
|
|||||||
XENAPI_IMP_ERR = traceback.format_exc()
|
XENAPI_IMP_ERR = traceback.format_exc()
|
||||||
|
|
||||||
from ansible.module_utils.basic import env_fallback, missing_required_lib
|
from ansible.module_utils.basic import env_fallback, missing_required_lib
|
||||||
|
from ansible.module_utils.common.network import is_mac
|
||||||
from ansible.module_utils.ansible_release import __version__ as ANSIBLE_VERSION
|
from ansible.module_utils.ansible_release import __version__ as ANSIBLE_VERSION
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
1
plugins/modules/ali_instance_facts.py
Symbolic link
1
plugins/modules/ali_instance_facts.py
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
cloud/alicloud/ali_instance_facts.py
|
||||||
1
plugins/modules/cloud/alicloud/ali_instance_facts.py
Symbolic link
1
plugins/modules/cloud/alicloud/ali_instance_facts.py
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
ali_instance_info.py
|
||||||
@@ -383,6 +383,9 @@ def main():
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
module = AnsibleModule(argument_spec=argument_spec)
|
module = AnsibleModule(argument_spec=argument_spec)
|
||||||
|
if module._name in ('ali_instance_facts', 'community.general.ali_instance_facts'):
|
||||||
|
module.deprecate("The 'ali_instance_facts' module has been renamed to 'ali_instance_info'",
|
||||||
|
version='3.0.0', collection_name='community.general') # was Ansible 2.13
|
||||||
|
|
||||||
if HAS_FOOTMARK is False:
|
if HAS_FOOTMARK is False:
|
||||||
module.fail_json(msg=missing_required_lib('footmark'), exception=FOOTMARK_IMP_ERR)
|
module.fail_json(msg=missing_required_lib('footmark'), exception=FOOTMARK_IMP_ERR)
|
||||||
|
|||||||
@@ -102,8 +102,7 @@ def do_install(module, mode, rootfs, container, image, values_list, backend):
|
|||||||
system_list = ["--system"] if mode == 'system' else []
|
system_list = ["--system"] if mode == 'system' else []
|
||||||
user_list = ["--user"] if mode == 'user' else []
|
user_list = ["--user"] if mode == 'user' else []
|
||||||
rootfs_list = ["--rootfs=%s" % rootfs] if rootfs else []
|
rootfs_list = ["--rootfs=%s" % rootfs] if rootfs else []
|
||||||
atomic_bin = module.get_bin_path('atomic')
|
args = ['atomic', 'install', "--storage=%s" % backend, '--name=%s' % container] + system_list + user_list + rootfs_list + values_list + [image]
|
||||||
args = [atomic_bin, 'install', "--storage=%s" % backend, '--name=%s' % container] + system_list + user_list + rootfs_list + values_list + [image]
|
|
||||||
rc, out, err = module.run_command(args, check_rc=False)
|
rc, out, err = module.run_command(args, check_rc=False)
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
module.fail_json(rc=rc, msg=err)
|
module.fail_json(rc=rc, msg=err)
|
||||||
@@ -113,8 +112,7 @@ def do_install(module, mode, rootfs, container, image, values_list, backend):
|
|||||||
|
|
||||||
|
|
||||||
def do_update(module, container, image, values_list):
|
def do_update(module, container, image, values_list):
|
||||||
atomic_bin = module.get_bin_path('atomic')
|
args = ['atomic', 'containers', 'update', "--rebase=%s" % image] + values_list + [container]
|
||||||
args = [atomic_bin, 'containers', 'update', "--rebase=%s" % image] + values_list + [container]
|
|
||||||
rc, out, err = module.run_command(args, check_rc=False)
|
rc, out, err = module.run_command(args, check_rc=False)
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
module.fail_json(rc=rc, msg=err)
|
module.fail_json(rc=rc, msg=err)
|
||||||
@@ -124,8 +122,7 @@ def do_update(module, container, image, values_list):
|
|||||||
|
|
||||||
|
|
||||||
def do_uninstall(module, name, backend):
|
def do_uninstall(module, name, backend):
|
||||||
atomic_bin = module.get_bin_path('atomic')
|
args = ['atomic', 'uninstall', "--storage=%s" % backend, name]
|
||||||
args = [atomic_bin, 'uninstall', "--storage=%s" % backend, name]
|
|
||||||
rc, out, err = module.run_command(args, check_rc=False)
|
rc, out, err = module.run_command(args, check_rc=False)
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
module.fail_json(rc=rc, msg=err)
|
module.fail_json(rc=rc, msg=err)
|
||||||
@@ -133,8 +130,7 @@ def do_uninstall(module, name, backend):
|
|||||||
|
|
||||||
|
|
||||||
def do_rollback(module, name):
|
def do_rollback(module, name):
|
||||||
atomic_bin = module.get_bin_path('atomic')
|
args = ['atomic', 'containers', 'rollback', name]
|
||||||
args = [atomic_bin, 'containers', 'rollback', name]
|
|
||||||
rc, out, err = module.run_command(args, check_rc=False)
|
rc, out, err = module.run_command(args, check_rc=False)
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
module.fail_json(rc=rc, msg=err)
|
module.fail_json(rc=rc, msg=err)
|
||||||
@@ -152,12 +148,14 @@ def core(module):
|
|||||||
backend = module.params['backend']
|
backend = module.params['backend']
|
||||||
state = module.params['state']
|
state = module.params['state']
|
||||||
|
|
||||||
atomic_bin = module.get_bin_path('atomic')
|
|
||||||
module.run_command_environ_update = dict(LANG='C', LC_ALL='C', LC_MESSAGES='C')
|
module.run_command_environ_update = dict(LANG='C', LC_ALL='C', LC_MESSAGES='C')
|
||||||
|
out = {}
|
||||||
|
err = {}
|
||||||
|
rc = 0
|
||||||
|
|
||||||
values_list = ["--set=%s" % x for x in values] if values else []
|
values_list = ["--set=%s" % x for x in values] if values else []
|
||||||
|
|
||||||
args = [atomic_bin, 'containers', 'list', '--no-trunc', '-n', '--all', '-f', 'backend=%s' % backend, '-f', 'container=%s' % name]
|
args = ['atomic', 'containers', 'list', '--no-trunc', '-n', '--all', '-f', 'backend=%s' % backend, '-f', 'container=%s' % name]
|
||||||
rc, out, err = module.run_command(args, check_rc=False)
|
rc, out, err = module.run_command(args, check_rc=False)
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
module.fail_json(rc=rc, msg=err)
|
module.fail_json(rc=rc, msg=err)
|
||||||
@@ -196,7 +194,9 @@ def main():
|
|||||||
module.fail_json(msg="values is supported only with user or system mode")
|
module.fail_json(msg="values is supported only with user or system mode")
|
||||||
|
|
||||||
# Verify that the platform supports atomic command
|
# Verify that the platform supports atomic command
|
||||||
dummy = module.get_bin_path('atomic', required=True)
|
rc, out, err = module.run_command('atomic -v', check_rc=False)
|
||||||
|
if rc != 0:
|
||||||
|
module.fail_json(msg="Error in running atomic command", err=err)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
core(module)
|
core(module)
|
||||||
|
|||||||
@@ -57,14 +57,18 @@ from ansible.module_utils._text import to_native
|
|||||||
|
|
||||||
def core(module):
|
def core(module):
|
||||||
revision = module.params['revision']
|
revision = module.params['revision']
|
||||||
atomic_bin = module.get_bin_path('atomic', required=True)
|
args = []
|
||||||
|
|
||||||
module.run_command_environ_update = dict(LANG='C', LC_ALL='C', LC_MESSAGES='C')
|
module.run_command_environ_update = dict(LANG='C', LC_ALL='C', LC_MESSAGES='C')
|
||||||
|
|
||||||
if revision == 'latest':
|
if revision == 'latest':
|
||||||
args = [atomic_bin, 'host', 'upgrade']
|
args = ['atomic', 'host', 'upgrade']
|
||||||
else:
|
else:
|
||||||
args = [atomic_bin, 'host', 'deploy', revision]
|
args = ['atomic', 'host', 'deploy', revision]
|
||||||
|
|
||||||
|
out = {}
|
||||||
|
err = {}
|
||||||
|
rc = 0
|
||||||
|
|
||||||
rc, out, err = module.run_command(args, check_rc=False)
|
rc, out, err = module.run_command(args, check_rc=False)
|
||||||
|
|
||||||
|
|||||||
@@ -73,8 +73,7 @@ from ansible.module_utils._text import to_native
|
|||||||
|
|
||||||
|
|
||||||
def do_upgrade(module, image):
|
def do_upgrade(module, image):
|
||||||
atomic_bin = module.get_bin_path('atomic')
|
args = ['atomic', 'update', '--force', image]
|
||||||
args = [atomic_bin, 'update', '--force', image]
|
|
||||||
rc, out, err = module.run_command(args, check_rc=False)
|
rc, out, err = module.run_command(args, check_rc=False)
|
||||||
if rc != 0: # something went wrong emit the msg
|
if rc != 0: # something went wrong emit the msg
|
||||||
module.fail_json(rc=rc, msg=err)
|
module.fail_json(rc=rc, msg=err)
|
||||||
@@ -92,21 +91,20 @@ def core(module):
|
|||||||
is_upgraded = False
|
is_upgraded = False
|
||||||
|
|
||||||
module.run_command_environ_update = dict(LANG='C', LC_ALL='C', LC_MESSAGES='C')
|
module.run_command_environ_update = dict(LANG='C', LC_ALL='C', LC_MESSAGES='C')
|
||||||
atomic_bin = module.get_bin_path('atomic')
|
|
||||||
out = {}
|
out = {}
|
||||||
err = {}
|
err = {}
|
||||||
rc = 0
|
rc = 0
|
||||||
|
|
||||||
if backend:
|
if backend:
|
||||||
if state == 'present' or state == 'latest':
|
if state == 'present' or state == 'latest':
|
||||||
args = [atomic_bin, 'pull', "--storage=%s" % backend, image]
|
args = ['atomic', 'pull', "--storage=%s" % backend, image]
|
||||||
rc, out, err = module.run_command(args, check_rc=False)
|
rc, out, err = module.run_command(args, check_rc=False)
|
||||||
if rc < 0:
|
if rc < 0:
|
||||||
module.fail_json(rc=rc, msg=err)
|
module.fail_json(rc=rc, msg=err)
|
||||||
else:
|
else:
|
||||||
out_run = ""
|
out_run = ""
|
||||||
if started:
|
if started:
|
||||||
args = [atomic_bin, 'run', "--storage=%s" % backend, image]
|
args = ['atomic', 'run', "--storage=%s" % backend, image]
|
||||||
rc, out_run, err = module.run_command(args, check_rc=False)
|
rc, out_run, err = module.run_command(args, check_rc=False)
|
||||||
if rc < 0:
|
if rc < 0:
|
||||||
module.fail_json(rc=rc, msg=err)
|
module.fail_json(rc=rc, msg=err)
|
||||||
@@ -114,7 +112,7 @@ def core(module):
|
|||||||
changed = "Extracting" in out or "Copying blob" in out
|
changed = "Extracting" in out or "Copying blob" in out
|
||||||
module.exit_json(msg=(out + out_run), changed=changed)
|
module.exit_json(msg=(out + out_run), changed=changed)
|
||||||
elif state == 'absent':
|
elif state == 'absent':
|
||||||
args = [atomic_bin, 'images', 'delete', "--storage=%s" % backend, image]
|
args = ['atomic', 'images', 'delete', "--storage=%s" % backend, image]
|
||||||
rc, out, err = module.run_command(args, check_rc=False)
|
rc, out, err = module.run_command(args, check_rc=False)
|
||||||
if rc < 0:
|
if rc < 0:
|
||||||
module.fail_json(rc=rc, msg=err)
|
module.fail_json(rc=rc, msg=err)
|
||||||
@@ -128,11 +126,11 @@ def core(module):
|
|||||||
is_upgraded = do_upgrade(module, image)
|
is_upgraded = do_upgrade(module, image)
|
||||||
|
|
||||||
if started:
|
if started:
|
||||||
args = [atomic_bin, 'run', image]
|
args = ['atomic', 'run', image]
|
||||||
else:
|
else:
|
||||||
args = [atomic_bin, 'install', image]
|
args = ['atomic', 'install', image]
|
||||||
elif state == 'absent':
|
elif state == 'absent':
|
||||||
args = [atomic_bin, 'uninstall', image]
|
args = ['atomic', 'uninstall', image]
|
||||||
|
|
||||||
rc, out, err = module.run_command(args, check_rc=False)
|
rc, out, err = module.run_command(args, check_rc=False)
|
||||||
|
|
||||||
@@ -157,7 +155,9 @@ def main():
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Verify that the platform supports atomic command
|
# Verify that the platform supports atomic command
|
||||||
dummy = module.get_bin_path('atomic', required=True)
|
rc, out, err = module.run_command('atomic -v', check_rc=False)
|
||||||
|
if rc != 0:
|
||||||
|
module.fail_json(msg="Error in running atomic command", err=err)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
core(module)
|
core(module)
|
||||||
|
|||||||
@@ -30,6 +30,10 @@ options:
|
|||||||
required: False
|
required: False
|
||||||
default: present
|
default: present
|
||||||
choices: ['present','absent']
|
choices: ['present','absent']
|
||||||
|
wait:
|
||||||
|
description:
|
||||||
|
- This option does nothing and will be removed in community.general 3.0.0.
|
||||||
|
type: bool
|
||||||
requirements:
|
requirements:
|
||||||
- python = 2.7
|
- python = 2.7
|
||||||
- requests >= 2.5.0
|
- requests >= 2.5.0
|
||||||
@@ -181,6 +185,7 @@ class ClcAntiAffinityPolicy:
|
|||||||
argument_spec = dict(
|
argument_spec = dict(
|
||||||
name=dict(required=True),
|
name=dict(required=True),
|
||||||
location=dict(required=True),
|
location=dict(required=True),
|
||||||
|
wait=dict(type='bool', removed_in_version='3.0.0', removed_from_collection='community.general'), # was Ansible 2.14
|
||||||
state=dict(default='present', choices=['present', 'absent']),
|
state=dict(default='present', choices=['present', 'absent']),
|
||||||
)
|
)
|
||||||
return argument_spec
|
return argument_spec
|
||||||
|
|||||||
@@ -260,7 +260,7 @@ class DimensionDataNetworkModule(DimensionDataModule):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.module.fail_json(
|
self.module.fail_json(
|
||||||
"Unexpected failure deleting network with id %s" % network.id
|
"Unexpected failure deleting network with id %s", network.id
|
||||||
)
|
)
|
||||||
|
|
||||||
except DimensionDataAPIException as e:
|
except DimensionDataAPIException as e:
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ options:
|
|||||||
- The region of the instance. This is a required parameter only when
|
- The region of the instance. This is a required parameter only when
|
||||||
creating Linode instances. See
|
creating Linode instances. See
|
||||||
U(https://www.linode.com/docs/api/regions/).
|
U(https://www.linode.com/docs/api/regions/).
|
||||||
|
required: false
|
||||||
type: str
|
type: str
|
||||||
image:
|
image:
|
||||||
description:
|
description:
|
||||||
@@ -35,12 +36,14 @@ options:
|
|||||||
creating Linode instances. See
|
creating Linode instances. See
|
||||||
U(https://www.linode.com/docs/api/images/).
|
U(https://www.linode.com/docs/api/images/).
|
||||||
type: str
|
type: str
|
||||||
|
required: false
|
||||||
type:
|
type:
|
||||||
description:
|
description:
|
||||||
- The type of the instance. This is a required parameter only when
|
- The type of the instance. This is a required parameter only when
|
||||||
creating Linode instances. See
|
creating Linode instances. See
|
||||||
U(https://www.linode.com/docs/api/linode-types/).
|
U(https://www.linode.com/docs/api/linode-types/).
|
||||||
type: str
|
type: str
|
||||||
|
required: false
|
||||||
label:
|
label:
|
||||||
description:
|
description:
|
||||||
- The instance label. This label is used as the main determiner for
|
- The instance label. This label is used as the main determiner for
|
||||||
@@ -53,17 +56,12 @@ options:
|
|||||||
group labelling is deprecated but still supported. The encouraged
|
group labelling is deprecated but still supported. The encouraged
|
||||||
method for marking instances is to use tags.
|
method for marking instances is to use tags.
|
||||||
type: str
|
type: str
|
||||||
private_ip:
|
required: false
|
||||||
description:
|
|
||||||
- If C(true), the created Linode will have private networking enabled and
|
|
||||||
assigned a private IPv4 address.
|
|
||||||
type: bool
|
|
||||||
default: false
|
|
||||||
version_added: 3.0.0
|
|
||||||
tags:
|
tags:
|
||||||
description:
|
description:
|
||||||
- The tags that the instance should be marked under. See
|
- The tags that the instance should be marked under. See
|
||||||
U(https://www.linode.com/docs/api/tags/).
|
U(https://www.linode.com/docs/api/tags/).
|
||||||
|
required: false
|
||||||
type: list
|
type: list
|
||||||
elements: str
|
elements: str
|
||||||
root_pass:
|
root_pass:
|
||||||
@@ -71,10 +69,12 @@ options:
|
|||||||
- The password for the root user. If not specified, one will be
|
- The password for the root user. If not specified, one will be
|
||||||
generated. This generated password will be available in the task
|
generated. This generated password will be available in the task
|
||||||
success JSON.
|
success JSON.
|
||||||
|
required: false
|
||||||
type: str
|
type: str
|
||||||
authorized_keys:
|
authorized_keys:
|
||||||
description:
|
description:
|
||||||
- A list of SSH public key parts to deploy for the root user.
|
- A list of SSH public key parts to deploy for the root user.
|
||||||
|
required: false
|
||||||
type: list
|
type: list
|
||||||
elements: str
|
elements: str
|
||||||
state:
|
state:
|
||||||
@@ -208,8 +208,9 @@ def create_linode(module, client, **kwargs):
|
|||||||
else:
|
else:
|
||||||
return response._raw_json
|
return response._raw_json
|
||||||
except TypeError:
|
except TypeError:
|
||||||
module.fail_json(msg='Unable to parse Linode instance creation response. Please raise a bug against this'
|
module.fail_json(msg='Unable to parse Linode instance creation'
|
||||||
' module on https://github.com/ansible-collections/community.general/issues'
|
' response. Please raise a bug against this'
|
||||||
|
' module on https://github.com/ansible/ansible/issues'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -241,16 +242,15 @@ def initialise_module():
|
|||||||
no_log=True,
|
no_log=True,
|
||||||
fallback=(env_fallback, ['LINODE_ACCESS_TOKEN']),
|
fallback=(env_fallback, ['LINODE_ACCESS_TOKEN']),
|
||||||
),
|
),
|
||||||
authorized_keys=dict(type='list', elements='str', no_log=False),
|
authorized_keys=dict(type='list', elements='str', required=False, no_log=False),
|
||||||
group=dict(type='str'),
|
group=dict(type='str', required=False),
|
||||||
image=dict(type='str'),
|
image=dict(type='str', required=False),
|
||||||
private_ip=dict(type='bool', default=False),
|
region=dict(type='str', required=False),
|
||||||
region=dict(type='str'),
|
root_pass=dict(type='str', required=False, no_log=True),
|
||||||
root_pass=dict(type='str', no_log=True),
|
tags=dict(type='list', elements='str', required=False),
|
||||||
tags=dict(type='list', elements='str'),
|
type=dict(type='str', required=False),
|
||||||
type=dict(type='str'),
|
stackscript_id=dict(type='int', required=False),
|
||||||
stackscript_id=dict(type='int'),
|
stackscript_data=dict(type='dict', required=False),
|
||||||
stackscript_data=dict(type='dict'),
|
|
||||||
),
|
),
|
||||||
supports_check_mode=False,
|
supports_check_mode=False,
|
||||||
required_one_of=(
|
required_one_of=(
|
||||||
@@ -290,7 +290,6 @@ def main():
|
|||||||
group=module.params['group'],
|
group=module.params['group'],
|
||||||
image=module.params['image'],
|
image=module.params['image'],
|
||||||
label=module.params['label'],
|
label=module.params['label'],
|
||||||
private_ip=module.params['private_ip'],
|
|
||||||
region=module.params['region'],
|
region=module.params['region'],
|
||||||
root_pass=module.params['root_pass'],
|
root_pass=module.params['root_pass'],
|
||||||
tags=module.params['tags'],
|
tags=module.params['tags'],
|
||||||
|
|||||||
1
plugins/modules/cloud/memset/memset_memstore_facts.py
Symbolic link
1
plugins/modules/cloud/memset/memset_memstore_facts.py
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
memset_memstore_info.py
|
||||||
@@ -151,6 +151,9 @@ def main():
|
|||||||
),
|
),
|
||||||
supports_check_mode=False
|
supports_check_mode=False
|
||||||
)
|
)
|
||||||
|
if module._name in ('memset_memstore_facts', 'community.general.memset_memstore_facts'):
|
||||||
|
module.deprecate("The 'memset_memstore_facts' module has been renamed to 'memset_memstore_info'",
|
||||||
|
version='3.0.0', collection_name='community.general') # was Ansible 2.13
|
||||||
|
|
||||||
# populate the dict with the user-provided vars.
|
# populate the dict with the user-provided vars.
|
||||||
args = dict()
|
args = dict()
|
||||||
|
|||||||
1
plugins/modules/cloud/memset/memset_server_facts.py
Symbolic link
1
plugins/modules/cloud/memset/memset_server_facts.py
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
memset_server_info.py
|
||||||
@@ -276,6 +276,9 @@ def main():
|
|||||||
),
|
),
|
||||||
supports_check_mode=False
|
supports_check_mode=False
|
||||||
)
|
)
|
||||||
|
if module._name in ('memset_server_facts', 'community.general.memset_server_facts'):
|
||||||
|
module.deprecate("The 'memset_server_facts' module has been renamed to 'memset_server_info'",
|
||||||
|
version='3.0.0', collection_name='community.general') # was Ansible 2.13
|
||||||
|
|
||||||
# populate the dict with the user-provided vars.
|
# populate the dict with the user-provided vars.
|
||||||
args = dict()
|
args = dict()
|
||||||
|
|||||||
216
plugins/modules/cloud/misc/helm.py
Normal file
216
plugins/modules/cloud/misc/helm.py
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# (c) 2016, Flavio Percoco <flavio@redhat.com>
|
||||||
|
#
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.14
|
||||||
|
why: For more details https://github.com/ansible/ansible/issues/61546.
|
||||||
|
alternative: Use M(community.kubernetes.helm) instead.
|
||||||
|
module: helm
|
||||||
|
short_description: Manages Kubernetes packages with the Helm package manager
|
||||||
|
author: "Flavio Percoco (@flaper87)"
|
||||||
|
description:
|
||||||
|
- Install, upgrade, delete and list packages with the Helm package manager.
|
||||||
|
requirements:
|
||||||
|
- "pyhelm"
|
||||||
|
- "grpcio"
|
||||||
|
options:
|
||||||
|
host:
|
||||||
|
description:
|
||||||
|
- Tiller's server host.
|
||||||
|
type: str
|
||||||
|
default: "localhost"
|
||||||
|
port:
|
||||||
|
description:
|
||||||
|
- Tiller's server port.
|
||||||
|
type: int
|
||||||
|
default: 44134
|
||||||
|
namespace:
|
||||||
|
description:
|
||||||
|
- Kubernetes namespace where the chart should be installed.
|
||||||
|
type: str
|
||||||
|
default: "default"
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Release name to manage.
|
||||||
|
type: str
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Whether to install C(present), remove C(absent), or purge C(purged) a package.
|
||||||
|
choices: ['absent', 'purged', 'present']
|
||||||
|
type: str
|
||||||
|
default: "present"
|
||||||
|
chart:
|
||||||
|
description:
|
||||||
|
- A map describing the chart to install. See examples for available options.
|
||||||
|
type: dict
|
||||||
|
default: {}
|
||||||
|
values:
|
||||||
|
description:
|
||||||
|
- A map of value options for the chart.
|
||||||
|
type: dict
|
||||||
|
default: {}
|
||||||
|
disable_hooks:
|
||||||
|
description:
|
||||||
|
- Whether to disable hooks during the uninstall process.
|
||||||
|
type: bool
|
||||||
|
default: 'no'
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = ''' # '''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
- name: Install helm chart
|
||||||
|
community.general.helm:
|
||||||
|
host: localhost
|
||||||
|
chart:
|
||||||
|
name: memcached
|
||||||
|
version: 0.4.0
|
||||||
|
source:
|
||||||
|
type: repo
|
||||||
|
location: https://kubernetes-charts.storage.googleapis.com
|
||||||
|
state: present
|
||||||
|
name: my-memcached
|
||||||
|
namespace: default
|
||||||
|
|
||||||
|
- name: Uninstall helm chart
|
||||||
|
community.general.helm:
|
||||||
|
host: localhost
|
||||||
|
state: absent
|
||||||
|
name: my-memcached
|
||||||
|
|
||||||
|
- name: Install helm chart from a git repo
|
||||||
|
community.general.helm:
|
||||||
|
host: localhost
|
||||||
|
chart:
|
||||||
|
source:
|
||||||
|
type: git
|
||||||
|
location: https://github.com/user/helm-chart.git
|
||||||
|
state: present
|
||||||
|
name: my-example
|
||||||
|
namespace: default
|
||||||
|
values:
|
||||||
|
foo: "bar"
|
||||||
|
|
||||||
|
- name: Install helm chart from a git repo specifying path
|
||||||
|
community.general.helm:
|
||||||
|
host: localhost
|
||||||
|
chart:
|
||||||
|
source:
|
||||||
|
type: git
|
||||||
|
location: https://github.com/helm/charts.git
|
||||||
|
path: stable/memcached
|
||||||
|
state: present
|
||||||
|
name: my-memcached
|
||||||
|
namespace: default
|
||||||
|
values: "{{ lookup('file', '/path/to/file/values.yaml') | from_yaml }}"
|
||||||
|
'''
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
HELM_IMPORT_ERR = None
|
||||||
|
try:
|
||||||
|
import grpc
|
||||||
|
from pyhelm import tiller
|
||||||
|
from pyhelm import chartbuilder
|
||||||
|
except ImportError:
|
||||||
|
HELM_IMPORT_ERR = traceback.format_exc()
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||||
|
|
||||||
|
|
||||||
|
def install(module, tserver):
|
||||||
|
changed = False
|
||||||
|
params = module.params
|
||||||
|
name = params['name']
|
||||||
|
values = params['values']
|
||||||
|
chart = module.params['chart']
|
||||||
|
namespace = module.params['namespace']
|
||||||
|
|
||||||
|
chartb = chartbuilder.ChartBuilder(chart)
|
||||||
|
r_matches = (x for x in tserver.list_releases()
|
||||||
|
if x.name == name and x.namespace == namespace)
|
||||||
|
installed_release = next(r_matches, None)
|
||||||
|
if installed_release:
|
||||||
|
if installed_release.chart.metadata.version != chart['version']:
|
||||||
|
tserver.update_release(chartb.get_helm_chart(), False,
|
||||||
|
namespace, name=name, values=values)
|
||||||
|
changed = True
|
||||||
|
else:
|
||||||
|
tserver.install_release(chartb.get_helm_chart(), namespace,
|
||||||
|
dry_run=False, name=name,
|
||||||
|
values=values)
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
return dict(changed=changed)
|
||||||
|
|
||||||
|
|
||||||
|
def delete(module, tserver, purge=False):
|
||||||
|
changed = False
|
||||||
|
params = module.params
|
||||||
|
|
||||||
|
if not module.params['name']:
|
||||||
|
module.fail_json(msg='Missing required field name')
|
||||||
|
|
||||||
|
name = module.params['name']
|
||||||
|
disable_hooks = params['disable_hooks']
|
||||||
|
|
||||||
|
try:
|
||||||
|
tserver.uninstall_release(name, disable_hooks, purge)
|
||||||
|
changed = True
|
||||||
|
except grpc._channel._Rendezvous as exc:
|
||||||
|
if 'not found' not in str(exc):
|
||||||
|
raise exc
|
||||||
|
|
||||||
|
return dict(changed=changed)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""The main function."""
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec=dict(
|
||||||
|
host=dict(type='str', default='localhost'),
|
||||||
|
port=dict(type='int', default=44134),
|
||||||
|
name=dict(type='str', default=''),
|
||||||
|
chart=dict(type='dict'),
|
||||||
|
state=dict(
|
||||||
|
choices=['absent', 'purged', 'present'],
|
||||||
|
default='present'
|
||||||
|
),
|
||||||
|
# Install options
|
||||||
|
values=dict(type='dict'),
|
||||||
|
namespace=dict(type='str', default='default'),
|
||||||
|
|
||||||
|
# Uninstall options
|
||||||
|
disable_hooks=dict(type='bool', default=False),
|
||||||
|
),
|
||||||
|
supports_check_mode=True)
|
||||||
|
|
||||||
|
if HELM_IMPORT_ERR:
|
||||||
|
module.fail_json(msg=missing_required_lib('pyhelm'), exception=HELM_IMPORT_ERR)
|
||||||
|
|
||||||
|
host = module.params['host']
|
||||||
|
port = module.params['port']
|
||||||
|
state = module.params['state']
|
||||||
|
tserver = tiller.Tiller(host, port)
|
||||||
|
|
||||||
|
if state == 'present':
|
||||||
|
rst = install(module, tserver)
|
||||||
|
|
||||||
|
if state in 'absent':
|
||||||
|
rst = delete(module, tserver)
|
||||||
|
|
||||||
|
if state in 'purged':
|
||||||
|
rst = delete(module, tserver, True)
|
||||||
|
|
||||||
|
module.exit_json(**rst)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
503
plugins/modules/cloud/misc/ovirt.py
Normal file
503
plugins/modules/cloud/misc/ovirt.py
Normal file
@@ -0,0 +1,503 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# Copyright: (c) 2013, Vincent Van der Kussen <vincent at vanderkussen.org>
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: ovirt
|
||||||
|
author:
|
||||||
|
- Vincent Van der Kussen (@vincentvdk)
|
||||||
|
short_description: oVirt/RHEV platform management
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.14
|
||||||
|
why: This module is for deprecated version of ovirt.
|
||||||
|
alternative: Use C(ovirt_vm) from the C(ovirt.ovirt) collection instead
|
||||||
|
description:
|
||||||
|
- This module only supports oVirt/RHEV version 3. A newer module M(ovirt.ovirt.ovirt_vm) supports oVirt/RHV version 4.
|
||||||
|
- Allows you to create new instances, either from scratch or an image, in addition to deleting or stopping instances on the oVirt/RHEV platform.
|
||||||
|
options:
|
||||||
|
user:
|
||||||
|
description:
|
||||||
|
- The user to authenticate with.
|
||||||
|
type: str
|
||||||
|
required: true
|
||||||
|
url:
|
||||||
|
description:
|
||||||
|
- The url of the oVirt instance.
|
||||||
|
type: str
|
||||||
|
required: true
|
||||||
|
instance_name:
|
||||||
|
description:
|
||||||
|
- The name of the instance to use.
|
||||||
|
type: str
|
||||||
|
required: true
|
||||||
|
aliases: [ vmname ]
|
||||||
|
password:
|
||||||
|
description:
|
||||||
|
- Password of the user to authenticate with.
|
||||||
|
type: str
|
||||||
|
required: true
|
||||||
|
image:
|
||||||
|
description:
|
||||||
|
- The template to use for the instance.
|
||||||
|
type: str
|
||||||
|
resource_type:
|
||||||
|
description:
|
||||||
|
- Whether you want to deploy an image or create an instance from scratch.
|
||||||
|
type: str
|
||||||
|
choices: [ new, template ]
|
||||||
|
zone:
|
||||||
|
description:
|
||||||
|
- Deploy the image to this oVirt cluster.
|
||||||
|
type: str
|
||||||
|
instance_disksize:
|
||||||
|
description:
|
||||||
|
- Size of the instance's disk in GB.
|
||||||
|
type: str
|
||||||
|
aliases: [ vm_disksize]
|
||||||
|
instance_cpus:
|
||||||
|
description:
|
||||||
|
- The instance's number of CPUs.
|
||||||
|
type: str
|
||||||
|
default: 1
|
||||||
|
aliases: [ vmcpus ]
|
||||||
|
instance_nic:
|
||||||
|
description:
|
||||||
|
- The name of the network interface in oVirt/RHEV.
|
||||||
|
type: str
|
||||||
|
aliases: [ vmnic ]
|
||||||
|
instance_network:
|
||||||
|
description:
|
||||||
|
- The logical network the machine should belong to.
|
||||||
|
type: str
|
||||||
|
default: rhevm
|
||||||
|
aliases: [ vmnetwork ]
|
||||||
|
instance_mem:
|
||||||
|
description:
|
||||||
|
- The instance's amount of memory in MB.
|
||||||
|
type: str
|
||||||
|
aliases: [ vmmem ]
|
||||||
|
instance_type:
|
||||||
|
description:
|
||||||
|
- Define whether the instance is a server, desktop or high_performance.
|
||||||
|
- I(high_performance) is supported since Ansible 2.5 and oVirt/RHV 4.2.
|
||||||
|
type: str
|
||||||
|
choices: [ desktop, server, high_performance ]
|
||||||
|
default: server
|
||||||
|
aliases: [ vmtype ]
|
||||||
|
disk_alloc:
|
||||||
|
description:
|
||||||
|
- Define whether disk is thin or preallocated.
|
||||||
|
type: str
|
||||||
|
choices: [ preallocated, thin ]
|
||||||
|
default: thin
|
||||||
|
disk_int:
|
||||||
|
description:
|
||||||
|
- Interface type of the disk.
|
||||||
|
type: str
|
||||||
|
choices: [ ide, virtio ]
|
||||||
|
default: virtio
|
||||||
|
instance_os:
|
||||||
|
description:
|
||||||
|
- Type of Operating System.
|
||||||
|
type: str
|
||||||
|
aliases: [ vmos ]
|
||||||
|
instance_cores:
|
||||||
|
description:
|
||||||
|
- Define the instance's number of cores.
|
||||||
|
type: str
|
||||||
|
default: 1
|
||||||
|
aliases: [ vmcores ]
|
||||||
|
sdomain:
|
||||||
|
description:
|
||||||
|
- The Storage Domain where you want to create the instance's disk on.
|
||||||
|
type: str
|
||||||
|
region:
|
||||||
|
description:
|
||||||
|
- The oVirt/RHEV datacenter where you want to deploy to.
|
||||||
|
type: str
|
||||||
|
instance_dns:
|
||||||
|
description:
|
||||||
|
- Define the instance's Primary DNS server.
|
||||||
|
type: str
|
||||||
|
aliases: [ dns ]
|
||||||
|
instance_domain:
|
||||||
|
description:
|
||||||
|
- Define the instance's Domain.
|
||||||
|
type: str
|
||||||
|
aliases: [ domain ]
|
||||||
|
instance_hostname:
|
||||||
|
description:
|
||||||
|
- Define the instance's Hostname.
|
||||||
|
type: str
|
||||||
|
aliases: [ hostname ]
|
||||||
|
instance_ip:
|
||||||
|
description:
|
||||||
|
- Define the instance's IP.
|
||||||
|
type: str
|
||||||
|
aliases: [ ip ]
|
||||||
|
instance_netmask:
|
||||||
|
description:
|
||||||
|
- Define the instance's Netmask.
|
||||||
|
type: str
|
||||||
|
aliases: [ netmask ]
|
||||||
|
instance_gateway:
|
||||||
|
description:
|
||||||
|
- Define the instance's Gateway.
|
||||||
|
type: str
|
||||||
|
aliases: [ gateway ]
|
||||||
|
instance_rootpw:
|
||||||
|
description:
|
||||||
|
- Define the instance's Root password.
|
||||||
|
type: str
|
||||||
|
aliases: [ rootpw ]
|
||||||
|
instance_key:
|
||||||
|
description:
|
||||||
|
- Define the instance's Authorized key.
|
||||||
|
type: str
|
||||||
|
aliases: [ key ]
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Create, terminate or remove instances.
|
||||||
|
type: str
|
||||||
|
choices: [ absent, present, restart, shutdown, started ]
|
||||||
|
default: present
|
||||||
|
requirements:
|
||||||
|
- ovirt-engine-sdk-python
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
- name: Basic example to provision from image
|
||||||
|
community.general.ovirt:
|
||||||
|
user: admin@internal
|
||||||
|
url: https://ovirt.example.com
|
||||||
|
instance_name: ansiblevm04
|
||||||
|
password: secret
|
||||||
|
image: centos_64
|
||||||
|
zone: cluster01
|
||||||
|
resource_type: template
|
||||||
|
|
||||||
|
- name: Full example to create new instance from scratch
|
||||||
|
community.general.ovirt:
|
||||||
|
instance_name: testansible
|
||||||
|
resource_type: new
|
||||||
|
instance_type: server
|
||||||
|
user: admin@internal
|
||||||
|
password: secret
|
||||||
|
url: https://ovirt.example.com
|
||||||
|
instance_disksize: 10
|
||||||
|
zone: cluster01
|
||||||
|
region: datacenter1
|
||||||
|
instance_cpus: 1
|
||||||
|
instance_nic: nic1
|
||||||
|
instance_network: rhevm
|
||||||
|
instance_mem: 1000
|
||||||
|
disk_alloc: thin
|
||||||
|
sdomain: FIBER01
|
||||||
|
instance_cores: 1
|
||||||
|
instance_os: rhel_6x64
|
||||||
|
disk_int: virtio
|
||||||
|
|
||||||
|
- name: Stopping an existing instance
|
||||||
|
community.general.ovirt:
|
||||||
|
instance_name: testansible
|
||||||
|
state: stopped
|
||||||
|
user: admin@internal
|
||||||
|
password: secret
|
||||||
|
url: https://ovirt.example.com
|
||||||
|
|
||||||
|
- name: Start an existing instance
|
||||||
|
community.general.ovirt:
|
||||||
|
instance_name: testansible
|
||||||
|
state: started
|
||||||
|
user: admin@internal
|
||||||
|
password: secret
|
||||||
|
url: https://ovirt.example.com
|
||||||
|
|
||||||
|
- name: Start an instance with cloud init information
|
||||||
|
community.general.ovirt:
|
||||||
|
instance_name: testansible
|
||||||
|
state: started
|
||||||
|
user: admin@internal
|
||||||
|
password: secret
|
||||||
|
url: https://ovirt.example.com
|
||||||
|
hostname: testansible
|
||||||
|
domain: ansible.local
|
||||||
|
ip: 192.0.2.100
|
||||||
|
netmask: 255.255.255.0
|
||||||
|
gateway: 192.0.2.1
|
||||||
|
rootpw: bigsecret
|
||||||
|
'''
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
|
try:
|
||||||
|
from ovirtsdk.api import API
|
||||||
|
from ovirtsdk.xml import params
|
||||||
|
HAS_OVIRTSDK = True
|
||||||
|
except ImportError:
|
||||||
|
HAS_OVIRTSDK = False
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible.module_utils.common.removed import removed_module
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------- #
|
||||||
|
# create connection with API
|
||||||
|
#
|
||||||
|
def conn(url, user, password):
|
||||||
|
api = API(url=url, username=user, password=password, insecure=True)
|
||||||
|
try:
|
||||||
|
value = api.test()
|
||||||
|
except Exception:
|
||||||
|
raise Exception("error connecting to the oVirt API")
|
||||||
|
return api
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------- #
|
||||||
|
# Create VM from scratch
|
||||||
|
def create_vm(conn, vmtype, vmname, zone, vmdisk_size, vmcpus, vmnic, vmnetwork, vmmem, vmdisk_alloc, sdomain, vmcores, vmos, vmdisk_int):
|
||||||
|
if vmdisk_alloc == 'thin':
|
||||||
|
# define VM params
|
||||||
|
vmparams = params.VM(name=vmname, cluster=conn.clusters.get(name=zone), os=params.OperatingSystem(type_=vmos),
|
||||||
|
template=conn.templates.get(name="Blank"), memory=1024 * 1024 * int(vmmem),
|
||||||
|
cpu=params.CPU(topology=params.CpuTopology(cores=int(vmcores), sockets=vmcpus)), type_=vmtype)
|
||||||
|
# define disk params
|
||||||
|
vmdisk = params.Disk(size=1024 * 1024 * 1024 * int(vmdisk_size), wipe_after_delete=True, sparse=True, interface=vmdisk_int, type_="System",
|
||||||
|
format='cow',
|
||||||
|
storage_domains=params.StorageDomains(storage_domain=[conn.storagedomains.get(name=sdomain)]))
|
||||||
|
# define network parameters
|
||||||
|
network_net = params.Network(name=vmnetwork)
|
||||||
|
nic_net1 = params.NIC(name='nic1', network=network_net, interface='virtio')
|
||||||
|
elif vmdisk_alloc == 'preallocated':
|
||||||
|
# define VM params
|
||||||
|
vmparams = params.VM(name=vmname, cluster=conn.clusters.get(name=zone), os=params.OperatingSystem(type_=vmos),
|
||||||
|
template=conn.templates.get(name="Blank"), memory=1024 * 1024 * int(vmmem),
|
||||||
|
cpu=params.CPU(topology=params.CpuTopology(cores=int(vmcores), sockets=vmcpus)), type_=vmtype)
|
||||||
|
# define disk params
|
||||||
|
vmdisk = params.Disk(size=1024 * 1024 * 1024 * int(vmdisk_size), wipe_after_delete=True, sparse=False, interface=vmdisk_int, type_="System",
|
||||||
|
format='raw', storage_domains=params.StorageDomains(storage_domain=[conn.storagedomains.get(name=sdomain)]))
|
||||||
|
# define network parameters
|
||||||
|
network_net = params.Network(name=vmnetwork)
|
||||||
|
nic_net1 = params.NIC(name=vmnic, network=network_net, interface='virtio')
|
||||||
|
|
||||||
|
try:
|
||||||
|
conn.vms.add(vmparams)
|
||||||
|
except Exception:
|
||||||
|
raise Exception("Error creating VM with specified parameters")
|
||||||
|
vm = conn.vms.get(name=vmname)
|
||||||
|
try:
|
||||||
|
vm.disks.add(vmdisk)
|
||||||
|
except Exception:
|
||||||
|
raise Exception("Error attaching disk")
|
||||||
|
try:
|
||||||
|
vm.nics.add(nic_net1)
|
||||||
|
except Exception:
|
||||||
|
raise Exception("Error adding nic")
|
||||||
|
|
||||||
|
|
||||||
|
# create an instance from a template
|
||||||
|
def create_vm_template(conn, vmname, image, zone):
|
||||||
|
vmparams = params.VM(name=vmname, cluster=conn.clusters.get(name=zone), template=conn.templates.get(name=image), disks=params.Disks(clone=True))
|
||||||
|
try:
|
||||||
|
conn.vms.add(vmparams)
|
||||||
|
except Exception:
|
||||||
|
raise Exception('error adding template %s' % image)
|
||||||
|
|
||||||
|
|
||||||
|
# start instance
|
||||||
|
def vm_start(conn, vmname, hostname=None, ip=None, netmask=None, gateway=None,
|
||||||
|
domain=None, dns=None, rootpw=None, key=None):
|
||||||
|
vm = conn.vms.get(name=vmname)
|
||||||
|
use_cloud_init = False
|
||||||
|
nics = None
|
||||||
|
nic = None
|
||||||
|
if hostname or ip or netmask or gateway or domain or dns or rootpw or key:
|
||||||
|
use_cloud_init = True
|
||||||
|
if ip and netmask and gateway:
|
||||||
|
ipinfo = params.IP(address=ip, netmask=netmask, gateway=gateway)
|
||||||
|
nic = params.GuestNicConfiguration(name='eth0', boot_protocol='STATIC', ip=ipinfo, on_boot=True)
|
||||||
|
nics = params.Nics()
|
||||||
|
nics = params.GuestNicsConfiguration(nic_configuration=[nic])
|
||||||
|
initialization = params.Initialization(regenerate_ssh_keys=True, host_name=hostname, domain=domain, user_name='root',
|
||||||
|
root_password=rootpw, nic_configurations=nics, dns_servers=dns,
|
||||||
|
authorized_ssh_keys=key)
|
||||||
|
action = params.Action(use_cloud_init=use_cloud_init, vm=params.VM(initialization=initialization))
|
||||||
|
vm.start(action=action)
|
||||||
|
|
||||||
|
|
||||||
|
# Stop instance
|
||||||
|
def vm_stop(conn, vmname):
|
||||||
|
vm = conn.vms.get(name=vmname)
|
||||||
|
vm.stop()
|
||||||
|
|
||||||
|
|
||||||
|
# restart instance
|
||||||
|
def vm_restart(conn, vmname):
|
||||||
|
state = vm_status(conn, vmname)
|
||||||
|
vm = conn.vms.get(name=vmname)
|
||||||
|
vm.stop()
|
||||||
|
while conn.vms.get(vmname).get_status().get_state() != 'down':
|
||||||
|
time.sleep(5)
|
||||||
|
vm.start()
|
||||||
|
|
||||||
|
|
||||||
|
# remove an instance
|
||||||
|
def vm_remove(conn, vmname):
|
||||||
|
vm = conn.vms.get(name=vmname)
|
||||||
|
vm.delete()
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------- #
|
||||||
|
# VM statuses
|
||||||
|
#
|
||||||
|
# Get the VMs status
|
||||||
|
def vm_status(conn, vmname):
|
||||||
|
status = conn.vms.get(name=vmname).status.state
|
||||||
|
return status
|
||||||
|
|
||||||
|
|
||||||
|
# Get VM object and return it's name if object exists
|
||||||
|
def get_vm(conn, vmname):
|
||||||
|
vm = conn.vms.get(name=vmname)
|
||||||
|
if vm is None:
|
||||||
|
name = "empty"
|
||||||
|
else:
|
||||||
|
name = vm.get_name()
|
||||||
|
return name
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------- #
|
||||||
|
# Hypervisor operations
|
||||||
|
#
|
||||||
|
# not available yet
|
||||||
|
# ------------------------------------------------------------------- #
|
||||||
|
# Main
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec=dict(
|
||||||
|
state=dict(type='str', default='present', choices=['absent', 'present', 'restart', 'shutdown', 'started']),
|
||||||
|
user=dict(type='str', required=True),
|
||||||
|
url=dict(type='str', required=True),
|
||||||
|
instance_name=dict(type='str', required=True, aliases=['vmname']),
|
||||||
|
password=dict(type='str', required=True, no_log=True),
|
||||||
|
image=dict(type='str'),
|
||||||
|
resource_type=dict(type='str', choices=['new', 'template']),
|
||||||
|
zone=dict(type='str'),
|
||||||
|
instance_disksize=dict(type='str', aliases=['vm_disksize']),
|
||||||
|
instance_cpus=dict(type='str', default=1, aliases=['vmcpus']),
|
||||||
|
instance_nic=dict(type='str', aliases=['vmnic']),
|
||||||
|
instance_network=dict(type='str', default='rhevm', aliases=['vmnetwork']),
|
||||||
|
instance_mem=dict(type='str', aliases=['vmmem']),
|
||||||
|
instance_type=dict(type='str', default='server', aliases=['vmtype'], choices=['desktop', 'server', 'high_performance']),
|
||||||
|
disk_alloc=dict(type='str', default='thin', choices=['preallocated', 'thin']),
|
||||||
|
disk_int=dict(type='str', default='virtio', choices=['ide', 'virtio']),
|
||||||
|
instance_os=dict(type='str', aliases=['vmos']),
|
||||||
|
instance_cores=dict(type='str', default=1, aliases=['vmcores']),
|
||||||
|
instance_hostname=dict(type='str', aliases=['hostname']),
|
||||||
|
instance_ip=dict(type='str', aliases=['ip']),
|
||||||
|
instance_netmask=dict(type='str', aliases=['netmask']),
|
||||||
|
instance_gateway=dict(type='str', aliases=['gateway']),
|
||||||
|
instance_domain=dict(type='str', aliases=['domain']),
|
||||||
|
instance_dns=dict(type='str', aliases=['dns']),
|
||||||
|
instance_rootpw=dict(type='str', aliases=['rootpw'], no_log=True),
|
||||||
|
instance_key=dict(type='str', aliases=['key'], no_log=True),
|
||||||
|
sdomain=dict(type='str'),
|
||||||
|
region=dict(type='str'),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
if not HAS_OVIRTSDK:
|
||||||
|
module.fail_json(msg='ovirtsdk required for this module')
|
||||||
|
|
||||||
|
state = module.params['state']
|
||||||
|
user = module.params['user']
|
||||||
|
url = module.params['url']
|
||||||
|
vmname = module.params['instance_name']
|
||||||
|
password = module.params['password']
|
||||||
|
image = module.params['image'] # name of the image to deploy
|
||||||
|
resource_type = module.params['resource_type'] # template or from scratch
|
||||||
|
zone = module.params['zone'] # oVirt cluster
|
||||||
|
vmdisk_size = module.params['instance_disksize'] # disksize
|
||||||
|
vmcpus = module.params['instance_cpus'] # number of cpu
|
||||||
|
vmnic = module.params['instance_nic'] # network interface
|
||||||
|
vmnetwork = module.params['instance_network'] # logical network
|
||||||
|
vmmem = module.params['instance_mem'] # mem size
|
||||||
|
vmdisk_alloc = module.params['disk_alloc'] # thin, preallocated
|
||||||
|
vmdisk_int = module.params['disk_int'] # disk interface virtio or ide
|
||||||
|
vmos = module.params['instance_os'] # Operating System
|
||||||
|
vmtype = module.params['instance_type'] # server, desktop or high_performance
|
||||||
|
vmcores = module.params['instance_cores'] # number of cores
|
||||||
|
sdomain = module.params['sdomain'] # storage domain to store disk on
|
||||||
|
region = module.params['region'] # oVirt Datacenter
|
||||||
|
hostname = module.params['instance_hostname']
|
||||||
|
ip = module.params['instance_ip']
|
||||||
|
netmask = module.params['instance_netmask']
|
||||||
|
gateway = module.params['instance_gateway']
|
||||||
|
domain = module.params['instance_domain']
|
||||||
|
dns = module.params['instance_dns']
|
||||||
|
rootpw = module.params['instance_rootpw']
|
||||||
|
key = module.params['instance_key']
|
||||||
|
# initialize connection
|
||||||
|
try:
|
||||||
|
c = conn(url + "/api", user, password)
|
||||||
|
except Exception as e:
|
||||||
|
module.fail_json(msg='%s' % e)
|
||||||
|
|
||||||
|
if state == 'present':
|
||||||
|
if get_vm(c, vmname) == "empty":
|
||||||
|
if resource_type == 'template':
|
||||||
|
try:
|
||||||
|
create_vm_template(c, vmname, image, zone)
|
||||||
|
except Exception as e:
|
||||||
|
module.fail_json(msg='%s' % e)
|
||||||
|
module.exit_json(changed=True, msg="deployed VM %s from template %s" % (vmname, image))
|
||||||
|
elif resource_type == 'new':
|
||||||
|
# FIXME: refactor, use keyword args.
|
||||||
|
try:
|
||||||
|
create_vm(c, vmtype, vmname, zone, vmdisk_size, vmcpus, vmnic, vmnetwork, vmmem, vmdisk_alloc, sdomain, vmcores, vmos, vmdisk_int)
|
||||||
|
except Exception as e:
|
||||||
|
module.fail_json(msg='%s' % e)
|
||||||
|
module.exit_json(changed=True, msg="deployed VM %s from scratch" % vmname)
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False, msg="You did not specify a resource type")
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False, msg="VM %s already exists" % vmname)
|
||||||
|
|
||||||
|
if state == 'started':
|
||||||
|
if vm_status(c, vmname) == 'up':
|
||||||
|
module.exit_json(changed=False, msg="VM %s is already running" % vmname)
|
||||||
|
else:
|
||||||
|
# vm_start(c, vmname)
|
||||||
|
vm_start(c, vmname, hostname, ip, netmask, gateway, domain, dns, rootpw, key)
|
||||||
|
module.exit_json(changed=True, msg="VM %s started" % vmname)
|
||||||
|
|
||||||
|
if state == 'shutdown':
|
||||||
|
if vm_status(c, vmname) == 'down':
|
||||||
|
module.exit_json(changed=False, msg="VM %s is already shutdown" % vmname)
|
||||||
|
else:
|
||||||
|
vm_stop(c, vmname)
|
||||||
|
module.exit_json(changed=True, msg="VM %s is shutting down" % vmname)
|
||||||
|
|
||||||
|
if state == 'restart':
|
||||||
|
if vm_status(c, vmname) == 'up':
|
||||||
|
vm_restart(c, vmname)
|
||||||
|
module.exit_json(changed=True, msg="VM %s is restarted" % vmname)
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False, msg="VM %s is not running" % vmname)
|
||||||
|
|
||||||
|
if state == 'absent':
|
||||||
|
if get_vm(c, vmname) == "empty":
|
||||||
|
module.exit_json(changed=False, msg="VM %s does not exist" % vmname)
|
||||||
|
else:
|
||||||
|
vm_remove(c, vmname)
|
||||||
|
module.exit_json(changed=True, msg="VM %s removed" % vmname)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright: Tristan Le Guern (@tleguern) <tleguern at bouledef.eu>
|
# Copyright: Tristan Le Guern (@Aversiste) <tleguern at bouledef.eu>
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
from __future__ import absolute_import, division, print_function
|
from __future__ import absolute_import, division, print_function
|
||||||
@@ -21,7 +21,7 @@ options:
|
|||||||
- Restrict results to a specific authentication realm.
|
- Restrict results to a specific authentication realm.
|
||||||
aliases: ['realm', 'name']
|
aliases: ['realm', 'name']
|
||||||
type: str
|
type: str
|
||||||
author: Tristan Le Guern (@tleguern)
|
author: Tristan Le Guern (@Aversiste)
|
||||||
extends_documentation_fragment: community.general.proxmox.documentation
|
extends_documentation_fragment: community.general.proxmox.documentation
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ options:
|
|||||||
- Restrict results to a specific group.
|
- Restrict results to a specific group.
|
||||||
aliases: ['groupid', 'name']
|
aliases: ['groupid', 'name']
|
||||||
type: str
|
type: str
|
||||||
author: Tristan Le Guern (@tleguern)
|
author: Tristan Le Guern (@Aversiste)
|
||||||
extends_documentation_fragment: community.general.proxmox.documentation
|
extends_documentation_fragment: community.general.proxmox.documentation
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright: Tristan Le Guern (@tleguern) <tleguern at bouledef.eu>
|
# Copyright: Tristan Le Guern (@Aversiste) <tleguern at bouledef.eu>
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
from __future__ import absolute_import, division, print_function
|
from __future__ import absolute_import, division, print_function
|
||||||
@@ -25,7 +25,7 @@ options:
|
|||||||
description:
|
description:
|
||||||
- Filter on a specifc storage type.
|
- Filter on a specifc storage type.
|
||||||
type: str
|
type: str
|
||||||
author: Tristan Le Guern (@tleguern)
|
author: Tristan Le Guern (@Aversiste)
|
||||||
extends_documentation_fragment: community.general.proxmox.documentation
|
extends_documentation_fragment: community.general.proxmox.documentation
|
||||||
notes:
|
notes:
|
||||||
- Storage specific options can be returned by this module, please look at the documentation at U(https://pve.proxmox.com/wiki/Storage).
|
- Storage specific options can be returned by this module, please look at the documentation at U(https://pve.proxmox.com/wiki/Storage).
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ options:
|
|||||||
description:
|
description:
|
||||||
- Restrict results to a specific user ID, which is a concatenation of a user and domain parts.
|
- Restrict results to a specific user ID, which is a concatenation of a user and domain parts.
|
||||||
type: str
|
type: str
|
||||||
author: Tristan Le Guern (@tleguern)
|
author: Tristan Le Guern (@Aversiste)
|
||||||
extends_documentation_fragment: community.general.proxmox.documentation
|
extends_documentation_fragment: community.general.proxmox.documentation
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|||||||
@@ -1229,6 +1229,24 @@ class RHEV(object):
|
|||||||
self.__get_conn()
|
self.__get_conn()
|
||||||
return self.conn.set_VM_Host(vmname, vmhost)
|
return self.conn.set_VM_Host(vmname, vmhost)
|
||||||
|
|
||||||
|
# pylint: disable=unreachable
|
||||||
|
VM = self.conn.get_VM(vmname)
|
||||||
|
HOST = self.conn.get_Host(vmhost)
|
||||||
|
|
||||||
|
if VM.placement_policy.host is None:
|
||||||
|
self.conn.set_VM_Host(vmname, vmhost)
|
||||||
|
elif str(VM.placement_policy.host.id) != str(HOST.id):
|
||||||
|
self.conn.set_VM_Host(vmname, vmhost)
|
||||||
|
else:
|
||||||
|
setMsg("VM's startup host was already set to " + vmhost)
|
||||||
|
checkFail()
|
||||||
|
|
||||||
|
if str(VM.status.state) == "up":
|
||||||
|
self.conn.migrate_VM(vmname, vmhost)
|
||||||
|
checkFail()
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
def setHost(self, hostname, cluster, ifaces):
|
def setHost(self, hostname, cluster, ifaces):
|
||||||
self.__get_conn()
|
self.__get_conn()
|
||||||
return self.conn.set_Host(hostname, cluster, ifaces)
|
return self.conn.set_Host(hostname, cluster, ifaces)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from __future__ import absolute_import, division, print_function
|
|||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
|
|
||||||
DOCUMENTATION = r'''
|
DOCUMENTATION = '''
|
||||||
---
|
---
|
||||||
module: terraform
|
module: terraform
|
||||||
short_description: Manages a Terraform deployment (and plans)
|
short_description: Manages a Terraform deployment (and plans)
|
||||||
@@ -33,19 +33,6 @@ options:
|
|||||||
vars.tf/main.tf/etc to use.
|
vars.tf/main.tf/etc to use.
|
||||||
type: path
|
type: path
|
||||||
required: true
|
required: true
|
||||||
plugin_paths:
|
|
||||||
description:
|
|
||||||
- List of paths containing Terraform plugin executable files.
|
|
||||||
- Plugin executables can be downloaded from U(https://releases.hashicorp.com/).
|
|
||||||
- When set, the plugin discovery and auto-download behavior of Terraform is disabled.
|
|
||||||
- The directory structure in the plugin path can be tricky. The Terraform docs
|
|
||||||
U(https://learn.hashicorp.com/tutorials/terraform/automate-terraform#pre-installed-plugins)
|
|
||||||
show a simple directory of files, but actually, the directory structure
|
|
||||||
has to follow the same structure you would see if Terraform auto-downloaded the plugins.
|
|
||||||
See the examples below for a tree output of an example plugin directory.
|
|
||||||
type: list
|
|
||||||
elements: path
|
|
||||||
version_added: 3.0.0
|
|
||||||
workspace:
|
workspace:
|
||||||
description:
|
description:
|
||||||
- The terraform workspace to work with.
|
- The terraform workspace to work with.
|
||||||
@@ -154,28 +141,6 @@ EXAMPLES = """
|
|||||||
backend_config_files:
|
backend_config_files:
|
||||||
- /path/to/backend_config_file_1
|
- /path/to/backend_config_file_1
|
||||||
- /path/to/backend_config_file_2
|
- /path/to/backend_config_file_2
|
||||||
|
|
||||||
- name: Disable plugin discovery and auto-download by setting plugin_paths
|
|
||||||
community.general.terraform:
|
|
||||||
project_path: 'project/'
|
|
||||||
state: "{{ state }}"
|
|
||||||
force_init: true
|
|
||||||
plugin_paths:
|
|
||||||
- /path/to/plugins_dir_1
|
|
||||||
- /path/to/plugins_dir_2
|
|
||||||
|
|
||||||
### Example directory structure for plugin_paths example
|
|
||||||
# $ tree /path/to/plugins_dir_1
|
|
||||||
# /path/to/plugins_dir_1/
|
|
||||||
# └── registry.terraform.io
|
|
||||||
# └── hashicorp
|
|
||||||
# └── vsphere
|
|
||||||
# ├── 1.24.0
|
|
||||||
# │ └── linux_amd64
|
|
||||||
# │ └── terraform-provider-vsphere_v1.24.0_x4
|
|
||||||
# └── 1.26.0
|
|
||||||
# └── linux_amd64
|
|
||||||
# └── terraform-provider-vsphere_v1.26.0_x4
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
RETURN = """
|
RETURN = """
|
||||||
@@ -212,31 +177,24 @@ command:
|
|||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
import tempfile
|
import tempfile
|
||||||
from distutils.version import LooseVersion
|
|
||||||
from ansible.module_utils.six.moves import shlex_quote
|
from ansible.module_utils.six.moves import shlex_quote
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
|
||||||
|
DESTROY_ARGS = ('destroy', '-no-color', '-force')
|
||||||
|
APPLY_ARGS = ('apply', '-no-color', '-input=false', '-auto-approve=true')
|
||||||
module = None
|
module = None
|
||||||
|
|
||||||
|
|
||||||
def get_version(bin_path):
|
def preflight_validation(bin_path, project_path, variables_args=None, plan_file=None):
|
||||||
extract_version = module.run_command([bin_path, 'version', '-json'])
|
|
||||||
terraform_version = (json.loads(extract_version[1]))['terraform_version']
|
|
||||||
return terraform_version
|
|
||||||
|
|
||||||
|
|
||||||
def preflight_validation(bin_path, project_path, version, variables_args=None, plan_file=None):
|
|
||||||
if project_path in [None, ''] or '/' not in project_path:
|
if project_path in [None, ''] or '/' not in project_path:
|
||||||
module.fail_json(msg="Path for Terraform project can not be None or ''.")
|
module.fail_json(msg="Path for Terraform project can not be None or ''.")
|
||||||
if not os.path.exists(bin_path):
|
if not os.path.exists(bin_path):
|
||||||
module.fail_json(msg="Path for Terraform binary '{0}' doesn't exist on this host - check the path and try again please.".format(bin_path))
|
module.fail_json(msg="Path for Terraform binary '{0}' doesn't exist on this host - check the path and try again please.".format(bin_path))
|
||||||
if not os.path.isdir(project_path):
|
if not os.path.isdir(project_path):
|
||||||
module.fail_json(msg="Path for Terraform project '{0}' doesn't exist on this host - check the path and try again please.".format(project_path))
|
module.fail_json(msg="Path for Terraform project '{0}' doesn't exist on this host - check the path and try again please.".format(project_path))
|
||||||
if LooseVersion(version) < LooseVersion('0.15.0'):
|
|
||||||
rc, out, err = module.run_command([bin_path, 'validate'] + variables_args, check_rc=True, cwd=project_path)
|
rc, out, err = module.run_command([bin_path, 'validate'] + variables_args, check_rc=True, cwd=project_path, use_unsafe_shell=True)
|
||||||
else:
|
|
||||||
rc, out, err = module.run_command([bin_path, 'validate'], check_rc=True, cwd=project_path)
|
|
||||||
|
|
||||||
|
|
||||||
def _state_args(state_file):
|
def _state_args(state_file):
|
||||||
@@ -247,7 +205,7 @@ def _state_args(state_file):
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
def init_plugins(bin_path, project_path, backend_config, backend_config_files, init_reconfigure, plugin_paths):
|
def init_plugins(bin_path, project_path, backend_config, backend_config_files, init_reconfigure):
|
||||||
command = [bin_path, 'init', '-input=false']
|
command = [bin_path, 'init', '-input=false']
|
||||||
if backend_config:
|
if backend_config:
|
||||||
for key, val in backend_config.items():
|
for key, val in backend_config.items():
|
||||||
@@ -260,9 +218,6 @@ def init_plugins(bin_path, project_path, backend_config, backend_config_files, i
|
|||||||
command.extend(['-backend-config', f])
|
command.extend(['-backend-config', f])
|
||||||
if init_reconfigure:
|
if init_reconfigure:
|
||||||
command.extend(['-reconfigure'])
|
command.extend(['-reconfigure'])
|
||||||
if plugin_paths:
|
|
||||||
for plugin_path in plugin_paths:
|
|
||||||
command.extend(['-plugin-dir', plugin_path])
|
|
||||||
rc, out, err = module.run_command(command, check_rc=True, cwd=project_path)
|
rc, out, err = module.run_command(command, check_rc=True, cwd=project_path)
|
||||||
|
|
||||||
|
|
||||||
@@ -312,7 +267,7 @@ def build_plan(command, project_path, variables_args, state_file, targets, state
|
|||||||
|
|
||||||
plan_command.extend(_state_args(state_file))
|
plan_command.extend(_state_args(state_file))
|
||||||
|
|
||||||
rc, out, err = module.run_command(plan_command + variables_args, cwd=project_path)
|
rc, out, err = module.run_command(plan_command + variables_args, cwd=project_path, use_unsafe_shell=True)
|
||||||
|
|
||||||
if rc == 0:
|
if rc == 0:
|
||||||
# no changes
|
# no changes
|
||||||
@@ -333,7 +288,6 @@ def main():
|
|||||||
argument_spec=dict(
|
argument_spec=dict(
|
||||||
project_path=dict(required=True, type='path'),
|
project_path=dict(required=True, type='path'),
|
||||||
binary_path=dict(type='path'),
|
binary_path=dict(type='path'),
|
||||||
plugin_paths=dict(type='list', elements='path'),
|
|
||||||
workspace=dict(required=False, type='str', default='default'),
|
workspace=dict(required=False, type='str', default='default'),
|
||||||
purge_workspace=dict(type='bool', default=False),
|
purge_workspace=dict(type='bool', default=False),
|
||||||
state=dict(default='present', choices=['present', 'absent', 'planned']),
|
state=dict(default='present', choices=['present', 'absent', 'planned']),
|
||||||
@@ -355,7 +309,6 @@ def main():
|
|||||||
|
|
||||||
project_path = module.params.get('project_path')
|
project_path = module.params.get('project_path')
|
||||||
bin_path = module.params.get('binary_path')
|
bin_path = module.params.get('binary_path')
|
||||||
plugin_paths = module.params.get('plugin_paths')
|
|
||||||
workspace = module.params.get('workspace')
|
workspace = module.params.get('workspace')
|
||||||
purge_workspace = module.params.get('purge_workspace')
|
purge_workspace = module.params.get('purge_workspace')
|
||||||
state = module.params.get('state')
|
state = module.params.get('state')
|
||||||
@@ -373,17 +326,8 @@ def main():
|
|||||||
else:
|
else:
|
||||||
command = [module.get_bin_path('terraform', required=True)]
|
command = [module.get_bin_path('terraform', required=True)]
|
||||||
|
|
||||||
checked_version = get_version(command[0])
|
|
||||||
|
|
||||||
if LooseVersion(checked_version) < LooseVersion('0.15.0'):
|
|
||||||
DESTROY_ARGS = ('destroy', '-no-color', '-force')
|
|
||||||
APPLY_ARGS = ('apply', '-no-color', '-input=false', '-auto-approve=true')
|
|
||||||
else:
|
|
||||||
DESTROY_ARGS = ('destroy', '-no-color', '-auto-approve')
|
|
||||||
APPLY_ARGS = ('apply', '-no-color', '-input=false', '-auto-approve')
|
|
||||||
|
|
||||||
if force_init:
|
if force_init:
|
||||||
init_plugins(command[0], project_path, backend_config, backend_config_files, init_reconfigure, plugin_paths)
|
init_plugins(command[0], project_path, backend_config, backend_config_files, init_reconfigure)
|
||||||
|
|
||||||
workspace_ctx = get_workspace_context(command[0], project_path)
|
workspace_ctx = get_workspace_context(command[0], project_path)
|
||||||
if workspace_ctx["current"] != workspace:
|
if workspace_ctx["current"] != workspace:
|
||||||
@@ -407,7 +351,7 @@ def main():
|
|||||||
for f in variables_files:
|
for f in variables_files:
|
||||||
variables_args.extend(['-var-file', f])
|
variables_args.extend(['-var-file', f])
|
||||||
|
|
||||||
preflight_validation(command[0], project_path, checked_version, variables_args)
|
preflight_validation(command[0], project_path, variables_args)
|
||||||
|
|
||||||
if module.params.get('lock') is not None:
|
if module.params.get('lock') is not None:
|
||||||
if module.params.get('lock'):
|
if module.params.get('lock'):
|
||||||
|
|||||||
175
plugins/modules/cloud/online/online_server_facts.py
Normal file
175
plugins/modules/cloud/online/online_server_facts.py
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = r'''
|
||||||
|
---
|
||||||
|
module: online_server_facts
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.13
|
||||||
|
why: Deprecated in favour of C(_info) module.
|
||||||
|
alternative: Use M(community.general.online_server_info) instead.
|
||||||
|
short_description: Gather facts about Online servers.
|
||||||
|
description:
|
||||||
|
- Gather facts about the servers.
|
||||||
|
- U(https://www.online.net/en/dedicated-server)
|
||||||
|
author:
|
||||||
|
- "Remy Leone (@sieben)"
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.general.online
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = r'''
|
||||||
|
- name: Gather Online server facts
|
||||||
|
community.general.online_server_facts:
|
||||||
|
api_token: '0d1627e8-bbf0-44c5-a46f-5c4d3aef033f'
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = r'''
|
||||||
|
---
|
||||||
|
online_server_facts:
|
||||||
|
description: Response from Online API
|
||||||
|
returned: success
|
||||||
|
type: complex
|
||||||
|
sample:
|
||||||
|
"online_server_facts": [
|
||||||
|
{
|
||||||
|
"abuse": "abuse@example.com",
|
||||||
|
"anti_ddos": false,
|
||||||
|
"bmc": {
|
||||||
|
"session_key": null
|
||||||
|
},
|
||||||
|
"boot_mode": "normal",
|
||||||
|
"contacts": {
|
||||||
|
"owner": "foobar",
|
||||||
|
"tech": "foobar"
|
||||||
|
},
|
||||||
|
"disks": [
|
||||||
|
{
|
||||||
|
"$ref": "/api/v1/server/hardware/disk/68452"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "/api/v1/server/hardware/disk/68453"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"drive_arrays": [
|
||||||
|
{
|
||||||
|
"disks": [
|
||||||
|
{
|
||||||
|
"$ref": "/api/v1/server/hardware/disk/68452"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "/api/v1/server/hardware/disk/68453"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"raid_controller": {
|
||||||
|
"$ref": "/api/v1/server/hardware/raidController/9910"
|
||||||
|
},
|
||||||
|
"raid_level": "RAID1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"hardware_watch": true,
|
||||||
|
"hostname": "sd-42",
|
||||||
|
"id": 42,
|
||||||
|
"ip": [
|
||||||
|
{
|
||||||
|
"address": "195.154.172.149",
|
||||||
|
"mac": "28:92:4a:33:5e:c6",
|
||||||
|
"reverse": "195-154-172-149.rev.poneytelecom.eu.",
|
||||||
|
"switch_port_state": "up",
|
||||||
|
"type": "public"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.90.53.212",
|
||||||
|
"mac": "28:92:4a:33:5e:c7",
|
||||||
|
"reverse": null,
|
||||||
|
"switch_port_state": "up",
|
||||||
|
"type": "private"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"last_reboot": "2018-08-23T08:32:03.000Z",
|
||||||
|
"location": {
|
||||||
|
"block": "A",
|
||||||
|
"datacenter": "DC3",
|
||||||
|
"position": 19,
|
||||||
|
"rack": "A23",
|
||||||
|
"room": "4 4-4"
|
||||||
|
},
|
||||||
|
"network": {
|
||||||
|
"ip": [
|
||||||
|
"195.154.172.149"
|
||||||
|
],
|
||||||
|
"ipfo": [],
|
||||||
|
"private": [
|
||||||
|
"10.90.53.212"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"offer": "Pro-1-S-SATA",
|
||||||
|
"os": {
|
||||||
|
"name": "FreeBSD",
|
||||||
|
"version": "11.1-RELEASE"
|
||||||
|
},
|
||||||
|
"power": "ON",
|
||||||
|
"proactive_monitoring": false,
|
||||||
|
"raid_controllers": [
|
||||||
|
{
|
||||||
|
"$ref": "/api/v1/server/hardware/raidController/9910"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"support": "Basic service level"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.community.general.plugins.module_utils.online import (
|
||||||
|
Online, OnlineException, online_argument_spec
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class OnlineServerFacts(Online):
|
||||||
|
|
||||||
|
def __init__(self, module):
|
||||||
|
super(OnlineServerFacts, self).__init__(module)
|
||||||
|
self.name = 'api/v1/server'
|
||||||
|
|
||||||
|
def _get_server_detail(self, server_path):
|
||||||
|
try:
|
||||||
|
return self.get(path=server_path).json
|
||||||
|
except OnlineException as exc:
|
||||||
|
self.module.fail_json(msg="A problem occurred while fetching: %s (%s)" % (server_path, exc))
|
||||||
|
|
||||||
|
def all_detailed_servers(self):
|
||||||
|
servers_api_path = self.get_resources()
|
||||||
|
|
||||||
|
server_data = (
|
||||||
|
self._get_server_detail(server_api_path)
|
||||||
|
for server_api_path in servers_api_path
|
||||||
|
)
|
||||||
|
|
||||||
|
return [s for s in server_data if s is not None]
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec=online_argument_spec(),
|
||||||
|
supports_check_mode=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
servers_facts = OnlineServerFacts(module).all_detailed_servers()
|
||||||
|
module.exit_json(
|
||||||
|
ansible_facts={'online_server_facts': servers_facts}
|
||||||
|
)
|
||||||
|
except OnlineException as exc:
|
||||||
|
module.fail_json(msg=exc.message)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
76
plugins/modules/cloud/online/online_user_facts.py
Normal file
76
plugins/modules/cloud/online/online_user_facts.py
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = r'''
|
||||||
|
---
|
||||||
|
module: online_user_facts
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.13
|
||||||
|
why: Deprecated in favour of C(_info) module.
|
||||||
|
alternative: Use M(community.general.online_user_info) instead.
|
||||||
|
short_description: Gather facts about Online user.
|
||||||
|
description:
|
||||||
|
- Gather facts about the user.
|
||||||
|
author:
|
||||||
|
- "Remy Leone (@sieben)"
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.general.online
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = r'''
|
||||||
|
- name: Gather Online user facts
|
||||||
|
community.general.online_user_facts:
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = r'''
|
||||||
|
---
|
||||||
|
online_user_facts:
|
||||||
|
description: Response from Online API
|
||||||
|
returned: success
|
||||||
|
type: complex
|
||||||
|
sample:
|
||||||
|
"online_user_facts": {
|
||||||
|
"company": "foobar LLC",
|
||||||
|
"email": "foobar@example.com",
|
||||||
|
"first_name": "foo",
|
||||||
|
"id": 42,
|
||||||
|
"last_name": "bar",
|
||||||
|
"login": "foobar"
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.community.general.plugins.module_utils.online import (
|
||||||
|
Online, OnlineException, online_argument_spec
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class OnlineUserFacts(Online):
|
||||||
|
|
||||||
|
def __init__(self, module):
|
||||||
|
super(OnlineUserFacts, self).__init__(module)
|
||||||
|
self.name = 'api/v1/user'
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec=online_argument_spec(),
|
||||||
|
supports_check_mode=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
module.exit_json(
|
||||||
|
ansible_facts={'online_user_facts': OnlineUserFacts(module).get_resources()}
|
||||||
|
)
|
||||||
|
except OnlineException as exc:
|
||||||
|
module.fail_json(msg=exc.message)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
@@ -31,7 +31,7 @@ short_description: Manages OpenNebula images
|
|||||||
description:
|
description:
|
||||||
- Manages OpenNebula images
|
- Manages OpenNebula images
|
||||||
requirements:
|
requirements:
|
||||||
- pyone
|
- python-oca
|
||||||
options:
|
options:
|
||||||
api_url:
|
api_url:
|
||||||
description:
|
description:
|
||||||
@@ -88,7 +88,7 @@ EXAMPLES = '''
|
|||||||
|
|
||||||
- name: Print the IMAGE properties
|
- name: Print the IMAGE properties
|
||||||
ansible.builtin.debug:
|
ansible.builtin.debug:
|
||||||
var: result
|
msg: result
|
||||||
|
|
||||||
- name: Rename existing IMAGE
|
- name: Rename existing IMAGE
|
||||||
community.general.one_image:
|
community.general.one_image:
|
||||||
@@ -168,20 +168,21 @@ running_vms:
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import pyone
|
import oca
|
||||||
HAS_PYONE = True
|
HAS_OCA = True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
HAS_PYONE = False
|
HAS_OCA = False
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
def get_image(module, client, predicate):
|
def get_image(module, client, predicate):
|
||||||
|
pool = oca.ImagePool(client)
|
||||||
# Filter -2 means fetch all images user can Use
|
# Filter -2 means fetch all images user can Use
|
||||||
pool = client.imagepool.info(-2, -1, -1, -1)
|
pool.info(filter=-2)
|
||||||
|
|
||||||
for image in pool.IMAGE:
|
for image in pool:
|
||||||
if predicate(image):
|
if predicate(image):
|
||||||
return image
|
return image
|
||||||
|
|
||||||
@@ -189,11 +190,11 @@ def get_image(module, client, predicate):
|
|||||||
|
|
||||||
|
|
||||||
def get_image_by_name(module, client, image_name):
|
def get_image_by_name(module, client, image_name):
|
||||||
return get_image(module, client, lambda image: (image.NAME == image_name))
|
return get_image(module, client, lambda image: (image.name == image_name))
|
||||||
|
|
||||||
|
|
||||||
def get_image_by_id(module, client, image_id):
|
def get_image_by_id(module, client, image_id):
|
||||||
return get_image(module, client, lambda image: (image.ID == image_id))
|
return get_image(module, client, lambda image: (image.id == image_id))
|
||||||
|
|
||||||
|
|
||||||
def get_image_instance(module, client, requested_id, requested_name):
|
def get_image_instance(module, client, requested_id, requested_name):
|
||||||
@@ -207,28 +208,30 @@ IMAGE_STATES = ['INIT', 'READY', 'USED', 'DISABLED', 'LOCKED', 'ERROR', 'CLONE',
|
|||||||
|
|
||||||
|
|
||||||
def get_image_info(image):
|
def get_image_info(image):
|
||||||
|
image.info()
|
||||||
|
|
||||||
info = {
|
info = {
|
||||||
'id': image.ID,
|
'id': image.id,
|
||||||
'name': image.NAME,
|
'name': image.name,
|
||||||
'state': IMAGE_STATES[image.STATE],
|
'state': IMAGE_STATES[image.state],
|
||||||
'running_vms': image.RUNNING_VMS,
|
'running_vms': image.running_vms,
|
||||||
'used': bool(image.RUNNING_VMS),
|
'used': bool(image.running_vms),
|
||||||
'user_name': image.UNAME,
|
'user_name': image.uname,
|
||||||
'user_id': image.UID,
|
'user_id': image.uid,
|
||||||
'group_name': image.GNAME,
|
'group_name': image.gname,
|
||||||
'group_id': image.GID,
|
'group_id': image.gid,
|
||||||
}
|
}
|
||||||
|
|
||||||
return info
|
return info
|
||||||
|
|
||||||
|
|
||||||
def wait_for_state(module, client, image_id, wait_timeout, state_predicate):
|
def wait_for_state(module, image, wait_timeout, state_predicate):
|
||||||
import time
|
import time
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
|
|
||||||
while (time.time() - start_time) < wait_timeout:
|
while (time.time() - start_time) < wait_timeout:
|
||||||
image = client.image.info(image_id)
|
image.info()
|
||||||
state = image.STATE
|
state = image.state
|
||||||
|
|
||||||
if state_predicate(state):
|
if state_predicate(state):
|
||||||
return image
|
return image
|
||||||
@@ -238,19 +241,19 @@ def wait_for_state(module, client, image_id, wait_timeout, state_predicate):
|
|||||||
module.fail_json(msg="Wait timeout has expired!")
|
module.fail_json(msg="Wait timeout has expired!")
|
||||||
|
|
||||||
|
|
||||||
def wait_for_ready(module, client, image_id, wait_timeout=60):
|
def wait_for_ready(module, image, wait_timeout=60):
|
||||||
return wait_for_state(module, client, image_id, wait_timeout, lambda state: (state in [IMAGE_STATES.index('READY')]))
|
return wait_for_state(module, image, wait_timeout, lambda state: (state in [IMAGE_STATES.index('READY')]))
|
||||||
|
|
||||||
|
|
||||||
def wait_for_delete(module, client, image_id, wait_timeout=60):
|
def wait_for_delete(module, image, wait_timeout=60):
|
||||||
return wait_for_state(module, client, image_id, wait_timeout, lambda state: (state in [IMAGE_STATES.index('DELETE')]))
|
return wait_for_state(module, image, wait_timeout, lambda state: (state in [IMAGE_STATES.index('DELETE')]))
|
||||||
|
|
||||||
|
|
||||||
def enable_image(module, client, image, enable):
|
def enable_image(module, client, image, enable):
|
||||||
image = client.image.info(image.ID)
|
image.info()
|
||||||
changed = False
|
changed = False
|
||||||
|
|
||||||
state = image.STATE
|
state = image.state
|
||||||
|
|
||||||
if state not in [IMAGE_STATES.index('READY'), IMAGE_STATES.index('DISABLED'), IMAGE_STATES.index('ERROR')]:
|
if state not in [IMAGE_STATES.index('READY'), IMAGE_STATES.index('DISABLED'), IMAGE_STATES.index('ERROR')]:
|
||||||
if enable:
|
if enable:
|
||||||
@@ -263,7 +266,7 @@ def enable_image(module, client, image, enable):
|
|||||||
changed = True
|
changed = True
|
||||||
|
|
||||||
if changed and not module.check_mode:
|
if changed and not module.check_mode:
|
||||||
client.image.enable(image.ID, enable)
|
client.call('image.enable', image.id, enable)
|
||||||
|
|
||||||
result = get_image_info(image)
|
result = get_image_info(image)
|
||||||
result['changed'] = changed
|
result['changed'] = changed
|
||||||
@@ -273,7 +276,7 @@ def enable_image(module, client, image, enable):
|
|||||||
|
|
||||||
def clone_image(module, client, image, new_name):
|
def clone_image(module, client, image, new_name):
|
||||||
if new_name is None:
|
if new_name is None:
|
||||||
new_name = "Copy of " + image.NAME
|
new_name = "Copy of " + image.name
|
||||||
|
|
||||||
tmp_image = get_image_by_name(module, client, new_name)
|
tmp_image = get_image_by_name(module, client, new_name)
|
||||||
if tmp_image:
|
if tmp_image:
|
||||||
@@ -281,13 +284,13 @@ def clone_image(module, client, image, new_name):
|
|||||||
result['changed'] = False
|
result['changed'] = False
|
||||||
return result
|
return result
|
||||||
|
|
||||||
if image.STATE == IMAGE_STATES.index('DISABLED'):
|
if image.state == IMAGE_STATES.index('DISABLED'):
|
||||||
module.fail_json(msg="Cannot clone DISABLED image")
|
module.fail_json(msg="Cannot clone DISABLED image")
|
||||||
|
|
||||||
if not module.check_mode:
|
if not module.check_mode:
|
||||||
new_id = client.image.clone(image.ID, new_name)
|
new_id = client.call('image.clone', image.id, new_name)
|
||||||
wait_for_ready(module, client, new_id)
|
image = get_image_by_id(module, client, new_id)
|
||||||
image = client.image.info(new_id)
|
wait_for_ready(module, image)
|
||||||
|
|
||||||
result = get_image_info(image)
|
result = get_image_info(image)
|
||||||
result['changed'] = True
|
result['changed'] = True
|
||||||
@@ -299,7 +302,7 @@ def rename_image(module, client, image, new_name):
|
|||||||
if new_name is None:
|
if new_name is None:
|
||||||
module.fail_json(msg="'new_name' option has to be specified when the state is 'renamed'")
|
module.fail_json(msg="'new_name' option has to be specified when the state is 'renamed'")
|
||||||
|
|
||||||
if new_name == image.NAME:
|
if new_name == image.name:
|
||||||
result = get_image_info(image)
|
result = get_image_info(image)
|
||||||
result['changed'] = False
|
result['changed'] = False
|
||||||
return result
|
return result
|
||||||
@@ -309,7 +312,7 @@ def rename_image(module, client, image, new_name):
|
|||||||
module.fail_json(msg="Name '" + new_name + "' is already taken by IMAGE with id=" + str(tmp_image.id))
|
module.fail_json(msg="Name '" + new_name + "' is already taken by IMAGE with id=" + str(tmp_image.id))
|
||||||
|
|
||||||
if not module.check_mode:
|
if not module.check_mode:
|
||||||
client.image.rename(image.ID, new_name)
|
client.call('image.rename', image.id, new_name)
|
||||||
|
|
||||||
result = get_image_info(image)
|
result = get_image_info(image)
|
||||||
result['changed'] = True
|
result['changed'] = True
|
||||||
@@ -321,12 +324,12 @@ def delete_image(module, client, image):
|
|||||||
if not image:
|
if not image:
|
||||||
return {'changed': False}
|
return {'changed': False}
|
||||||
|
|
||||||
if image.RUNNING_VMS > 0:
|
if image.running_vms > 0:
|
||||||
module.fail_json(msg="Cannot delete image. There are " + str(image.RUNNING_VMS) + " VMs using it.")
|
module.fail_json(msg="Cannot delete image. There are " + str(image.running_vms) + " VMs using it.")
|
||||||
|
|
||||||
if not module.check_mode:
|
if not module.check_mode:
|
||||||
client.image.delete(image.ID)
|
client.call('image.delete', image.id)
|
||||||
wait_for_delete(module, client, image.ID)
|
wait_for_delete(module, image)
|
||||||
|
|
||||||
return {'changed': True}
|
return {'changed': True}
|
||||||
|
|
||||||
@@ -375,8 +378,8 @@ def main():
|
|||||||
mutually_exclusive=[['id', 'name']],
|
mutually_exclusive=[['id', 'name']],
|
||||||
supports_check_mode=True)
|
supports_check_mode=True)
|
||||||
|
|
||||||
if not HAS_PYONE:
|
if not HAS_OCA:
|
||||||
module.fail_json(msg='This module requires pyone to work!')
|
module.fail_json(msg='This module requires python-oca to work!')
|
||||||
|
|
||||||
auth = get_connection_info(module)
|
auth = get_connection_info(module)
|
||||||
params = module.params
|
params = module.params
|
||||||
@@ -385,7 +388,7 @@ def main():
|
|||||||
state = params.get('state')
|
state = params.get('state')
|
||||||
enabled = params.get('enabled')
|
enabled = params.get('enabled')
|
||||||
new_name = params.get('new_name')
|
new_name = params.get('new_name')
|
||||||
client = pyone.OneServer(auth.url, session=auth.username + ':' + auth.password)
|
client = oca.Client(auth.username + ':' + auth.password, auth.url)
|
||||||
|
|
||||||
result = {}
|
result = {}
|
||||||
|
|
||||||
|
|||||||
1
plugins/modules/cloud/opennebula/one_image_facts.py
Symbolic link
1
plugins/modules/cloud/opennebula/one_image_facts.py
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
one_image_info.py
|
||||||
@@ -261,6 +261,9 @@ def main():
|
|||||||
module = AnsibleModule(argument_spec=fields,
|
module = AnsibleModule(argument_spec=fields,
|
||||||
mutually_exclusive=[['ids', 'name']],
|
mutually_exclusive=[['ids', 'name']],
|
||||||
supports_check_mode=True)
|
supports_check_mode=True)
|
||||||
|
if module._name in ('one_image_facts', 'community.general.one_image_facts'):
|
||||||
|
module.deprecate("The 'one_image_facts' module has been renamed to 'one_image_info'",
|
||||||
|
version='3.0.0', collection_name='community.general') # was Ansible 2.13
|
||||||
|
|
||||||
if not HAS_PYONE:
|
if not HAS_PYONE:
|
||||||
module.fail_json(msg='This module requires pyone to work!')
|
module.fail_json(msg='This module requires pyone to work!')
|
||||||
|
|||||||
@@ -752,20 +752,11 @@ def get_vm_info(client, vm):
|
|||||||
if 'NIC' in vm.TEMPLATE:
|
if 'NIC' in vm.TEMPLATE:
|
||||||
if isinstance(vm.TEMPLATE['NIC'], list):
|
if isinstance(vm.TEMPLATE['NIC'], list):
|
||||||
for nic in vm.TEMPLATE['NIC']:
|
for nic in vm.TEMPLATE['NIC']:
|
||||||
networks_info.append({
|
networks_info.append({'ip': nic['IP'], 'mac': nic['MAC'], 'name': nic['NETWORK'], 'security_groups': nic['SECURITY_GROUPS']})
|
||||||
'ip': nic.get('IP', ''),
|
|
||||||
'mac': nic.get('MAC', ''),
|
|
||||||
'name': nic.get('NETWORK', ''),
|
|
||||||
'security_groups': nic.get('SECURITY_GROUPS', '')
|
|
||||||
})
|
|
||||||
else:
|
else:
|
||||||
networks_info.append({
|
networks_info.append(
|
||||||
'ip': vm.TEMPLATE['NIC'].get('IP', ''),
|
{'ip': vm.TEMPLATE['NIC']['IP'], 'mac': vm.TEMPLATE['NIC']['MAC'],
|
||||||
'mac': vm.TEMPLATE['NIC'].get('MAC', ''),
|
'name': vm.TEMPLATE['NIC']['NETWORK'], 'security_groups': vm.TEMPLATE['NIC']['SECURITY_GROUPS']})
|
||||||
'name': vm.TEMPLATE['NIC'].get('NETWORK', ''),
|
|
||||||
'security_groups':
|
|
||||||
vm.TEMPLATE['NIC'].get('SECURITY_GROUPS', '')
|
|
||||||
})
|
|
||||||
import time
|
import time
|
||||||
|
|
||||||
current_time = time.localtime()
|
current_time = time.localtime()
|
||||||
|
|||||||
@@ -162,6 +162,7 @@ def waitForTaskDone(client, name, taskId, timeout):
|
|||||||
currentTimeout -= 5
|
currentTimeout -= 5
|
||||||
if currentTimeout < 0:
|
if currentTimeout < 0:
|
||||||
return False
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|||||||
196
plugins/modules/cloud/ovirt/ovirt_affinity_label_facts.py
Normal file
196
plugins/modules/cloud/ovirt/ovirt_affinity_label_facts.py
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# This file is part of Ansible
|
||||||
|
#
|
||||||
|
# Ansible is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Ansible is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: ovirt_affinity_label_facts
|
||||||
|
short_description: Retrieve information about one or more oVirt/RHV affinity labels
|
||||||
|
author: "Ondra Machacek (@machacekondra)"
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.13
|
||||||
|
why: When migrating to collection we decided to use only _info modules.
|
||||||
|
alternative: Use M(ovirt.ovirt.ovirt_affinity_label_info) instead.
|
||||||
|
description:
|
||||||
|
- "Retrieve information about one or more oVirt/RHV affinity labels."
|
||||||
|
notes:
|
||||||
|
- "This module returns a variable C(ovirt_affinity_labels), which
|
||||||
|
contains a list of affinity labels. You need to register the result with
|
||||||
|
the I(register) keyword to use it."
|
||||||
|
options:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- "Name of the affinity labels which should be listed."
|
||||||
|
vm:
|
||||||
|
description:
|
||||||
|
- "Name of the VM, which affinity labels should be listed."
|
||||||
|
host:
|
||||||
|
description:
|
||||||
|
- "Name of the host, which affinity labels should be listed."
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.general.ovirt_facts
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Examples don't contain auth parameter for simplicity,
|
||||||
|
# look at ovirt_auth module to see how to reuse authentication:
|
||||||
|
|
||||||
|
- name: Gather information about all affinity labels, which names start with label
|
||||||
|
ovirt_affinity_label_info:
|
||||||
|
name: label*
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Print gathered information
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "{{ result.ovirt_affinity_labels }}"
|
||||||
|
|
||||||
|
- name: >
|
||||||
|
Gather information about all affinity labels, which are assigned to VMs
|
||||||
|
which names start with postgres
|
||||||
|
ovirt_affinity_label_info:
|
||||||
|
vm: postgres*
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Print gathered information
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "{{ result.ovirt_affinity_labels }}"
|
||||||
|
|
||||||
|
- name: >
|
||||||
|
Gather information about all affinity labels, which are assigned to hosts
|
||||||
|
which names start with west
|
||||||
|
ovirt_affinity_label_info:
|
||||||
|
host: west*
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Print gathered information
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "{{ result.ovirt_affinity_labels }}"
|
||||||
|
|
||||||
|
- name: >
|
||||||
|
Gather information about all affinity labels, which are assigned to hosts
|
||||||
|
which names start with west or VMs which names start with postgres
|
||||||
|
ovirt_affinity_label_info:
|
||||||
|
host: west*
|
||||||
|
vm: postgres*
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Print gathered information
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "{{ result.ovirt_affinity_labels }}"
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
ovirt_affinity_labels:
|
||||||
|
description: "List of dictionaries describing the affinity labels. Affinity labels attributes are mapped to dictionary keys,
|
||||||
|
all affinity labels attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/affinity_label."
|
||||||
|
returned: On success.
|
||||||
|
type: list
|
||||||
|
'''
|
||||||
|
|
||||||
|
import fnmatch
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from ansible.module_utils.common.removed import removed_module
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.community.general.plugins.module_utils._ovirt import (
|
||||||
|
check_sdk,
|
||||||
|
create_connection,
|
||||||
|
get_dict_of_struct,
|
||||||
|
ovirt_info_full_argument_spec,
|
||||||
|
search_by_name,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = ovirt_info_full_argument_spec(
|
||||||
|
name=dict(default=None),
|
||||||
|
host=dict(default=None),
|
||||||
|
vm=dict(default=None),
|
||||||
|
)
|
||||||
|
module = AnsibleModule(argument_spec)
|
||||||
|
is_old_facts = module._name in ('ovirt_affinity_label_facts', 'community.general.ovirt_affinity_label_facts')
|
||||||
|
if is_old_facts:
|
||||||
|
module.deprecate("The 'ovirt_affinity_label_facts' module has been renamed to 'ovirt_affinity_label_info', "
|
||||||
|
"and the renamed one no longer returns ansible_facts",
|
||||||
|
version='3.0.0', collection_name='community.general') # was Ansible 2.13
|
||||||
|
|
||||||
|
check_sdk(module)
|
||||||
|
|
||||||
|
try:
|
||||||
|
auth = module.params.pop('auth')
|
||||||
|
connection = create_connection(auth)
|
||||||
|
affinity_labels_service = connection.system_service().affinity_labels_service()
|
||||||
|
labels = []
|
||||||
|
all_labels = affinity_labels_service.list()
|
||||||
|
if module.params['name']:
|
||||||
|
labels.extend([
|
||||||
|
l for l in all_labels
|
||||||
|
if fnmatch.fnmatch(l.name, module.params['name'])
|
||||||
|
])
|
||||||
|
if module.params['host']:
|
||||||
|
hosts_service = connection.system_service().hosts_service()
|
||||||
|
if search_by_name(hosts_service, module.params['host']) is None:
|
||||||
|
raise Exception("Host '%s' was not found." % module.params['host'])
|
||||||
|
labels.extend([
|
||||||
|
label
|
||||||
|
for label in all_labels
|
||||||
|
for host in connection.follow_link(label.hosts)
|
||||||
|
if fnmatch.fnmatch(hosts_service.service(host.id).get().name, module.params['host'])
|
||||||
|
])
|
||||||
|
if module.params['vm']:
|
||||||
|
vms_service = connection.system_service().vms_service()
|
||||||
|
if search_by_name(vms_service, module.params['vm']) is None:
|
||||||
|
raise Exception("Vm '%s' was not found." % module.params['vm'])
|
||||||
|
labels.extend([
|
||||||
|
label
|
||||||
|
for label in all_labels
|
||||||
|
for vm in connection.follow_link(label.vms)
|
||||||
|
if fnmatch.fnmatch(vms_service.service(vm.id).get().name, module.params['vm'])
|
||||||
|
])
|
||||||
|
|
||||||
|
if not (module.params['vm'] or module.params['host'] or module.params['name']):
|
||||||
|
labels = all_labels
|
||||||
|
|
||||||
|
result = dict(
|
||||||
|
ovirt_affinity_labels=[
|
||||||
|
get_dict_of_struct(
|
||||||
|
struct=l,
|
||||||
|
connection=connection,
|
||||||
|
fetch_nested=module.params.get('fetch_nested'),
|
||||||
|
attributes=module.params.get('nested_attributes'),
|
||||||
|
) for l in labels
|
||||||
|
],
|
||||||
|
)
|
||||||
|
if is_old_facts:
|
||||||
|
module.exit_json(changed=False, ansible_facts=result)
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False, **result)
|
||||||
|
except Exception as e:
|
||||||
|
module.fail_json(msg=str(e), exception=traceback.format_exc())
|
||||||
|
finally:
|
||||||
|
connection.close(logout=auth.get('token') is None)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
98
plugins/modules/cloud/ovirt/ovirt_api_facts.py
Normal file
98
plugins/modules/cloud/ovirt/ovirt_api_facts.py
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (c) 2017 Ansible Project
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: ovirt_api_facts
|
||||||
|
short_description: Retrieve information about the oVirt/RHV API
|
||||||
|
author: "Ondra Machacek (@machacekondra)"
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.13
|
||||||
|
why: When migrating to collection we decided to use only _info modules.
|
||||||
|
alternative: Use M(ovirt.ovirt.ovirt_api_info) instead.
|
||||||
|
description:
|
||||||
|
- "Retrieve information about the oVirt/RHV API."
|
||||||
|
notes:
|
||||||
|
- "This module returns a variable C(ovirt_api),
|
||||||
|
which contains a information about oVirt/RHV API. You need to register the result with
|
||||||
|
the I(register) keyword to use it."
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.general.ovirt_facts
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Examples don't contain auth parameter for simplicity,
|
||||||
|
# look at ovirt_auth module to see how to reuse authentication:
|
||||||
|
|
||||||
|
- name: Gather information oVirt API
|
||||||
|
ovirt_api_info:
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Print gathered information
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "{{ result.ovirt_api }}"
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
ovirt_api:
|
||||||
|
description: "Dictionary describing the oVirt API information.
|
||||||
|
Api attributes are mapped to dictionary keys,
|
||||||
|
all API attributes can be found at following
|
||||||
|
url: https://ovirt.example.com/ovirt-engine/api/model#types/api."
|
||||||
|
returned: On success.
|
||||||
|
type: dict
|
||||||
|
'''
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from ansible.module_utils.common.removed import removed_module
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.community.general.plugins.module_utils._ovirt import (
|
||||||
|
check_sdk,
|
||||||
|
create_connection,
|
||||||
|
get_dict_of_struct,
|
||||||
|
ovirt_info_full_argument_spec,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = ovirt_info_full_argument_spec()
|
||||||
|
module = AnsibleModule(argument_spec)
|
||||||
|
is_old_facts = module._name in ('ovirt_api_facts', 'community.general.ovirt_api_facts')
|
||||||
|
if is_old_facts:
|
||||||
|
module.deprecate("The 'ovirt_api_facts' module has been renamed to 'ovirt_api_info', "
|
||||||
|
"and the renamed one no longer returns ansible_facts",
|
||||||
|
version='3.0.0', collection_name='community.general') # was Ansible 2.13
|
||||||
|
check_sdk(module)
|
||||||
|
|
||||||
|
try:
|
||||||
|
auth = module.params.pop('auth')
|
||||||
|
connection = create_connection(auth)
|
||||||
|
api = connection.system_service().get()
|
||||||
|
result = dict(
|
||||||
|
ovirt_api=get_dict_of_struct(
|
||||||
|
struct=api,
|
||||||
|
connection=connection,
|
||||||
|
fetch_nested=module.params.get('fetch_nested'),
|
||||||
|
attributes=module.params.get('nested_attributes'),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if is_old_facts:
|
||||||
|
module.exit_json(changed=False, ansible_facts=result)
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False, **result)
|
||||||
|
except Exception as e:
|
||||||
|
module.fail_json(msg=str(e), exception=traceback.format_exc())
|
||||||
|
finally:
|
||||||
|
connection.close(logout=auth.get('token') is None)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
125
plugins/modules/cloud/ovirt/ovirt_cluster_facts.py
Normal file
125
plugins/modules/cloud/ovirt/ovirt_cluster_facts.py
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# This file is part of Ansible
|
||||||
|
#
|
||||||
|
# Ansible is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Ansible is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: ovirt_cluster_facts
|
||||||
|
short_description: Retrieve information about one or more oVirt/RHV clusters
|
||||||
|
author: "Ondra Machacek (@machacekondra)"
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.13
|
||||||
|
why: When migrating to collection we decided to use only _info modules.
|
||||||
|
alternative: Use M(ovirt.ovirt.ovirt_cluster_info) instead.
|
||||||
|
description:
|
||||||
|
- "Retrieve information about one or more oVirt/RHV clusters."
|
||||||
|
notes:
|
||||||
|
- "This module returns a variable C(ovirt_clusters), which
|
||||||
|
contains a list of clusters. You need to register the result with
|
||||||
|
the I(register) keyword to use it."
|
||||||
|
options:
|
||||||
|
pattern:
|
||||||
|
description:
|
||||||
|
- "Search term which is accepted by oVirt/RHV search backend."
|
||||||
|
- "For example to search cluster X from datacenter Y use following pattern:
|
||||||
|
name=X and datacenter=Y"
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.general.ovirt_facts
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Examples don't contain auth parameter for simplicity,
|
||||||
|
# look at ovirt_auth module to see how to reuse authentication:
|
||||||
|
|
||||||
|
- name: Gather information about all clusters which names start with production
|
||||||
|
ovirt_cluster_info:
|
||||||
|
pattern:
|
||||||
|
name: 'production*'
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Print gathered information
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "{{ result.ovirt_clusters }}"
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
ovirt_clusters:
|
||||||
|
description: "List of dictionaries describing the clusters. Cluster attributes are mapped to dictionary keys,
|
||||||
|
all clusters attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/cluster."
|
||||||
|
returned: On success.
|
||||||
|
type: list
|
||||||
|
'''
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from ansible.module_utils.common.removed import removed_module
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.community.general.plugins.module_utils._ovirt import (
|
||||||
|
check_sdk,
|
||||||
|
create_connection,
|
||||||
|
get_dict_of_struct,
|
||||||
|
ovirt_info_full_argument_spec,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = ovirt_info_full_argument_spec(
|
||||||
|
pattern=dict(default='', required=False),
|
||||||
|
)
|
||||||
|
module = AnsibleModule(argument_spec)
|
||||||
|
is_old_facts = module._name in ('ovirt_cluster_facts', 'community.general.ovirt_cluster_facts')
|
||||||
|
if is_old_facts:
|
||||||
|
module.deprecate("The 'ovirt_cluster_facts' module has been renamed to 'ovirt_cluster_info', "
|
||||||
|
"and the renamed one no longer returns ansible_facts",
|
||||||
|
version='3.0.0', collection_name='community.general') # was Ansible 2.13
|
||||||
|
|
||||||
|
check_sdk(module)
|
||||||
|
|
||||||
|
try:
|
||||||
|
auth = module.params.pop('auth')
|
||||||
|
connection = create_connection(auth)
|
||||||
|
clusters_service = connection.system_service().clusters_service()
|
||||||
|
clusters = clusters_service.list(search=module.params['pattern'])
|
||||||
|
result = dict(
|
||||||
|
ovirt_clusters=[
|
||||||
|
get_dict_of_struct(
|
||||||
|
struct=c,
|
||||||
|
connection=connection,
|
||||||
|
fetch_nested=module.params.get('fetch_nested'),
|
||||||
|
attributes=module.params.get('nested_attributes'),
|
||||||
|
) for c in clusters
|
||||||
|
],
|
||||||
|
)
|
||||||
|
if is_old_facts:
|
||||||
|
module.exit_json(changed=False, ansible_facts=result)
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False, **result)
|
||||||
|
except Exception as e:
|
||||||
|
module.fail_json(msg=str(e), exception=traceback.format_exc())
|
||||||
|
finally:
|
||||||
|
connection.close(logout=auth.get('token') is None)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
108
plugins/modules/cloud/ovirt/ovirt_datacenter_facts.py
Normal file
108
plugins/modules/cloud/ovirt/ovirt_datacenter_facts.py
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016 Red Hat, Inc.
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: ovirt_datacenter_facts
|
||||||
|
short_description: Retrieve information about one or more oVirt/RHV datacenters
|
||||||
|
author: "Ondra Machacek (@machacekondra)"
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.13
|
||||||
|
why: When migrating to collection we decided to use only _info modules.
|
||||||
|
alternative: Use M(ovirt.ovirt.ovirt_datacenter_info) instead.
|
||||||
|
description:
|
||||||
|
- "Retrieve information about one or more oVirt/RHV datacenters."
|
||||||
|
notes:
|
||||||
|
- "This module returns a variable C(ovirt_datacenters), which
|
||||||
|
contains a list of datacenters. You need to register the result with
|
||||||
|
the I(register) keyword to use it."
|
||||||
|
options:
|
||||||
|
pattern:
|
||||||
|
description:
|
||||||
|
- "Search term which is accepted by oVirt/RHV search backend."
|
||||||
|
- "For example to search datacenter I(X) use following pattern: I(name=X)"
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.general.ovirt_facts
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Examples don't contain auth parameter for simplicity,
|
||||||
|
# look at ovirt_auth module to see how to reuse authentication:
|
||||||
|
|
||||||
|
- name: Gather information about all data centers which names start with production
|
||||||
|
ovirt_datacenter_info:
|
||||||
|
pattern: name=production*
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Print gathered information
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "{{ result.ovirt_datacenters }}"
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
ovirt_datacenters:
|
||||||
|
description: "List of dictionaries describing the datacenters. Datacenter attributes are mapped to dictionary keys,
|
||||||
|
all datacenters attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/data_center."
|
||||||
|
returned: On success.
|
||||||
|
type: list
|
||||||
|
'''
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from ansible.module_utils.common.removed import removed_module
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.community.general.plugins.module_utils._ovirt import (
|
||||||
|
check_sdk,
|
||||||
|
create_connection,
|
||||||
|
get_dict_of_struct,
|
||||||
|
ovirt_info_full_argument_spec,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = ovirt_info_full_argument_spec(
|
||||||
|
pattern=dict(default='', required=False),
|
||||||
|
)
|
||||||
|
module = AnsibleModule(argument_spec)
|
||||||
|
is_old_facts = module._name in ('ovirt_datacenter_facts', 'community.general.ovirt_datacenter_facts')
|
||||||
|
if is_old_facts:
|
||||||
|
module.deprecate("The 'ovirt_datacenter_facts' module has been renamed to 'ovirt_datacenter_info', "
|
||||||
|
"and the renamed one no longer returns ansible_facts",
|
||||||
|
version='3.0.0', collection_name='community.general') # was Ansible 2.13
|
||||||
|
|
||||||
|
check_sdk(module)
|
||||||
|
|
||||||
|
try:
|
||||||
|
auth = module.params.pop('auth')
|
||||||
|
connection = create_connection(auth)
|
||||||
|
datacenters_service = connection.system_service().data_centers_service()
|
||||||
|
datacenters = datacenters_service.list(search=module.params['pattern'])
|
||||||
|
result = dict(
|
||||||
|
ovirt_datacenters=[
|
||||||
|
get_dict_of_struct(
|
||||||
|
struct=d,
|
||||||
|
connection=connection,
|
||||||
|
fetch_nested=module.params.get('fetch_nested'),
|
||||||
|
attributes=module.params.get('nested_attributes'),
|
||||||
|
) for d in datacenters
|
||||||
|
],
|
||||||
|
)
|
||||||
|
if is_old_facts:
|
||||||
|
module.exit_json(changed=False, ansible_facts=result)
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False, **result)
|
||||||
|
except Exception as e:
|
||||||
|
module.fail_json(msg=str(e), exception=traceback.format_exc())
|
||||||
|
finally:
|
||||||
|
connection.close(logout=auth.get('token') is None)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
125
plugins/modules/cloud/ovirt/ovirt_disk_facts.py
Normal file
125
plugins/modules/cloud/ovirt/ovirt_disk_facts.py
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2017 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# This file is part of Ansible
|
||||||
|
#
|
||||||
|
# Ansible is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Ansible is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: ovirt_disk_facts
|
||||||
|
short_description: Retrieve information about one or more oVirt/RHV disks
|
||||||
|
author: "Katerina Koukiou (@KKoukiou)"
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.13
|
||||||
|
why: When migrating to collection we decided to use only _info modules.
|
||||||
|
alternative: Use M(ovirt.ovirt.ovirt_disk_info) instead
|
||||||
|
description:
|
||||||
|
- "Retrieve information about one or more oVirt/RHV disks."
|
||||||
|
notes:
|
||||||
|
- "This module returns a variable C(ovirt_disks), which
|
||||||
|
contains a list of disks. You need to register the result with
|
||||||
|
the I(register) keyword to use it."
|
||||||
|
options:
|
||||||
|
pattern:
|
||||||
|
description:
|
||||||
|
- "Search term which is accepted by oVirt/RHV search backend."
|
||||||
|
- "For example to search Disk X from storage Y use following pattern:
|
||||||
|
name=X and storage.name=Y"
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.general.ovirt_facts
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Examples don't contain auth parameter for simplicity,
|
||||||
|
# look at ovirt_auth module to see how to reuse authentication:
|
||||||
|
|
||||||
|
- name: Gather information about all Disks which names start with centos
|
||||||
|
ovirt_disk_info:
|
||||||
|
pattern: name=centos*
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Print gathered information
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "{{ result.ovirt_disks }}"
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
ovirt_disks:
|
||||||
|
description: "List of dictionaries describing the Disks. Disk attributes are mapped to dictionary keys,
|
||||||
|
all Disks attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/disk."
|
||||||
|
returned: On success.
|
||||||
|
type: list
|
||||||
|
'''
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from ansible.module_utils.common.removed import removed_module
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.community.general.plugins.module_utils._ovirt import (
|
||||||
|
check_sdk,
|
||||||
|
create_connection,
|
||||||
|
get_dict_of_struct,
|
||||||
|
ovirt_info_full_argument_spec,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = ovirt_info_full_argument_spec(
|
||||||
|
pattern=dict(default='', required=False),
|
||||||
|
)
|
||||||
|
module = AnsibleModule(argument_spec)
|
||||||
|
is_old_facts = module._name in ('ovirt_disk_facts', 'community.general.ovirt_disk_facts')
|
||||||
|
if is_old_facts:
|
||||||
|
module.deprecate("The 'ovirt_disk_facts' module has been renamed to 'ovirt_disk_info', "
|
||||||
|
"and the renamed one no longer returns ansible_facts",
|
||||||
|
version='3.0.0', collection_name='community.general') # was Ansible 2.13
|
||||||
|
check_sdk(module)
|
||||||
|
|
||||||
|
try:
|
||||||
|
auth = module.params.pop('auth')
|
||||||
|
connection = create_connection(auth)
|
||||||
|
disks_service = connection.system_service().disks_service()
|
||||||
|
disks = disks_service.list(
|
||||||
|
search=module.params['pattern'],
|
||||||
|
)
|
||||||
|
result = dict(
|
||||||
|
ovirt_disks=[
|
||||||
|
get_dict_of_struct(
|
||||||
|
struct=c,
|
||||||
|
connection=connection,
|
||||||
|
fetch_nested=module.params.get('fetch_nested'),
|
||||||
|
attributes=module.params.get('nested_attributes'),
|
||||||
|
) for c in disks
|
||||||
|
],
|
||||||
|
)
|
||||||
|
if is_old_facts:
|
||||||
|
module.exit_json(changed=False, ansible_facts=result)
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False, **result)
|
||||||
|
except Exception as e:
|
||||||
|
module.fail_json(msg=str(e), exception=traceback.format_exc())
|
||||||
|
finally:
|
||||||
|
connection.close(logout=auth.get('token') is None)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
170
plugins/modules/cloud/ovirt/ovirt_event_facts.py
Normal file
170
plugins/modules/cloud/ovirt/ovirt_event_facts.py
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright: (c) 2019, Ansible Project
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: ovirt_event_facts
|
||||||
|
short_description: This module can be used to retrieve information about one or more oVirt/RHV events
|
||||||
|
author: "Chris Keller (@nasx)"
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.13
|
||||||
|
why: When migrating to collection we decided to use only _info modules.
|
||||||
|
alternative: Use M(ovirt.ovirt.ovirt_event_info) instead.
|
||||||
|
description:
|
||||||
|
- "Retrieve information about one or more oVirt/RHV events."
|
||||||
|
options:
|
||||||
|
case_sensitive:
|
||||||
|
description:
|
||||||
|
- "Indicates if the search performed using the search parameter should be performed taking case
|
||||||
|
into account. The default value is true, which means that case is taken into account. If you
|
||||||
|
want to search ignoring case set it to false."
|
||||||
|
required: false
|
||||||
|
default: true
|
||||||
|
type: bool
|
||||||
|
|
||||||
|
from_:
|
||||||
|
description:
|
||||||
|
- "Indicates the event index after which events should be returned. The indexes of events are
|
||||||
|
strictly increasing, so when this parameter is used only the events with greater indexes
|
||||||
|
will be returned."
|
||||||
|
required: false
|
||||||
|
type: int
|
||||||
|
|
||||||
|
max:
|
||||||
|
description:
|
||||||
|
- "Sets the maximum number of events to return. If not specified all the events are returned."
|
||||||
|
required: false
|
||||||
|
type: int
|
||||||
|
|
||||||
|
search:
|
||||||
|
description:
|
||||||
|
- "Search term which is accepted by the oVirt/RHV API."
|
||||||
|
- "For example to search for events of severity alert use the following pattern: severity=alert"
|
||||||
|
required: false
|
||||||
|
type: str
|
||||||
|
|
||||||
|
headers:
|
||||||
|
description:
|
||||||
|
- "Additional HTTP headers."
|
||||||
|
required: false
|
||||||
|
type: str
|
||||||
|
|
||||||
|
query:
|
||||||
|
description:
|
||||||
|
- "Additional URL query parameters."
|
||||||
|
required: false
|
||||||
|
type: str
|
||||||
|
|
||||||
|
wait:
|
||||||
|
description:
|
||||||
|
- "If True wait for the response."
|
||||||
|
required: false
|
||||||
|
default: true
|
||||||
|
type: bool
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.general.ovirt_facts
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Examples don't contain the auth parameter for simplicity,
|
||||||
|
# look at the ovirt_auth module to see how to reuse authentication.
|
||||||
|
|
||||||
|
- name: Return all events
|
||||||
|
ovirt_event_info:
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Return the last 10 events
|
||||||
|
ovirt_event_info:
|
||||||
|
max: 10
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Return all events of type alert
|
||||||
|
ovirt_event_info:
|
||||||
|
search: "severity=alert"
|
||||||
|
register: result
|
||||||
|
- ansible.builtin.debug:
|
||||||
|
msg: "{{ result.ovirt_events }}"
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
ovirt_events:
|
||||||
|
description: "List of dictionaries describing the events. Event attributes are mapped to dictionary keys.
|
||||||
|
All event attributes can be found at the following url:
|
||||||
|
http://ovirt.github.io/ovirt-engine-api-model/master/#types/event"
|
||||||
|
returned: On success."
|
||||||
|
type: list
|
||||||
|
'''
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from ansible.module_utils.common.removed import removed_module
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.community.general.plugins.module_utils._ovirt import (
|
||||||
|
check_sdk,
|
||||||
|
create_connection,
|
||||||
|
get_dict_of_struct,
|
||||||
|
ovirt_info_full_argument_spec,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = ovirt_info_full_argument_spec(
|
||||||
|
case_sensitive=dict(default=True, type='bool', required=False),
|
||||||
|
from_=dict(default=None, type='int', required=False),
|
||||||
|
max=dict(default=None, type='int', required=False),
|
||||||
|
search=dict(default='', required=False),
|
||||||
|
headers=dict(default='', required=False),
|
||||||
|
query=dict(default='', required=False),
|
||||||
|
wait=dict(default=True, type='bool', required=False)
|
||||||
|
)
|
||||||
|
module = AnsibleModule(argument_spec)
|
||||||
|
is_old_facts = module._name in ('ovirt_event_facts', 'community.general.ovirt_event_facts')
|
||||||
|
if is_old_facts:
|
||||||
|
module.deprecate("The 'ovirt_event_facts' module has been renamed to 'ovirt_event_info', "
|
||||||
|
"and the renamed one no longer returns ansible_facts",
|
||||||
|
version='3.0.0', collection_name='community.general') # was Ansible 2.13
|
||||||
|
|
||||||
|
check_sdk(module)
|
||||||
|
|
||||||
|
try:
|
||||||
|
auth = module.params.pop('auth')
|
||||||
|
connection = create_connection(auth)
|
||||||
|
events_service = connection.system_service().events_service()
|
||||||
|
events = events_service.list(
|
||||||
|
case_sensitive=module.params['case_sensitive'],
|
||||||
|
from_=module.params['from_'],
|
||||||
|
max=module.params['max'],
|
||||||
|
search=module.params['search'],
|
||||||
|
headers=module.params['headers'],
|
||||||
|
query=module.params['query'],
|
||||||
|
wait=module.params['wait']
|
||||||
|
)
|
||||||
|
|
||||||
|
result = dict(
|
||||||
|
ovirt_events=[
|
||||||
|
get_dict_of_struct(
|
||||||
|
struct=c,
|
||||||
|
connection=connection,
|
||||||
|
fetch_nested=module.params.get('fetch_nested'),
|
||||||
|
attributes=module.params.get('nested_attributes'),
|
||||||
|
) for c in events
|
||||||
|
],
|
||||||
|
)
|
||||||
|
if is_old_facts:
|
||||||
|
module.exit_json(changed=False, ansible_facts=result)
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False, **result)
|
||||||
|
except Exception as e:
|
||||||
|
module.fail_json(msg=str(e), exception=traceback.format_exc())
|
||||||
|
finally:
|
||||||
|
connection.close(logout=auth.get('token') is None)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
165
plugins/modules/cloud/ovirt/ovirt_external_provider_facts.py
Normal file
165
plugins/modules/cloud/ovirt/ovirt_external_provider_facts.py
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# This file is part of Ansible
|
||||||
|
#
|
||||||
|
# Ansible is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Ansible is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: ovirt_external_provider_facts
|
||||||
|
short_description: Retrieve information about one or more oVirt/RHV external providers
|
||||||
|
author: "Ondra Machacek (@machacekondra)"
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.13
|
||||||
|
why: When migrating to collection we decided to use only _info modules.
|
||||||
|
alternative: Use M(ovirt.ovirt.ovirt_external_provider_info) instead.
|
||||||
|
description:
|
||||||
|
- "Retrieve information about one or more oVirt/RHV external providers."
|
||||||
|
notes:
|
||||||
|
- "This module returns a variable C(ovirt_external_providers), which
|
||||||
|
contains a list of external_providers. You need to register the result with
|
||||||
|
the I(register) keyword to use it."
|
||||||
|
options:
|
||||||
|
type:
|
||||||
|
description:
|
||||||
|
- "Type of the external provider."
|
||||||
|
choices: ['os_image', 'os_network', 'os_volume', 'foreman']
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- "Name of the external provider, can be used as glob expression."
|
||||||
|
type: str
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.general.ovirt_facts
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Examples don't contain auth parameter for simplicity,
|
||||||
|
# look at ovirt_auth module to see how to reuse authentication:
|
||||||
|
|
||||||
|
- name: Gather information about all image external providers named glance
|
||||||
|
ovirt_external_provider_info:
|
||||||
|
type: os_image
|
||||||
|
name: glance
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Print gathered information
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "{{ result.ovirt_external_providers }}"
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
ovirt_external_providers:
|
||||||
|
description:
|
||||||
|
- "List of dictionaries. Content depends on I(type)."
|
||||||
|
- "For type C(foreman), attributes appearing in the dictionary can be found on your oVirt/RHV instance
|
||||||
|
at the following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/external_host_provider."
|
||||||
|
- "For type C(os_image), attributes appearing in the dictionary can be found on your oVirt/RHV instance
|
||||||
|
at the following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/openstack_image_provider."
|
||||||
|
- "For type C(os_volume), attributes appearing in the dictionary can be found on your oVirt/RHV instance
|
||||||
|
at the following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/openstack_volume_provider."
|
||||||
|
- "For type C(os_network), attributes appearing in the dictionary can be found on your oVirt/RHV instance
|
||||||
|
at the following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/openstack_network_provider."
|
||||||
|
returned: On success
|
||||||
|
type: list
|
||||||
|
'''
|
||||||
|
|
||||||
|
import fnmatch
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from ansible.module_utils.common.removed import removed_module
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.community.general.plugins.module_utils._ovirt import (
|
||||||
|
check_sdk,
|
||||||
|
create_connection,
|
||||||
|
get_dict_of_struct,
|
||||||
|
ovirt_info_full_argument_spec,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _external_provider_service(provider_type, system_service):
|
||||||
|
if provider_type == 'os_image':
|
||||||
|
return system_service.openstack_image_providers_service()
|
||||||
|
elif provider_type == 'os_network':
|
||||||
|
return system_service.openstack_network_providers_service()
|
||||||
|
elif provider_type == 'os_volume':
|
||||||
|
return system_service.openstack_volume_providers_service()
|
||||||
|
elif provider_type == 'foreman':
|
||||||
|
return system_service.external_host_providers_service()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = ovirt_info_full_argument_spec(
|
||||||
|
name=dict(default=None, required=False),
|
||||||
|
type=dict(
|
||||||
|
required=True,
|
||||||
|
choices=['os_image', 'os_network', 'os_volume', 'foreman'],
|
||||||
|
aliases=['provider'],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
module = AnsibleModule(argument_spec)
|
||||||
|
is_old_facts = module._name in ('ovirt_external_provider_facts', 'community.general.ovirt_external_provider_facts')
|
||||||
|
if is_old_facts:
|
||||||
|
module.deprecate("The 'ovirt_external_provider_facts' module has been renamed to 'ovirt_external_provider_info', "
|
||||||
|
"and the renamed one no longer returns ansible_facts",
|
||||||
|
version='3.0.0', collection_name='community.general') # was Ansible 2.13
|
||||||
|
|
||||||
|
check_sdk(module)
|
||||||
|
|
||||||
|
try:
|
||||||
|
auth = module.params.pop('auth')
|
||||||
|
connection = create_connection(auth)
|
||||||
|
external_providers_service = _external_provider_service(
|
||||||
|
provider_type=module.params.pop('type'),
|
||||||
|
system_service=connection.system_service(),
|
||||||
|
)
|
||||||
|
if module.params['name']:
|
||||||
|
external_providers = [
|
||||||
|
e for e in external_providers_service.list()
|
||||||
|
if fnmatch.fnmatch(e.name, module.params['name'])
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
external_providers = external_providers_service.list()
|
||||||
|
|
||||||
|
result = dict(
|
||||||
|
ovirt_external_providers=[
|
||||||
|
get_dict_of_struct(
|
||||||
|
struct=c,
|
||||||
|
connection=connection,
|
||||||
|
fetch_nested=module.params.get('fetch_nested'),
|
||||||
|
attributes=module.params.get('nested_attributes'),
|
||||||
|
) for c in external_providers
|
||||||
|
],
|
||||||
|
)
|
||||||
|
if is_old_facts:
|
||||||
|
module.exit_json(changed=False, ansible_facts=result)
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False, **result)
|
||||||
|
except Exception as e:
|
||||||
|
module.fail_json(msg=str(e), exception=traceback.format_exc())
|
||||||
|
finally:
|
||||||
|
connection.close(logout=auth.get('token') is None)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
123
plugins/modules/cloud/ovirt/ovirt_group_facts.py
Normal file
123
plugins/modules/cloud/ovirt/ovirt_group_facts.py
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# This file is part of Ansible
|
||||||
|
#
|
||||||
|
# Ansible is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Ansible is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: ovirt_group_facts
|
||||||
|
short_description: Retrieve information about one or more oVirt/RHV groups
|
||||||
|
author: "Ondra Machacek (@machacekondra)"
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.13
|
||||||
|
why: When migrating to collection we decided to use only _info modules.
|
||||||
|
alternative: Use M(ovirt.ovirt.ovirt_group_info) instead.
|
||||||
|
description:
|
||||||
|
- "Retrieve information about one or more oVirt/RHV groups."
|
||||||
|
notes:
|
||||||
|
- "This module returns a variable C(ovirt_groups), which
|
||||||
|
contains a list of groups. You need to register the result with
|
||||||
|
the I(register) keyword to use it."
|
||||||
|
options:
|
||||||
|
pattern:
|
||||||
|
description:
|
||||||
|
- "Search term which is accepted by oVirt/RHV search backend."
|
||||||
|
- "For example to search group X use following pattern: name=X"
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.general.ovirt_facts
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Examples don't contain auth parameter for simplicity,
|
||||||
|
# look at ovirt_auth module to see how to reuse authentication:
|
||||||
|
|
||||||
|
- name: Gather information about all groups which names start with admin
|
||||||
|
ovirt_group_info:
|
||||||
|
pattern: name=admin*
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Print gathered information
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "{{ result.ovirt_groups }}"
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
ovirt_groups:
|
||||||
|
description: "List of dictionaries describing the groups. Group attributes are mapped to dictionary keys,
|
||||||
|
all groups attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/group."
|
||||||
|
returned: On success.
|
||||||
|
type: list
|
||||||
|
'''
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from ansible.module_utils.common.removed import removed_module
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.community.general.plugins.module_utils._ovirt import (
|
||||||
|
check_sdk,
|
||||||
|
create_connection,
|
||||||
|
get_dict_of_struct,
|
||||||
|
ovirt_info_full_argument_spec,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = ovirt_info_full_argument_spec(
|
||||||
|
pattern=dict(default='', required=False),
|
||||||
|
)
|
||||||
|
module = AnsibleModule(argument_spec)
|
||||||
|
is_old_facts = module._name in ('ovirt_group_facts', 'community.general.ovirt_group_facts')
|
||||||
|
if is_old_facts:
|
||||||
|
module.deprecate("The 'ovirt_group_facts' module has been renamed to 'ovirt_group_info', "
|
||||||
|
"and the renamed one no longer returns ansible_facts",
|
||||||
|
version='3.0.0', collection_name='community.general') # was Ansible 2.13
|
||||||
|
|
||||||
|
check_sdk(module)
|
||||||
|
|
||||||
|
try:
|
||||||
|
auth = module.params.pop('auth')
|
||||||
|
connection = create_connection(auth)
|
||||||
|
groups_service = connection.system_service().groups_service()
|
||||||
|
groups = groups_service.list(search=module.params['pattern'])
|
||||||
|
result = dict(
|
||||||
|
ovirt_groups=[
|
||||||
|
get_dict_of_struct(
|
||||||
|
struct=c,
|
||||||
|
connection=connection,
|
||||||
|
fetch_nested=module.params.get('fetch_nested'),
|
||||||
|
attributes=module.params.get('nested_attributes'),
|
||||||
|
) for c in groups
|
||||||
|
],
|
||||||
|
)
|
||||||
|
if is_old_facts:
|
||||||
|
module.exit_json(changed=False, ansible_facts=result)
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False, **result)
|
||||||
|
except Exception as e:
|
||||||
|
module.fail_json(msg=str(e), exception=traceback.format_exc())
|
||||||
|
finally:
|
||||||
|
connection.close(logout=auth.get('token') is None)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
149
plugins/modules/cloud/ovirt/ovirt_host_facts.py
Normal file
149
plugins/modules/cloud/ovirt/ovirt_host_facts.py
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016 Red Hat, Inc.
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: ovirt_host_facts
|
||||||
|
short_description: Retrieve information about one or more oVirt/RHV hosts
|
||||||
|
author: "Ondra Machacek (@machacekondra)"
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.13
|
||||||
|
why: When migrating to collection we decided to use only _info modules.
|
||||||
|
alternative: Use M(ovirt.ovirt.ovirt_host_info) instead.
|
||||||
|
description:
|
||||||
|
- "Retrieve information about one or more oVirt/RHV hosts."
|
||||||
|
notes:
|
||||||
|
- "This module returns a variable C(ovirt_hosts), which
|
||||||
|
contains a list of hosts. You need to register the result with
|
||||||
|
the I(register) keyword to use it."
|
||||||
|
options:
|
||||||
|
pattern:
|
||||||
|
description:
|
||||||
|
- "Search term which is accepted by oVirt/RHV search backend."
|
||||||
|
- "For example to search host X from datacenter Y use following pattern:
|
||||||
|
name=X and datacenter=Y"
|
||||||
|
all_content:
|
||||||
|
description:
|
||||||
|
- "If I(true) all the attributes of the hosts should be
|
||||||
|
included in the response."
|
||||||
|
default: False
|
||||||
|
type: bool
|
||||||
|
cluster_version:
|
||||||
|
description:
|
||||||
|
- "Filter the hosts based on the cluster version."
|
||||||
|
type: str
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.general.ovirt_facts
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Examples don't contain auth parameter for simplicity,
|
||||||
|
# look at ovirt_auth module to see how to reuse authentication:
|
||||||
|
|
||||||
|
- name: Gather information about all hosts which names start with host and belong to data center west
|
||||||
|
ovirt_host_info:
|
||||||
|
pattern: name=host* and datacenter=west
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Print gathered information
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "{{ result.ovirt_hosts }}"
|
||||||
|
|
||||||
|
- name: Gather information about all hosts with cluster version 4.2
|
||||||
|
ovirt_host_info:
|
||||||
|
pattern: name=host*
|
||||||
|
cluster_version: "4.2"
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Print gathered information
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "{{ result.ovirt_hosts }}"
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
ovirt_hosts:
|
||||||
|
description: "List of dictionaries describing the hosts. Host attributes are mapped to dictionary keys,
|
||||||
|
all hosts attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/host."
|
||||||
|
returned: On success.
|
||||||
|
type: list
|
||||||
|
'''
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from ansible.module_utils.common.removed import removed_module
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.community.general.plugins.module_utils._ovirt import (
|
||||||
|
check_sdk,
|
||||||
|
create_connection,
|
||||||
|
get_dict_of_struct,
|
||||||
|
ovirt_info_full_argument_spec,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_filtered_hosts(cluster_version, hosts, connection):
|
||||||
|
# Filtering by cluster version returns only those which have same cluster version as input
|
||||||
|
filtered_hosts = []
|
||||||
|
for host in hosts:
|
||||||
|
cluster = connection.follow_link(host.cluster)
|
||||||
|
cluster_version_host = str(cluster.version.major) + '.' + str(cluster.version.minor)
|
||||||
|
if cluster_version_host == cluster_version:
|
||||||
|
filtered_hosts.append(host)
|
||||||
|
return filtered_hosts
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = ovirt_info_full_argument_spec(
|
||||||
|
pattern=dict(default='', required=False),
|
||||||
|
all_content=dict(default=False, type='bool'),
|
||||||
|
cluster_version=dict(default=None, type='str'),
|
||||||
|
)
|
||||||
|
module = AnsibleModule(argument_spec)
|
||||||
|
is_old_facts = module._name in ('ovirt_host_facts', 'community.general.ovirt_host_facts')
|
||||||
|
if is_old_facts:
|
||||||
|
module.deprecate("The 'ovirt_host_facts' module has been renamed to 'ovirt_host_info', "
|
||||||
|
"and the renamed one no longer returns ansible_facts",
|
||||||
|
version='3.0.0', collection_name='community.general') # was Ansible 2.13
|
||||||
|
|
||||||
|
check_sdk(module)
|
||||||
|
|
||||||
|
try:
|
||||||
|
auth = module.params.pop('auth')
|
||||||
|
connection = create_connection(auth)
|
||||||
|
hosts_service = connection.system_service().hosts_service()
|
||||||
|
hosts = hosts_service.list(
|
||||||
|
search=module.params['pattern'],
|
||||||
|
all_content=module.params['all_content']
|
||||||
|
)
|
||||||
|
cluster_version = module.params.get('cluster_version')
|
||||||
|
if cluster_version is not None:
|
||||||
|
hosts = get_filtered_hosts(cluster_version, hosts, connection)
|
||||||
|
result = dict(
|
||||||
|
ovirt_hosts=[
|
||||||
|
get_dict_of_struct(
|
||||||
|
struct=c,
|
||||||
|
connection=connection,
|
||||||
|
fetch_nested=module.params.get('fetch_nested'),
|
||||||
|
attributes=module.params.get('nested_attributes'),
|
||||||
|
) for c in hosts
|
||||||
|
],
|
||||||
|
)
|
||||||
|
if is_old_facts:
|
||||||
|
module.exit_json(changed=False, ansible_facts=result)
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False, **result)
|
||||||
|
except Exception as e:
|
||||||
|
module.fail_json(msg=str(e), exception=traceback.format_exc())
|
||||||
|
finally:
|
||||||
|
connection.close(logout=auth.get('token') is None)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
187
plugins/modules/cloud/ovirt/ovirt_host_storage_facts.py
Normal file
187
plugins/modules/cloud/ovirt/ovirt_host_storage_facts.py
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2017 Red Hat, Inc.
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: ovirt_host_storage_facts
|
||||||
|
short_description: Retrieve information about one or more oVirt/RHV HostStorages (applicable only for block storage)
|
||||||
|
author: "Daniel Erez (@derez)"
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.13
|
||||||
|
why: When migrating to collection we decided to use only _info modules.
|
||||||
|
alternative: Use M(ovirt.ovirt.ovirt_host_storage_info) instead.
|
||||||
|
description:
|
||||||
|
- "Retrieve information about one or more oVirt/RHV HostStorages (applicable only for block storage)."
|
||||||
|
options:
|
||||||
|
host:
|
||||||
|
description:
|
||||||
|
- "Host to get device list from."
|
||||||
|
required: true
|
||||||
|
iscsi:
|
||||||
|
description:
|
||||||
|
- "Dictionary with values for iSCSI storage type:"
|
||||||
|
suboptions:
|
||||||
|
address:
|
||||||
|
description:
|
||||||
|
- "Address of the iSCSI storage server."
|
||||||
|
target:
|
||||||
|
description:
|
||||||
|
- "The target IQN for the storage device."
|
||||||
|
username:
|
||||||
|
description:
|
||||||
|
- "A CHAP user name for logging into a target."
|
||||||
|
password:
|
||||||
|
description:
|
||||||
|
- "A CHAP password for logging into a target."
|
||||||
|
portal:
|
||||||
|
description:
|
||||||
|
- "The portal being used to connect with iscsi."
|
||||||
|
fcp:
|
||||||
|
description:
|
||||||
|
- "Dictionary with values for fibre channel storage type:"
|
||||||
|
suboptions:
|
||||||
|
address:
|
||||||
|
description:
|
||||||
|
- "Address of the fibre channel storage server."
|
||||||
|
port:
|
||||||
|
description:
|
||||||
|
- "Port of the fibre channel storage server."
|
||||||
|
lun_id:
|
||||||
|
description:
|
||||||
|
- "LUN id."
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.general.ovirt_facts
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Examples don't contain auth parameter for simplicity,
|
||||||
|
# look at ovirt_auth module to see how to reuse authentication:
|
||||||
|
|
||||||
|
- name: Gather information about HostStorages with specified target and address
|
||||||
|
ovirt_host_storage_info:
|
||||||
|
host: myhost
|
||||||
|
iscsi:
|
||||||
|
target: iqn.2016-08-09.domain-01:nickname
|
||||||
|
address: 10.34.63.204
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Print gathered information
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "{{ result.ovirt_host_storages }}"
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
ovirt_host_storages:
|
||||||
|
description: "List of dictionaries describing the HostStorage. HostStorage attributes are mapped to dictionary keys,
|
||||||
|
all HostStorage attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/host_storage."
|
||||||
|
returned: On success.
|
||||||
|
type: list
|
||||||
|
'''
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
try:
|
||||||
|
import ovirtsdk4.types as otypes
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
from ansible.module_utils.common.removed import removed_module
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.community.general.plugins.module_utils._ovirt import (
|
||||||
|
check_sdk,
|
||||||
|
create_connection,
|
||||||
|
get_dict_of_struct,
|
||||||
|
ovirt_info_full_argument_spec,
|
||||||
|
get_id_by_name,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _login(host_service, iscsi):
|
||||||
|
host_service.iscsi_login(
|
||||||
|
iscsi=otypes.IscsiDetails(
|
||||||
|
username=iscsi.get('username'),
|
||||||
|
password=iscsi.get('password'),
|
||||||
|
address=iscsi.get('address'),
|
||||||
|
target=iscsi.get('target'),
|
||||||
|
portal=iscsi.get('portal')
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_storage_type(params):
|
||||||
|
for sd_type in ['iscsi', 'fcp']:
|
||||||
|
if params.get(sd_type) is not None:
|
||||||
|
return sd_type
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = ovirt_info_full_argument_spec(
|
||||||
|
host=dict(required=True),
|
||||||
|
iscsi=dict(default=None, type='dict'),
|
||||||
|
fcp=dict(default=None, type='dict'),
|
||||||
|
)
|
||||||
|
module = AnsibleModule(argument_spec)
|
||||||
|
is_old_facts = module._name in ('ovirt_host_storage_facts', 'community.general.ovirt_host_storage_facts')
|
||||||
|
if is_old_facts:
|
||||||
|
module.deprecate("The 'ovirt_host_storage_facts' module has been renamed to 'ovirt_host_storage_info', "
|
||||||
|
"and the renamed one no longer returns ansible_facts",
|
||||||
|
version='3.0.0', collection_name='community.general') # was Ansible 2.13
|
||||||
|
check_sdk(module)
|
||||||
|
|
||||||
|
try:
|
||||||
|
auth = module.params.pop('auth')
|
||||||
|
connection = create_connection(auth)
|
||||||
|
|
||||||
|
# Get Host
|
||||||
|
hosts_service = connection.system_service().hosts_service()
|
||||||
|
host_id = get_id_by_name(hosts_service, module.params['host'])
|
||||||
|
storage_type = _get_storage_type(module.params)
|
||||||
|
host_service = hosts_service.host_service(host_id)
|
||||||
|
|
||||||
|
if storage_type == 'iscsi':
|
||||||
|
# Login
|
||||||
|
iscsi = module.params.get('iscsi')
|
||||||
|
_login(host_service, iscsi)
|
||||||
|
|
||||||
|
# Get LUNs exposed from the specified target
|
||||||
|
host_storages = host_service.storage_service().list()
|
||||||
|
|
||||||
|
if storage_type == 'iscsi':
|
||||||
|
filterred_host_storages = [host_storage for host_storage in host_storages
|
||||||
|
if host_storage.type == otypes.StorageType.ISCSI]
|
||||||
|
if 'target' in iscsi:
|
||||||
|
filterred_host_storages = [host_storage for host_storage in filterred_host_storages
|
||||||
|
if iscsi.get('target') == host_storage.logical_units[0].target]
|
||||||
|
elif storage_type == 'fcp':
|
||||||
|
filterred_host_storages = [host_storage for host_storage in host_storages
|
||||||
|
if host_storage.type == otypes.StorageType.FCP]
|
||||||
|
|
||||||
|
result = dict(
|
||||||
|
ovirt_host_storages=[
|
||||||
|
get_dict_of_struct(
|
||||||
|
struct=c,
|
||||||
|
connection=connection,
|
||||||
|
fetch_nested=module.params.get('fetch_nested'),
|
||||||
|
attributes=module.params.get('nested_attributes'),
|
||||||
|
) for c in filterred_host_storages
|
||||||
|
],
|
||||||
|
)
|
||||||
|
if is_old_facts:
|
||||||
|
module.exit_json(changed=False, ansible_facts=result)
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False, **result)
|
||||||
|
except Exception as e:
|
||||||
|
module.fail_json(msg=str(e), exception=traceback.format_exc())
|
||||||
|
finally:
|
||||||
|
connection.close(logout=auth.get('token') is None)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
125
plugins/modules/cloud/ovirt/ovirt_network_facts.py
Normal file
125
plugins/modules/cloud/ovirt/ovirt_network_facts.py
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# This file is part of Ansible
|
||||||
|
#
|
||||||
|
# Ansible is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Ansible is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: ovirt_network_facts
|
||||||
|
short_description: Retrieve information about one or more oVirt/RHV networks
|
||||||
|
author: "Ondra Machacek (@machacekondra)"
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.13
|
||||||
|
why: When migrating to collection we decided to use only _info modules.
|
||||||
|
alternative: Use M(ovirt.ovirt.ovirt_network_info) instead.
|
||||||
|
description:
|
||||||
|
- "Retrieve information about one or more oVirt/RHV networks."
|
||||||
|
notes:
|
||||||
|
- "This module returns a variable C(ovirt_networks), which
|
||||||
|
contains a list of networks. You need to register the result with
|
||||||
|
the I(register) keyword to use it."
|
||||||
|
options:
|
||||||
|
pattern:
|
||||||
|
description:
|
||||||
|
- "Search term which is accepted by oVirt/RHV search backend."
|
||||||
|
- "For example to search network starting with string vlan1 use: name=vlan1*"
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.general.ovirt_facts
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Examples don't contain auth parameter for simplicity,
|
||||||
|
# look at ovirt_auth module to see how to reuse authentication:
|
||||||
|
|
||||||
|
- name: Gather information about all networks which names start with vlan1
|
||||||
|
ovirt_network_info:
|
||||||
|
pattern: name=vlan1*
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Print gathered information
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "{{ result.ovirt_networks }}"
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
ovirt_networks:
|
||||||
|
description: "List of dictionaries describing the networks. Network attributes are mapped to dictionary keys,
|
||||||
|
all networks attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/network."
|
||||||
|
returned: On success.
|
||||||
|
type: list
|
||||||
|
'''
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from ansible.module_utils.common.removed import removed_module
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.community.general.plugins.module_utils._ovirt import (
|
||||||
|
check_sdk,
|
||||||
|
create_connection,
|
||||||
|
get_dict_of_struct,
|
||||||
|
ovirt_info_full_argument_spec,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = ovirt_info_full_argument_spec(
|
||||||
|
pattern=dict(default='', required=False),
|
||||||
|
)
|
||||||
|
module = AnsibleModule(argument_spec)
|
||||||
|
is_old_facts = module._name in ('ovirt_network_facts', 'community.general.ovirt_network_facts')
|
||||||
|
if is_old_facts:
|
||||||
|
module.deprecate("The 'ovirt_network_facts' module has been renamed to 'ovirt_network_info', "
|
||||||
|
"and the renamed one no longer returns ansible_facts",
|
||||||
|
version='3.0.0', collection_name='community.general') # was Ansible 2.13
|
||||||
|
|
||||||
|
check_sdk(module)
|
||||||
|
|
||||||
|
try:
|
||||||
|
auth = module.params.pop('auth')
|
||||||
|
connection = create_connection(auth)
|
||||||
|
networks_service = connection.system_service().networks_service()
|
||||||
|
networks = networks_service.list(search=module.params['pattern'])
|
||||||
|
result = dict(
|
||||||
|
ovirt_networks=[
|
||||||
|
get_dict_of_struct(
|
||||||
|
struct=c,
|
||||||
|
connection=connection,
|
||||||
|
fetch_nested=module.params.get('fetch_nested'),
|
||||||
|
attributes=module.params.get('nested_attributes'),
|
||||||
|
) for c in networks
|
||||||
|
],
|
||||||
|
)
|
||||||
|
if is_old_facts:
|
||||||
|
module.exit_json(changed=False, ansible_facts=result)
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False, **result)
|
||||||
|
except Exception as e:
|
||||||
|
module.fail_json(msg=str(e), exception=traceback.format_exc())
|
||||||
|
finally:
|
||||||
|
connection.close(logout=auth.get('token') is None)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
143
plugins/modules/cloud/ovirt/ovirt_nic_facts.py
Normal file
143
plugins/modules/cloud/ovirt/ovirt_nic_facts.py
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# This file is part of Ansible
|
||||||
|
#
|
||||||
|
# Ansible is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Ansible is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: ovirt_nic_facts
|
||||||
|
short_description: Retrieve information about one or more oVirt/RHV virtual machine network interfaces
|
||||||
|
author: "Ondra Machacek (@machacekondra)"
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.13
|
||||||
|
why: When migrating to collection we decided to use only _info modules.
|
||||||
|
alternative: Use M(ovirt.ovirt.ovirt_nic_info) instead.
|
||||||
|
description:
|
||||||
|
- "Retrieve information about one or more oVirt/RHV virtual machine network interfaces."
|
||||||
|
notes:
|
||||||
|
- "This module returns a variable C(ovirt_nics), which
|
||||||
|
contains a list of NICs. You need to register the result with
|
||||||
|
the I(register) keyword to use it."
|
||||||
|
options:
|
||||||
|
vm:
|
||||||
|
description:
|
||||||
|
- "Name of the VM where NIC is attached."
|
||||||
|
required: true
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- "Name of the NIC, can be used as glob expression."
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.general.ovirt_facts
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Examples don't contain auth parameter for simplicity,
|
||||||
|
# look at ovirt_auth module to see how to reuse authentication:
|
||||||
|
|
||||||
|
- name: Gather information about all NICs which names start with eth for VM named centos7
|
||||||
|
ovirt_nic_info:
|
||||||
|
vm: centos7
|
||||||
|
name: eth*
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Print gathered information
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "{{ result.ovirt_nics }}"
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
ovirt_nics:
|
||||||
|
description: "List of dictionaries describing the network interfaces. NIC attributes are mapped to dictionary keys,
|
||||||
|
all NICs attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/nic."
|
||||||
|
returned: On success.
|
||||||
|
type: list
|
||||||
|
'''
|
||||||
|
|
||||||
|
import fnmatch
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from ansible.module_utils.common.removed import removed_module
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.community.general.plugins.module_utils._ovirt import (
|
||||||
|
check_sdk,
|
||||||
|
create_connection,
|
||||||
|
get_dict_of_struct,
|
||||||
|
ovirt_info_full_argument_spec,
|
||||||
|
search_by_name,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = ovirt_info_full_argument_spec(
|
||||||
|
vm=dict(required=True),
|
||||||
|
name=dict(default=None),
|
||||||
|
)
|
||||||
|
module = AnsibleModule(argument_spec)
|
||||||
|
is_old_facts = module._name in ('ovirt_nic_facts', 'community.general.ovirt_nic_facts')
|
||||||
|
if is_old_facts:
|
||||||
|
module.deprecate("The 'ovirt_nic_facts' module has been renamed to 'ovirt_nic_info', "
|
||||||
|
"and the renamed one no longer returns ansible_facts",
|
||||||
|
version='3.0.0', collection_name='community.general') # was Ansible 2.13
|
||||||
|
|
||||||
|
check_sdk(module)
|
||||||
|
|
||||||
|
try:
|
||||||
|
auth = module.params.pop('auth')
|
||||||
|
connection = create_connection(auth)
|
||||||
|
vms_service = connection.system_service().vms_service()
|
||||||
|
vm_name = module.params['vm']
|
||||||
|
vm = search_by_name(vms_service, vm_name)
|
||||||
|
if vm is None:
|
||||||
|
raise Exception("VM '%s' was not found." % vm_name)
|
||||||
|
|
||||||
|
nics_service = vms_service.service(vm.id).nics_service()
|
||||||
|
if module.params['name']:
|
||||||
|
nics = [
|
||||||
|
e for e in nics_service.list()
|
||||||
|
if fnmatch.fnmatch(e.name, module.params['name'])
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
nics = nics_service.list()
|
||||||
|
|
||||||
|
result = dict(
|
||||||
|
ovirt_nics=[
|
||||||
|
get_dict_of_struct(
|
||||||
|
struct=c,
|
||||||
|
connection=connection,
|
||||||
|
fetch_nested=module.params.get('fetch_nested'),
|
||||||
|
attributes=module.params.get('nested_attributes'),
|
||||||
|
) for c in nics
|
||||||
|
],
|
||||||
|
)
|
||||||
|
if is_old_facts:
|
||||||
|
module.exit_json(changed=False, ansible_facts=result)
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False, **result)
|
||||||
|
except Exception as e:
|
||||||
|
module.fail_json(msg=str(e), exception=traceback.format_exc())
|
||||||
|
finally:
|
||||||
|
connection.close(logout=auth.get('token') is None)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
166
plugins/modules/cloud/ovirt/ovirt_permission_facts.py
Normal file
166
plugins/modules/cloud/ovirt/ovirt_permission_facts.py
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# This file is part of Ansible
|
||||||
|
#
|
||||||
|
# Ansible is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Ansible is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: ovirt_permission_facts
|
||||||
|
short_description: Retrieve information about one or more oVirt/RHV permissions
|
||||||
|
author: "Ondra Machacek (@machacekondra)"
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.13
|
||||||
|
why: When migrating to collection we decided to use only _info modules.
|
||||||
|
alternative: Use M(ovirt.ovirt.ovirt_permission_info) instead.
|
||||||
|
description:
|
||||||
|
- "Retrieve information about one or more oVirt/RHV permissions."
|
||||||
|
notes:
|
||||||
|
- "This module returns a variable C(ovirt_permissions), which
|
||||||
|
contains a list of permissions. You need to register the result with
|
||||||
|
the I(register) keyword to use it."
|
||||||
|
options:
|
||||||
|
user_name:
|
||||||
|
description:
|
||||||
|
- "Username of the user to manage. In most LDAPs it's I(uid) of the user, but in Active Directory you must specify I(UPN) of the user."
|
||||||
|
group_name:
|
||||||
|
description:
|
||||||
|
- "Name of the group to manage."
|
||||||
|
authz_name:
|
||||||
|
description:
|
||||||
|
- "Authorization provider of the user/group. In previous versions of oVirt/RHV known as domain."
|
||||||
|
required: true
|
||||||
|
aliases: ['domain']
|
||||||
|
namespace:
|
||||||
|
description:
|
||||||
|
- "Namespace of the authorization provider, where user/group resides."
|
||||||
|
required: false
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.general.ovirt_facts
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Examples don't contain auth parameter for simplicity,
|
||||||
|
# look at ovirt_auth module to see how to reuse authentication:
|
||||||
|
|
||||||
|
- name: Gather information about all permissions of user with username john
|
||||||
|
ovirt_permission_info:
|
||||||
|
user_name: john
|
||||||
|
authz_name: example.com-authz
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Print gathered information
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "{{ result.ovirt_permissions }}"
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
ovirt_permissions:
|
||||||
|
description: "List of dictionaries describing the permissions. Permission attributes are mapped to dictionary keys,
|
||||||
|
all permissions attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/permission."
|
||||||
|
returned: On success.
|
||||||
|
type: list
|
||||||
|
'''
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
try:
|
||||||
|
import ovirtsdk4 as sdk
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
from ansible.module_utils.common.removed import removed_module
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.community.general.plugins.module_utils._ovirt import (
|
||||||
|
check_sdk,
|
||||||
|
create_connection,
|
||||||
|
get_link_name,
|
||||||
|
ovirt_info_full_argument_spec,
|
||||||
|
search_by_name,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _permissions_service(connection, module):
|
||||||
|
if module.params['user_name']:
|
||||||
|
service = connection.system_service().users_service()
|
||||||
|
entity = next(
|
||||||
|
iter(
|
||||||
|
service.list(
|
||||||
|
search='usrname={0}'.format(
|
||||||
|
'{0}@{1}'.format(module.params['user_name'], module.params['authz_name'])
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
None
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
service = connection.system_service().groups_service()
|
||||||
|
entity = search_by_name(service, module.params['group_name'])
|
||||||
|
|
||||||
|
if entity is None:
|
||||||
|
raise Exception("User/Group wasn't found.")
|
||||||
|
|
||||||
|
return service.service(entity.id).permissions_service()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = ovirt_info_full_argument_spec(
|
||||||
|
authz_name=dict(required=True, aliases=['domain']),
|
||||||
|
user_name=dict(default=None),
|
||||||
|
group_name=dict(default=None),
|
||||||
|
namespace=dict(default=None),
|
||||||
|
)
|
||||||
|
module = AnsibleModule(argument_spec)
|
||||||
|
is_old_facts = module._name in ('ovirt_permission_facts', 'community.general.ovirt_permission_facts')
|
||||||
|
if is_old_facts:
|
||||||
|
module.deprecate("The 'ovirt_permission_facts' module has been renamed to 'ovirt_permission_info', "
|
||||||
|
"and the renamed one no longer returns ansible_facts",
|
||||||
|
version='3.0.0', collection_name='community.general') # was Ansible 2.13
|
||||||
|
|
||||||
|
check_sdk(module)
|
||||||
|
|
||||||
|
try:
|
||||||
|
auth = module.params.pop('auth')
|
||||||
|
connection = create_connection(auth)
|
||||||
|
permissions_service = _permissions_service(connection, module)
|
||||||
|
permissions = []
|
||||||
|
for p in permissions_service.list():
|
||||||
|
newperm = dict()
|
||||||
|
for key, value in p.__dict__.items():
|
||||||
|
if value and isinstance(value, sdk.Struct):
|
||||||
|
newperm[key[1:]] = get_link_name(connection, value)
|
||||||
|
newperm['%s_id' % key[1:]] = value.id
|
||||||
|
permissions.append(newperm)
|
||||||
|
|
||||||
|
result = dict(ovirt_permissions=permissions)
|
||||||
|
if is_old_facts:
|
||||||
|
module.exit_json(changed=False, ansible_facts=result)
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False, **result)
|
||||||
|
except Exception as e:
|
||||||
|
module.fail_json(msg=str(e), exception=traceback.format_exc())
|
||||||
|
finally:
|
||||||
|
connection.close(logout=auth.get('token') is None)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
143
plugins/modules/cloud/ovirt/ovirt_quota_facts.py
Normal file
143
plugins/modules/cloud/ovirt/ovirt_quota_facts.py
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# This file is part of Ansible
|
||||||
|
#
|
||||||
|
# Ansible is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Ansible is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: ovirt_quota_facts
|
||||||
|
short_description: Retrieve information about one or more oVirt/RHV quotas
|
||||||
|
author: "Maor Lipchuk (@machacekondra)"
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.13
|
||||||
|
why: When migrating to collection we decided to use only _info modules.
|
||||||
|
alternative: Use M(ovirt.ovirt.ovirt_quota_info) instead.
|
||||||
|
description:
|
||||||
|
- "Retrieve information about one or more oVirt/RHV quotas."
|
||||||
|
notes:
|
||||||
|
- "This module returns a variable C(ovirt_quotas), which
|
||||||
|
contains a list of quotas. You need to register the result with
|
||||||
|
the I(register) keyword to use it."
|
||||||
|
options:
|
||||||
|
data_center:
|
||||||
|
description:
|
||||||
|
- "Name of the datacenter where quota resides."
|
||||||
|
required: true
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- "Name of the quota, can be used as glob expression."
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.general.ovirt_facts
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Examples don't contain auth parameter for simplicity,
|
||||||
|
# look at ovirt_auth module to see how to reuse authentication:
|
||||||
|
|
||||||
|
- name: Gather information about quota named C<myquota> in Default datacenter
|
||||||
|
ovirt_quota_info:
|
||||||
|
data_center: Default
|
||||||
|
name: myquota
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Print gathered information
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "{{ result.ovirt_quotas }}"
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
ovirt_quotas:
|
||||||
|
description: "List of dictionaries describing the quotas. Quota attributes are mapped to dictionary keys,
|
||||||
|
all quotas attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/quota."
|
||||||
|
returned: On success.
|
||||||
|
type: list
|
||||||
|
'''
|
||||||
|
|
||||||
|
import fnmatch
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from ansible.module_utils.common.removed import removed_module
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.community.general.plugins.module_utils._ovirt import (
|
||||||
|
check_sdk,
|
||||||
|
create_connection,
|
||||||
|
get_dict_of_struct,
|
||||||
|
ovirt_info_full_argument_spec,
|
||||||
|
search_by_name,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = ovirt_info_full_argument_spec(
|
||||||
|
data_center=dict(required=True),
|
||||||
|
name=dict(default=None),
|
||||||
|
)
|
||||||
|
module = AnsibleModule(argument_spec)
|
||||||
|
is_old_facts = module._name in ('ovirt_quota_facts', 'community.general.ovirt_quota_facts')
|
||||||
|
if is_old_facts:
|
||||||
|
module.deprecate("The 'ovirt_quota_facts' module has been renamed to 'ovirt_quota_info', "
|
||||||
|
"and the renamed one no longer returns ansible_facts",
|
||||||
|
version='3.0.0', collection_name='community.general') # was Ansible 2.13
|
||||||
|
|
||||||
|
check_sdk(module)
|
||||||
|
|
||||||
|
try:
|
||||||
|
auth = module.params.pop('auth')
|
||||||
|
connection = create_connection(auth)
|
||||||
|
datacenters_service = connection.system_service().data_centers_service()
|
||||||
|
dc_name = module.params['data_center']
|
||||||
|
dc = search_by_name(datacenters_service, dc_name)
|
||||||
|
if dc is None:
|
||||||
|
raise Exception("Datacenter '%s' was not found." % dc_name)
|
||||||
|
|
||||||
|
quotas_service = datacenters_service.service(dc.id).quotas_service()
|
||||||
|
if module.params['name']:
|
||||||
|
quotas = [
|
||||||
|
e for e in quotas_service.list()
|
||||||
|
if fnmatch.fnmatch(e.name, module.params['name'])
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
quotas = quotas_service.list()
|
||||||
|
|
||||||
|
result = dict(
|
||||||
|
ovirt_quotas=[
|
||||||
|
get_dict_of_struct(
|
||||||
|
struct=c,
|
||||||
|
connection=connection,
|
||||||
|
fetch_nested=module.params.get('fetch_nested'),
|
||||||
|
attributes=module.params.get('nested_attributes'),
|
||||||
|
) for c in quotas
|
||||||
|
],
|
||||||
|
)
|
||||||
|
if is_old_facts:
|
||||||
|
module.exit_json(changed=False, ansible_facts=result)
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False, **result)
|
||||||
|
except Exception as e:
|
||||||
|
module.fail_json(msg=str(e), exception=traceback.format_exc())
|
||||||
|
finally:
|
||||||
|
connection.close(logout=auth.get('token') is None)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
140
plugins/modules/cloud/ovirt/ovirt_scheduling_policy_facts.py
Normal file
140
plugins/modules/cloud/ovirt/ovirt_scheduling_policy_facts.py
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2017 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# This file is part of Ansible
|
||||||
|
#
|
||||||
|
# Ansible is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Ansible is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: ovirt_scheduling_policy_facts
|
||||||
|
short_description: Retrieve information about one or more oVirt scheduling policies
|
||||||
|
author: "Ondra Machacek (@machacekondra)"
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.13
|
||||||
|
why: When migrating to collection we decided to use only _info modules.
|
||||||
|
alternative: Use M(ovirt.ovirt.ovirt_scheduling_policy_info) instead.
|
||||||
|
description:
|
||||||
|
- "Retrieve information about one or more oVirt scheduling policies."
|
||||||
|
notes:
|
||||||
|
- "This module returns a variable C(ovirt_scheduling_policies),
|
||||||
|
which contains a list of scheduling policies. You need to register the result with
|
||||||
|
the I(register) keyword to use it."
|
||||||
|
options:
|
||||||
|
id:
|
||||||
|
description:
|
||||||
|
- "ID of the scheduling policy."
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- "Name of the scheduling policy, can be used as glob expression."
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.general.ovirt_facts
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Examples don't contain auth parameter for simplicity,
|
||||||
|
# look at ovirt_auth module to see how to reuse authentication:
|
||||||
|
|
||||||
|
- name: Gather information about all scheduling policies with name InClusterUpgrade
|
||||||
|
ovirt_scheduling_policy_info:
|
||||||
|
name: InClusterUpgrade
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Print gathered information
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "{{ result.ovirt_scheduling_policies }}"
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
ovirt_scheduling_policies:
|
||||||
|
description: "List of dictionaries describing the scheduling policies.
|
||||||
|
Scheduling policies attributes are mapped to dictionary keys,
|
||||||
|
all scheduling policies attributes can be found at following
|
||||||
|
url: https://ovirt.example.com/ovirt-engine/api/model#types/scheduling_policy."
|
||||||
|
returned: On success.
|
||||||
|
type: list
|
||||||
|
'''
|
||||||
|
|
||||||
|
import fnmatch
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.community.general.plugins.module_utils._ovirt import (
|
||||||
|
check_sdk,
|
||||||
|
create_connection,
|
||||||
|
get_dict_of_struct,
|
||||||
|
ovirt_info_full_argument_spec,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = ovirt_info_full_argument_spec(
|
||||||
|
id=dict(default=None),
|
||||||
|
name=dict(default=None),
|
||||||
|
)
|
||||||
|
module = AnsibleModule(argument_spec)
|
||||||
|
is_old_facts = module._name in ('ovirt_scheduling_policy_facts', 'community.general.ovirt_scheduling_policy_facts')
|
||||||
|
if is_old_facts:
|
||||||
|
module.deprecate("The 'ovirt_scheduling_policy_facts' module has been renamed to 'ovirt_scheduling_policy_info', "
|
||||||
|
"and the renamed one no longer returns ansible_facts",
|
||||||
|
version='3.0.0', collection_name='community.general') # was Ansible 2.13
|
||||||
|
|
||||||
|
check_sdk(module)
|
||||||
|
|
||||||
|
try:
|
||||||
|
auth = module.params.pop('auth')
|
||||||
|
connection = create_connection(auth)
|
||||||
|
system_service = connection.system_service()
|
||||||
|
sched_policies_service = system_service.scheduling_policies_service()
|
||||||
|
if module.params['name']:
|
||||||
|
sched_policies = [
|
||||||
|
e for e in sched_policies_service.list()
|
||||||
|
if fnmatch.fnmatch(e.name, module.params['name'])
|
||||||
|
]
|
||||||
|
elif module.params['id']:
|
||||||
|
sched_policies = [
|
||||||
|
sched_policies_service.service(module.params['id']).get()
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
sched_policies = sched_policies_service.list()
|
||||||
|
|
||||||
|
result = dict(
|
||||||
|
ovirt_scheduling_policies=[
|
||||||
|
get_dict_of_struct(
|
||||||
|
struct=c,
|
||||||
|
connection=connection,
|
||||||
|
fetch_nested=module.params.get('fetch_nested'),
|
||||||
|
attributes=module.params.get('nested_attributes'),
|
||||||
|
) for c in sched_policies
|
||||||
|
],
|
||||||
|
)
|
||||||
|
if is_old_facts:
|
||||||
|
module.exit_json(changed=False, ansible_facts=result)
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False, **result)
|
||||||
|
except Exception as e:
|
||||||
|
module.fail_json(msg=str(e), exception=traceback.format_exc())
|
||||||
|
finally:
|
||||||
|
connection.close(logout=auth.get('token') is None)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
137
plugins/modules/cloud/ovirt/ovirt_snapshot_facts.py
Normal file
137
plugins/modules/cloud/ovirt/ovirt_snapshot_facts.py
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016 Red Hat, Inc.
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: ovirt_snapshot_facts
|
||||||
|
short_description: Retrieve information about one or more oVirt/RHV virtual machine snapshots
|
||||||
|
author: "Ondra Machacek (@machacekondra)"
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.13
|
||||||
|
why: When migrating to collection we decided to use only _info modules.
|
||||||
|
alternative: Use M(ovirt.ovirt.ovirt_snapshot_info) instead.
|
||||||
|
description:
|
||||||
|
- "Retrieve information about one or more oVirt/RHV virtual machine snapshots."
|
||||||
|
notes:
|
||||||
|
- "This module returns a variable C(ovirt_snapshots), which
|
||||||
|
contains a list of snapshots. You need to register the result with
|
||||||
|
the I(register) keyword to use it."
|
||||||
|
options:
|
||||||
|
vm:
|
||||||
|
description:
|
||||||
|
- "Name of the VM with snapshot."
|
||||||
|
required: true
|
||||||
|
description:
|
||||||
|
description:
|
||||||
|
- "Description of the snapshot, can be used as glob expression."
|
||||||
|
snapshot_id:
|
||||||
|
description:
|
||||||
|
- "Id of the snapshot we want to retrieve information about."
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.general.ovirt_facts
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Examples don't contain auth parameter for simplicity,
|
||||||
|
# look at ovirt_auth module to see how to reuse authentication:
|
||||||
|
|
||||||
|
- name: Gather information about all snapshots which description start with update for VM named centos7
|
||||||
|
ovirt_snapshot_info:
|
||||||
|
vm: centos7
|
||||||
|
description: update*
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Print gathered information
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "{{ result.ovirt_snapshots }}"
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
ovirt_snapshots:
|
||||||
|
description: "List of dictionaries describing the snapshot. Snapshot attributes are mapped to dictionary keys,
|
||||||
|
all snapshot attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/snapshot."
|
||||||
|
returned: On success.
|
||||||
|
type: list
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
import fnmatch
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from ansible.module_utils.common.removed import removed_module
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.community.general.plugins.module_utils._ovirt import (
|
||||||
|
check_sdk,
|
||||||
|
create_connection,
|
||||||
|
get_dict_of_struct,
|
||||||
|
ovirt_info_full_argument_spec,
|
||||||
|
search_by_name,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = ovirt_info_full_argument_spec(
|
||||||
|
vm=dict(required=True),
|
||||||
|
description=dict(default=None),
|
||||||
|
snapshot_id=dict(default=None),
|
||||||
|
)
|
||||||
|
module = AnsibleModule(argument_spec)
|
||||||
|
is_old_facts = module._name in ('ovirt_snapshot_facts', 'community.general.ovirt_snapshot_facts')
|
||||||
|
if is_old_facts:
|
||||||
|
module.deprecate("The 'ovirt_snapshot_facts' module has been renamed to 'ovirt_snapshot_info', "
|
||||||
|
"and the renamed one no longer returns ansible_facts",
|
||||||
|
version='3.0.0', collection_name='community.general') # was Ansible 2.13
|
||||||
|
|
||||||
|
check_sdk(module)
|
||||||
|
|
||||||
|
try:
|
||||||
|
auth = module.params.pop('auth')
|
||||||
|
connection = create_connection(auth)
|
||||||
|
vms_service = connection.system_service().vms_service()
|
||||||
|
vm_name = module.params['vm']
|
||||||
|
vm = search_by_name(vms_service, vm_name)
|
||||||
|
if vm is None:
|
||||||
|
raise Exception("VM '%s' was not found." % vm_name)
|
||||||
|
|
||||||
|
snapshots_service = vms_service.service(vm.id).snapshots_service()
|
||||||
|
if module.params['description']:
|
||||||
|
snapshots = [
|
||||||
|
e for e in snapshots_service.list()
|
||||||
|
if fnmatch.fnmatch(e.description, module.params['description'])
|
||||||
|
]
|
||||||
|
elif module.params['snapshot_id']:
|
||||||
|
snapshots = [
|
||||||
|
snapshots_service.snapshot_service(module.params['snapshot_id']).get()
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
snapshots = snapshots_service.list()
|
||||||
|
|
||||||
|
result = dict(
|
||||||
|
ovirt_snapshots=[
|
||||||
|
get_dict_of_struct(
|
||||||
|
struct=c,
|
||||||
|
connection=connection,
|
||||||
|
fetch_nested=module.params.get('fetch_nested'),
|
||||||
|
attributes=module.params.get('nested_attributes'),
|
||||||
|
) for c in snapshots
|
||||||
|
],
|
||||||
|
)
|
||||||
|
if is_old_facts:
|
||||||
|
module.exit_json(changed=False, ansible_facts=result)
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False, **result)
|
||||||
|
except Exception as e:
|
||||||
|
module.fail_json(msg=str(e), exception=traceback.format_exc())
|
||||||
|
finally:
|
||||||
|
connection.close(logout=auth.get('token') is None)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
126
plugins/modules/cloud/ovirt/ovirt_storage_domain_facts.py
Normal file
126
plugins/modules/cloud/ovirt/ovirt_storage_domain_facts.py
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# This file is part of Ansible
|
||||||
|
#
|
||||||
|
# Ansible is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Ansible is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: ovirt_storage_domain_facts
|
||||||
|
short_description: Retrieve information about one or more oVirt/RHV storage domains
|
||||||
|
author: "Ondra Machacek (@machacekondra)"
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.13
|
||||||
|
why: When migrating to collection we decided to use only _info modules.
|
||||||
|
alternative: Use M(ovirt.ovirt.ovirt_storage_domain_info) instead.
|
||||||
|
description:
|
||||||
|
- "Retrieve information about one or more oVirt/RHV storage domains."
|
||||||
|
notes:
|
||||||
|
- "This module returns a variable C(ovirt_storage_domains), which
|
||||||
|
contains a list of storage domains. You need to register the result with
|
||||||
|
the I(register) keyword to use it."
|
||||||
|
options:
|
||||||
|
pattern:
|
||||||
|
description:
|
||||||
|
- "Search term which is accepted by oVirt/RHV search backend."
|
||||||
|
- "For example to search storage domain X from datacenter Y use following pattern:
|
||||||
|
name=X and datacenter=Y"
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.general.ovirt_facts
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Examples don't contain auth parameter for simplicity,
|
||||||
|
# look at ovirt_auth module to see how to reuse authentication:
|
||||||
|
|
||||||
|
- name: >
|
||||||
|
Gather information about all storage domains which names
|
||||||
|
start with data and belong to data center west
|
||||||
|
ovirt_storage_domain_info:
|
||||||
|
pattern: name=data* and datacenter=west
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Print gathered information
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "{{ result.ovirt_storage_domains }}"
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
ovirt_storage_domains:
|
||||||
|
description: "List of dictionaries describing the storage domains. Storage_domain attributes are mapped to dictionary keys,
|
||||||
|
all storage domains attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/storage_domain."
|
||||||
|
returned: On success.
|
||||||
|
type: list
|
||||||
|
'''
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from ansible.module_utils.common.removed import removed_module
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.community.general.plugins.module_utils._ovirt import (
|
||||||
|
check_sdk,
|
||||||
|
create_connection,
|
||||||
|
get_dict_of_struct,
|
||||||
|
ovirt_info_full_argument_spec,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = ovirt_info_full_argument_spec(
|
||||||
|
pattern=dict(default='', required=False),
|
||||||
|
)
|
||||||
|
module = AnsibleModule(argument_spec)
|
||||||
|
is_old_facts = module._name in ('ovirt_storage_domain_facts', 'community.general.ovirt_storage_domain_facts')
|
||||||
|
if is_old_facts:
|
||||||
|
module.deprecate("The 'ovirt_storage_domain_facts' module has been renamed to 'ovirt_storage_domain_info', "
|
||||||
|
"and the renamed one no longer returns ansible_facts",
|
||||||
|
version='3.0.0', collection_name='community.general') # was Ansible 2.13
|
||||||
|
|
||||||
|
check_sdk(module)
|
||||||
|
|
||||||
|
try:
|
||||||
|
auth = module.params.pop('auth')
|
||||||
|
connection = create_connection(auth)
|
||||||
|
storage_domains_service = connection.system_service().storage_domains_service()
|
||||||
|
storage_domains = storage_domains_service.list(search=module.params['pattern'])
|
||||||
|
result = dict(
|
||||||
|
ovirt_storage_domains=[
|
||||||
|
get_dict_of_struct(
|
||||||
|
struct=c,
|
||||||
|
connection=connection,
|
||||||
|
fetch_nested=module.params.get('fetch_nested'),
|
||||||
|
attributes=module.params.get('nested_attributes'),
|
||||||
|
) for c in storage_domains
|
||||||
|
],
|
||||||
|
)
|
||||||
|
if is_old_facts:
|
||||||
|
module.exit_json(changed=False, ansible_facts=result)
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False, **result)
|
||||||
|
except Exception as e:
|
||||||
|
module.fail_json(msg=str(e), exception=traceback.format_exc())
|
||||||
|
finally:
|
||||||
|
connection.close(logout=auth.get('token') is None)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
142
plugins/modules/cloud/ovirt/ovirt_storage_template_facts.py
Normal file
142
plugins/modules/cloud/ovirt/ovirt_storage_template_facts.py
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2017 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# This file is part of Ansible
|
||||||
|
#
|
||||||
|
# Ansible is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Ansible is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: ovirt_storage_template_facts
|
||||||
|
short_description: Retrieve information about one or more oVirt/RHV templates relate to a storage domain.
|
||||||
|
author: "Maor Lipchuk (@machacekondra)"
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.13
|
||||||
|
why: When migrating to collection we decided to use only _info modules.
|
||||||
|
alternative: Use M(ovirt.ovirt.ovirt_storage_template_info) instead.
|
||||||
|
description:
|
||||||
|
- "Retrieve information about one or more oVirt/RHV templates relate to a storage domain."
|
||||||
|
notes:
|
||||||
|
- "This module returns a variable C(ovirt_storage_templates), which
|
||||||
|
contains a list of templates. You need to register the result with
|
||||||
|
the I(register) keyword to use it."
|
||||||
|
options:
|
||||||
|
unregistered:
|
||||||
|
description:
|
||||||
|
- "Flag which indicates whether to get unregistered templates which contain one or more
|
||||||
|
disks which reside on a storage domain or diskless templates."
|
||||||
|
type: bool
|
||||||
|
default: false
|
||||||
|
max:
|
||||||
|
description:
|
||||||
|
- "Sets the maximum number of templates to return. If not specified all the templates are returned."
|
||||||
|
storage_domain:
|
||||||
|
description:
|
||||||
|
- "The storage domain name where the templates should be listed."
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.general.ovirt_facts
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Examples don't contain auth parameter for simplicity,
|
||||||
|
# look at ovirt_auth module to see how to reuse authentication:
|
||||||
|
|
||||||
|
- name: Gather information about all templates which relate to a storage domain and are unregistered
|
||||||
|
ovirt_storage_template_info:
|
||||||
|
unregistered: yes
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Print gathered information
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "{{ result.ovirt_storage_templates }}"
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
ovirt_storage_templates:
|
||||||
|
description: "List of dictionaries describing the Templates. Template attributes are mapped to dictionary keys,
|
||||||
|
all Templates attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/template."
|
||||||
|
returned: On success.
|
||||||
|
type: list
|
||||||
|
'''
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from ansible.module_utils.common.removed import removed_module
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.community.general.plugins.module_utils._ovirt import (
|
||||||
|
check_sdk,
|
||||||
|
create_connection,
|
||||||
|
get_dict_of_struct,
|
||||||
|
ovirt_info_full_argument_spec,
|
||||||
|
get_id_by_name
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = ovirt_info_full_argument_spec(
|
||||||
|
storage_domain=dict(default=None),
|
||||||
|
max=dict(default=None, type='int'),
|
||||||
|
unregistered=dict(default=False, type='bool'),
|
||||||
|
)
|
||||||
|
module = AnsibleModule(argument_spec)
|
||||||
|
is_old_facts = module._name in ('ovirt_storage_template_facts', 'community.general.ovirt_storage_template_facts')
|
||||||
|
if is_old_facts:
|
||||||
|
module.deprecate("The 'ovirt_storage_template_facts' module has been renamed to 'ovirt_storage_template_info', "
|
||||||
|
"and the renamed one no longer returns ansible_facts",
|
||||||
|
version='3.0.0', collection_name='community.general') # was Ansible 2.13
|
||||||
|
|
||||||
|
check_sdk(module)
|
||||||
|
|
||||||
|
try:
|
||||||
|
auth = module.params.pop('auth')
|
||||||
|
connection = create_connection(auth)
|
||||||
|
storage_domains_service = connection.system_service().storage_domains_service()
|
||||||
|
sd_id = get_id_by_name(storage_domains_service, module.params['storage_domain'])
|
||||||
|
storage_domain_service = storage_domains_service.storage_domain_service(sd_id)
|
||||||
|
templates_service = storage_domain_service.templates_service()
|
||||||
|
|
||||||
|
# Find the unregistered Template we want to register:
|
||||||
|
if module.params.get('unregistered'):
|
||||||
|
templates = templates_service.list(unregistered=True)
|
||||||
|
else:
|
||||||
|
templates = templates_service.list(max=module.params['max'])
|
||||||
|
result = dict(
|
||||||
|
ovirt_storage_templates=[
|
||||||
|
get_dict_of_struct(
|
||||||
|
struct=c,
|
||||||
|
connection=connection,
|
||||||
|
fetch_nested=module.params.get('fetch_nested'),
|
||||||
|
attributes=module.params.get('nested_attributes'),
|
||||||
|
) for c in templates
|
||||||
|
],
|
||||||
|
)
|
||||||
|
if is_old_facts:
|
||||||
|
module.exit_json(changed=False, ansible_facts=result)
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False, **result)
|
||||||
|
except Exception as e:
|
||||||
|
module.fail_json(msg=str(e), exception=traceback.format_exc())
|
||||||
|
finally:
|
||||||
|
connection.close(logout=auth.get('token') is None)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
142
plugins/modules/cloud/ovirt/ovirt_storage_vm_facts.py
Normal file
142
plugins/modules/cloud/ovirt/ovirt_storage_vm_facts.py
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2017 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# This file is part of Ansible
|
||||||
|
#
|
||||||
|
# Ansible is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Ansible is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: ovirt_storage_vm_facts
|
||||||
|
short_description: Retrieve information about one or more oVirt/RHV virtual machines relate to a storage domain.
|
||||||
|
author: "Maor Lipchuk (@machacekondra)"
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.13
|
||||||
|
why: When migrating to collection we decided to use only _info modules.
|
||||||
|
alternative: Use M(ovirt.ovirt.ovirt_storage_vm_info) instead.
|
||||||
|
description:
|
||||||
|
- "Retrieve information about one or more oVirt/RHV virtual machines relate to a storage domain."
|
||||||
|
notes:
|
||||||
|
- "This module returns a variable C(ovirt_storage_vms), which
|
||||||
|
contains a list of virtual machines. You need to register the result with
|
||||||
|
the I(register) keyword to use it."
|
||||||
|
options:
|
||||||
|
unregistered:
|
||||||
|
description:
|
||||||
|
- "Flag which indicates whether to get unregistered virtual machines which contain one or more
|
||||||
|
disks which reside on a storage domain or diskless virtual machines."
|
||||||
|
type: bool
|
||||||
|
default: false
|
||||||
|
max:
|
||||||
|
description:
|
||||||
|
- "Sets the maximum number of virtual machines to return. If not specified all the virtual machines are returned."
|
||||||
|
storage_domain:
|
||||||
|
description:
|
||||||
|
- "The storage domain name where the virtual machines should be listed."
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.general.ovirt_facts
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Examples don't contain auth parameter for simplicity,
|
||||||
|
# look at ovirt_auth module to see how to reuse authentication:
|
||||||
|
|
||||||
|
- name: Gather information about all VMs which relate to a storage domain and are unregistered
|
||||||
|
ovirt_vms_info:
|
||||||
|
unregistered: yes
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Print gathered information
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "{{ result.ovirt_storage_vms }}"
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
ovirt_storage_vms:
|
||||||
|
description: "List of dictionaries describing the VMs. VM attributes are mapped to dictionary keys,
|
||||||
|
all VMs attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/vm."
|
||||||
|
returned: On success.
|
||||||
|
type: list
|
||||||
|
'''
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from ansible.module_utils.common.removed import removed_module
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.community.general.plugins.module_utils._ovirt import (
|
||||||
|
check_sdk,
|
||||||
|
create_connection,
|
||||||
|
get_dict_of_struct,
|
||||||
|
ovirt_info_full_argument_spec,
|
||||||
|
get_id_by_name
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = ovirt_info_full_argument_spec(
|
||||||
|
storage_domain=dict(default=None),
|
||||||
|
max=dict(default=None, type='int'),
|
||||||
|
unregistered=dict(default=False, type='bool'),
|
||||||
|
)
|
||||||
|
module = AnsibleModule(argument_spec)
|
||||||
|
is_old_facts = module._name in ('ovirt_storage_vm_facts', 'community.general.ovirt_storage_vm_facts')
|
||||||
|
if is_old_facts:
|
||||||
|
module.deprecate("The 'ovirt_storage_vm_facts' module has been renamed to 'ovirt_storage_vm_info', "
|
||||||
|
"and the renamed one no longer returns ansible_facts",
|
||||||
|
version='3.0.0', collection_name='community.general') # was Ansible 2.13
|
||||||
|
|
||||||
|
check_sdk(module)
|
||||||
|
|
||||||
|
try:
|
||||||
|
auth = module.params.pop('auth')
|
||||||
|
connection = create_connection(auth)
|
||||||
|
storage_domains_service = connection.system_service().storage_domains_service()
|
||||||
|
sd_id = get_id_by_name(storage_domains_service, module.params['storage_domain'])
|
||||||
|
storage_domain_service = storage_domains_service.storage_domain_service(sd_id)
|
||||||
|
vms_service = storage_domain_service.vms_service()
|
||||||
|
|
||||||
|
# Find the unregistered VM we want to register:
|
||||||
|
if module.params.get('unregistered'):
|
||||||
|
vms = vms_service.list(unregistered=True)
|
||||||
|
else:
|
||||||
|
vms = vms_service.list()
|
||||||
|
result = dict(
|
||||||
|
ovirt_storage_vms=[
|
||||||
|
get_dict_of_struct(
|
||||||
|
struct=c,
|
||||||
|
connection=connection,
|
||||||
|
fetch_nested=module.params.get('fetch_nested'),
|
||||||
|
attributes=module.params.get('nested_attributes'),
|
||||||
|
) for c in vms
|
||||||
|
],
|
||||||
|
)
|
||||||
|
if is_old_facts:
|
||||||
|
module.exit_json(changed=False, ansible_facts=result)
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False, **result)
|
||||||
|
except Exception as e:
|
||||||
|
module.fail_json(msg=str(e), exception=traceback.format_exc())
|
||||||
|
finally:
|
||||||
|
connection.close(logout=auth.get('token') is None)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
172
plugins/modules/cloud/ovirt/ovirt_tag_facts.py
Normal file
172
plugins/modules/cloud/ovirt/ovirt_tag_facts.py
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# This file is part of Ansible
|
||||||
|
#
|
||||||
|
# Ansible is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Ansible is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: ovirt_tag_facts
|
||||||
|
short_description: Retrieve information about one or more oVirt/RHV tags
|
||||||
|
author: "Ondra Machacek (@machacekondra)"
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.13
|
||||||
|
why: When migrating to collection we decided to use only _info modules.
|
||||||
|
alternative: Use M(ovirt.ovirt.ovirt_tag_info) instead.
|
||||||
|
description:
|
||||||
|
- "Retrieve information about one or more oVirt/RHV tags."
|
||||||
|
notes:
|
||||||
|
- "This module returns a variable C(ovirt_tags), which
|
||||||
|
contains a list of tags. You need to register the result with
|
||||||
|
the I(register) keyword to use it."
|
||||||
|
options:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- "Name of the tag which should be listed."
|
||||||
|
vm:
|
||||||
|
description:
|
||||||
|
- "Name of the VM, which tags should be listed."
|
||||||
|
host:
|
||||||
|
description:
|
||||||
|
- "Name of the host, which tags should be listed."
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.general.ovirt_facts
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Examples don't contain auth parameter for simplicity,
|
||||||
|
# look at ovirt_auth module to see how to reuse authentication:
|
||||||
|
|
||||||
|
- name: Gather information about all tags, which names start with tag
|
||||||
|
ovirt_tag_info:
|
||||||
|
name: tag*
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Print gathered information
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "{{ result.ovirt_tags }}"
|
||||||
|
|
||||||
|
- name: Gather information about all tags, which are assigned to VM postgres
|
||||||
|
ovirt_tag_info:
|
||||||
|
vm: postgres
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Print gathered information
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "{{ result.ovirt_tags }}"
|
||||||
|
|
||||||
|
- name: Gather information about all tags, which are assigned to host west
|
||||||
|
ovirt_tag_info:
|
||||||
|
host: west
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Print gathered information
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "{{ result.ovirt_tags }}"
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
ovirt_tags:
|
||||||
|
description: "List of dictionaries describing the tags. Tags attributes are mapped to dictionary keys,
|
||||||
|
all tags attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/tag."
|
||||||
|
returned: On success.
|
||||||
|
type: list
|
||||||
|
'''
|
||||||
|
|
||||||
|
import fnmatch
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from ansible.module_utils.common.removed import removed_module
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.community.general.plugins.module_utils._ovirt import (
|
||||||
|
check_sdk,
|
||||||
|
create_connection,
|
||||||
|
get_dict_of_struct,
|
||||||
|
ovirt_info_full_argument_spec,
|
||||||
|
search_by_name,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = ovirt_info_full_argument_spec(
|
||||||
|
name=dict(default=None),
|
||||||
|
host=dict(default=None),
|
||||||
|
vm=dict(default=None),
|
||||||
|
)
|
||||||
|
module = AnsibleModule(argument_spec)
|
||||||
|
is_old_facts = module._name in ('ovirt_tag_facts', 'community.general.ovirt_tag_facts')
|
||||||
|
if is_old_facts:
|
||||||
|
module.deprecate("The 'ovirt_tag_facts' module has been renamed to 'ovirt_tag_info', "
|
||||||
|
"and the renamed one no longer returns ansible_facts",
|
||||||
|
version='3.0.0', collection_name='community.general') # was Ansible 2.13
|
||||||
|
|
||||||
|
check_sdk(module)
|
||||||
|
|
||||||
|
try:
|
||||||
|
auth = module.params.pop('auth')
|
||||||
|
connection = create_connection(auth)
|
||||||
|
tags_service = connection.system_service().tags_service()
|
||||||
|
tags = []
|
||||||
|
all_tags = tags_service.list()
|
||||||
|
if module.params['name']:
|
||||||
|
tags.extend([
|
||||||
|
t for t in all_tags
|
||||||
|
if fnmatch.fnmatch(t.name, module.params['name'])
|
||||||
|
])
|
||||||
|
if module.params['host']:
|
||||||
|
hosts_service = connection.system_service().hosts_service()
|
||||||
|
host = search_by_name(hosts_service, module.params['host'])
|
||||||
|
if host is None:
|
||||||
|
raise Exception("Host '%s' was not found." % module.params['host'])
|
||||||
|
tags.extend(hosts_service.host_service(host.id).tags_service().list())
|
||||||
|
if module.params['vm']:
|
||||||
|
vms_service = connection.system_service().vms_service()
|
||||||
|
vm = search_by_name(vms_service, module.params['vm'])
|
||||||
|
if vm is None:
|
||||||
|
raise Exception("Vm '%s' was not found." % module.params['vm'])
|
||||||
|
tags.extend(vms_service.vm_service(vm.id).tags_service().list())
|
||||||
|
|
||||||
|
if not (module.params['vm'] or module.params['host'] or module.params['name']):
|
||||||
|
tags = all_tags
|
||||||
|
|
||||||
|
result = dict(
|
||||||
|
ovirt_tags=[
|
||||||
|
get_dict_of_struct(
|
||||||
|
struct=t,
|
||||||
|
connection=connection,
|
||||||
|
fetch_nested=module.params['fetch_nested'],
|
||||||
|
attributes=module.params['nested_attributes'],
|
||||||
|
) for t in tags
|
||||||
|
],
|
||||||
|
)
|
||||||
|
if is_old_facts:
|
||||||
|
module.exit_json(changed=False, ansible_facts=result)
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False, **result)
|
||||||
|
except Exception as e:
|
||||||
|
module.fail_json(msg=str(e), exception=traceback.format_exc())
|
||||||
|
finally:
|
||||||
|
connection.close(logout=auth.get('token') is None)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
124
plugins/modules/cloud/ovirt/ovirt_template_facts.py
Normal file
124
plugins/modules/cloud/ovirt/ovirt_template_facts.py
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# This file is part of Ansible
|
||||||
|
#
|
||||||
|
# Ansible is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Ansible is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: ovirt_template_facts
|
||||||
|
short_description: Retrieve information about one or more oVirt/RHV templates
|
||||||
|
author: "Ondra Machacek (@machacekondra)"
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.13
|
||||||
|
why: When migrating to collection we decided to use only _info modules.
|
||||||
|
alternative: Use M(ovirt.ovirt.ovirt_template_info) instead.
|
||||||
|
description:
|
||||||
|
- "Retrieve information about one or more oVirt/RHV templates."
|
||||||
|
notes:
|
||||||
|
- "This module returns a variable C(ovirt_templates), which
|
||||||
|
contains a list of templates. You need to register the result with
|
||||||
|
the I(register) keyword to use it."
|
||||||
|
options:
|
||||||
|
pattern:
|
||||||
|
description:
|
||||||
|
- "Search term which is accepted by oVirt/RHV search backend."
|
||||||
|
- "For example to search template X from datacenter Y use following pattern:
|
||||||
|
name=X and datacenter=Y"
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.general.ovirt_facts
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Examples don't contain auth parameter for simplicity,
|
||||||
|
# look at ovirt_auth module to see how to reuse authentication:
|
||||||
|
|
||||||
|
- name: Gather information about all templates which names start with centos and belongs to data center west
|
||||||
|
ovirt_template_info:
|
||||||
|
pattern: name=centos* and datacenter=west
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Print gathered information
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "{{ result.ovirt_templates }}"
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
ovirt_templates:
|
||||||
|
description: "List of dictionaries describing the templates. Template attributes are mapped to dictionary keys,
|
||||||
|
all templates attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/template."
|
||||||
|
returned: On success.
|
||||||
|
type: list
|
||||||
|
'''
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from ansible.module_utils.common.removed import removed_module
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.community.general.plugins.module_utils._ovirt import (
|
||||||
|
check_sdk,
|
||||||
|
create_connection,
|
||||||
|
get_dict_of_struct,
|
||||||
|
ovirt_info_full_argument_spec,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = ovirt_info_full_argument_spec(
|
||||||
|
pattern=dict(default='', required=False),
|
||||||
|
)
|
||||||
|
module = AnsibleModule(argument_spec)
|
||||||
|
is_old_facts = module._name in ('ovirt_template_facts', 'community.general.ovirt_template_facts')
|
||||||
|
if is_old_facts:
|
||||||
|
module.deprecate("The 'ovirt_template_facts' module has been renamed to 'ovirt_template_info', "
|
||||||
|
"and the renamed one no longer returns ansible_facts",
|
||||||
|
version='3.0.0', collection_name='community.general') # was Ansible 2.13
|
||||||
|
|
||||||
|
check_sdk(module)
|
||||||
|
|
||||||
|
try:
|
||||||
|
auth = module.params.pop('auth')
|
||||||
|
connection = create_connection(auth)
|
||||||
|
templates_service = connection.system_service().templates_service()
|
||||||
|
templates = templates_service.list(search=module.params['pattern'])
|
||||||
|
result = dict(
|
||||||
|
ovirt_templates=[
|
||||||
|
get_dict_of_struct(
|
||||||
|
struct=c,
|
||||||
|
connection=connection,
|
||||||
|
fetch_nested=module.params.get('fetch_nested'),
|
||||||
|
attributes=module.params.get('nested_attributes'),
|
||||||
|
) for c in templates
|
||||||
|
],
|
||||||
|
)
|
||||||
|
if is_old_facts:
|
||||||
|
module.exit_json(changed=False, ansible_facts=result)
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False, **result)
|
||||||
|
except Exception as e:
|
||||||
|
module.fail_json(msg=str(e), exception=traceback.format_exc())
|
||||||
|
finally:
|
||||||
|
connection.close(logout=auth.get('token') is None)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
123
plugins/modules/cloud/ovirt/ovirt_user_facts.py
Normal file
123
plugins/modules/cloud/ovirt/ovirt_user_facts.py
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# This file is part of Ansible
|
||||||
|
#
|
||||||
|
# Ansible is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Ansible is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: ovirt_user_facts
|
||||||
|
short_description: Retrieve information about one or more oVirt/RHV users
|
||||||
|
author: "Ondra Machacek (@machacekondra)"
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.13
|
||||||
|
why: When migrating to collection we decided to use only _info modules.
|
||||||
|
alternative: Use M(ovirt.ovirt.ovirt_user_info) instead.
|
||||||
|
description:
|
||||||
|
- "Retrieve information about one or more oVirt/RHV users."
|
||||||
|
notes:
|
||||||
|
- "This module returns a variable C(ovirt_users), which
|
||||||
|
contains a list of users. You need to register the result with
|
||||||
|
the I(register) keyword to use it."
|
||||||
|
options:
|
||||||
|
pattern:
|
||||||
|
description:
|
||||||
|
- "Search term which is accepted by oVirt/RHV search backend."
|
||||||
|
- "For example to search user X use following pattern: name=X"
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.general.ovirt_facts
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Examples don't contain auth parameter for simplicity,
|
||||||
|
# look at ovirt_auth module to see how to reuse authentication:
|
||||||
|
|
||||||
|
- name: Gather information about all users which first names start with john
|
||||||
|
ovirt_user_info:
|
||||||
|
pattern: name=john*
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Print gathered information
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "{{ result.ovirt_users }}"
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
ovirt_users:
|
||||||
|
description: "List of dictionaries describing the users. User attributes are mapped to dictionary keys,
|
||||||
|
all users attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/user."
|
||||||
|
returned: On success.
|
||||||
|
type: list
|
||||||
|
'''
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from ansible.module_utils.common.removed import removed_module
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.community.general.plugins.module_utils._ovirt import (
|
||||||
|
check_sdk,
|
||||||
|
create_connection,
|
||||||
|
get_dict_of_struct,
|
||||||
|
ovirt_info_full_argument_spec,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = ovirt_info_full_argument_spec(
|
||||||
|
pattern=dict(default='', required=False),
|
||||||
|
)
|
||||||
|
module = AnsibleModule(argument_spec)
|
||||||
|
is_old_facts = module._name in ('ovirt_user_facts', 'community.general.ovirt_user_facts')
|
||||||
|
if is_old_facts:
|
||||||
|
module.deprecate("The 'ovirt_user_facts' module has been renamed to 'ovirt_user_info', "
|
||||||
|
"and the renamed one no longer returns ansible_facts",
|
||||||
|
version='3.0.0', collection_name='community.general') # was Ansible 2.13
|
||||||
|
|
||||||
|
check_sdk(module)
|
||||||
|
|
||||||
|
try:
|
||||||
|
auth = module.params.pop('auth')
|
||||||
|
connection = create_connection(auth)
|
||||||
|
users_service = connection.system_service().users_service()
|
||||||
|
users = users_service.list(search=module.params['pattern'])
|
||||||
|
result = dict(
|
||||||
|
ovirt_users=[
|
||||||
|
get_dict_of_struct(
|
||||||
|
struct=c,
|
||||||
|
connection=connection,
|
||||||
|
fetch_nested=module.params.get('fetch_nested'),
|
||||||
|
attributes=module.params.get('nested_attributes'),
|
||||||
|
) for c in users
|
||||||
|
],
|
||||||
|
)
|
||||||
|
if is_old_facts:
|
||||||
|
module.exit_json(changed=False, ansible_facts=result)
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False, **result)
|
||||||
|
except Exception as e:
|
||||||
|
module.fail_json(msg=str(e), exception=traceback.format_exc())
|
||||||
|
finally:
|
||||||
|
connection.close(logout=auth.get('token') is None)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
166
plugins/modules/cloud/ovirt/ovirt_vm_facts.py
Normal file
166
plugins/modules/cloud/ovirt/ovirt_vm_facts.py
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# This file is part of Ansible
|
||||||
|
#
|
||||||
|
# Ansible is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Ansible is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: ovirt_vm_facts
|
||||||
|
short_description: Retrieve information about one or more oVirt/RHV virtual machines
|
||||||
|
author: "Ondra Machacek (@machacekondra)"
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.13
|
||||||
|
why: When migrating to collection we decided to use only _info modules.
|
||||||
|
alternative: Use M(ovirt.ovirt.ovirt_vm_info) instead.
|
||||||
|
description:
|
||||||
|
- "Retrieve information about one or more oVirt/RHV virtual machines."
|
||||||
|
notes:
|
||||||
|
- "This module returns a variable C(ovirt_vms), which
|
||||||
|
contains a list of virtual machines. You need to register the result with
|
||||||
|
the I(register) keyword to use it."
|
||||||
|
options:
|
||||||
|
pattern:
|
||||||
|
description:
|
||||||
|
- "Search term which is accepted by oVirt/RHV search backend."
|
||||||
|
- "For example to search VM X from cluster Y use following pattern:
|
||||||
|
name=X and cluster=Y"
|
||||||
|
all_content:
|
||||||
|
description:
|
||||||
|
- "If I(true) all the attributes of the virtual machines should be
|
||||||
|
included in the response."
|
||||||
|
type: bool
|
||||||
|
default: false
|
||||||
|
case_sensitive:
|
||||||
|
description:
|
||||||
|
- "If I(true) performed search will take case into account."
|
||||||
|
type: bool
|
||||||
|
default: true
|
||||||
|
max:
|
||||||
|
description:
|
||||||
|
- "The maximum number of results to return."
|
||||||
|
next_run:
|
||||||
|
description:
|
||||||
|
- "Indicates if the returned result describes the virtual machine as it is currently running or if describes
|
||||||
|
the virtual machine with the modifications that have already been performed but that will only come into
|
||||||
|
effect when the virtual machine is restarted. By default the value is set by engine."
|
||||||
|
type: bool
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.general.ovirt_facts
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Examples don't contain auth parameter for simplicity,
|
||||||
|
# look at ovirt_auth module to see how to reuse authentication:
|
||||||
|
|
||||||
|
- name: Gather information about all VMs which names start with centos and belong to cluster west
|
||||||
|
ovirt_vm_info:
|
||||||
|
pattern: name=centos* and cluster=west
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Print gathered information
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "{{ result.ovirt_vms }}"
|
||||||
|
|
||||||
|
- name: Gather info about next run configuration of virtual machine named myvm
|
||||||
|
ovirt_vm_info:
|
||||||
|
pattern: name=myvm
|
||||||
|
next_run: true
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Print gathered information
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "{{ result.ovirt_vms[0] }}"
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
ovirt_vms:
|
||||||
|
description: "List of dictionaries describing the VMs. VM attributes are mapped to dictionary keys,
|
||||||
|
all VMs attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/vm."
|
||||||
|
returned: On success.
|
||||||
|
type: list
|
||||||
|
'''
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from ansible.module_utils.common.removed import removed_module
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.community.general.plugins.module_utils._ovirt import (
|
||||||
|
check_sdk,
|
||||||
|
create_connection,
|
||||||
|
get_dict_of_struct,
|
||||||
|
ovirt_info_full_argument_spec,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = ovirt_info_full_argument_spec(
|
||||||
|
pattern=dict(default='', required=False),
|
||||||
|
all_content=dict(default=False, type='bool'),
|
||||||
|
next_run=dict(default=None, type='bool'),
|
||||||
|
case_sensitive=dict(default=True, type='bool'),
|
||||||
|
max=dict(default=None, type='int'),
|
||||||
|
)
|
||||||
|
module = AnsibleModule(argument_spec)
|
||||||
|
is_old_facts = module._name in ('ovirt_vm_facts', 'community.general.ovirt_vm_facts')
|
||||||
|
if is_old_facts:
|
||||||
|
module.deprecate("The 'ovirt_vm_facts' module has been renamed to 'ovirt_vm_info', "
|
||||||
|
"and the renamed one no longer returns ansible_facts",
|
||||||
|
version='3.0.0', collection_name='community.general') # was Ansible 2.13
|
||||||
|
|
||||||
|
check_sdk(module)
|
||||||
|
|
||||||
|
try:
|
||||||
|
auth = module.params.pop('auth')
|
||||||
|
connection = create_connection(auth)
|
||||||
|
vms_service = connection.system_service().vms_service()
|
||||||
|
vms = vms_service.list(
|
||||||
|
search=module.params['pattern'],
|
||||||
|
all_content=module.params['all_content'],
|
||||||
|
case_sensitive=module.params['case_sensitive'],
|
||||||
|
max=module.params['max'],
|
||||||
|
)
|
||||||
|
if module.params['next_run']:
|
||||||
|
vms = [vms_service.vm_service(vm.id).get(next_run=True) for vm in vms]
|
||||||
|
|
||||||
|
result = dict(
|
||||||
|
ovirt_vms=[
|
||||||
|
get_dict_of_struct(
|
||||||
|
struct=c,
|
||||||
|
connection=connection,
|
||||||
|
fetch_nested=module.params.get('fetch_nested'),
|
||||||
|
attributes=module.params.get('nested_attributes'),
|
||||||
|
) for c in vms
|
||||||
|
],
|
||||||
|
)
|
||||||
|
if is_old_facts:
|
||||||
|
module.exit_json(changed=False, ansible_facts=result)
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False, **result)
|
||||||
|
except Exception as e:
|
||||||
|
module.fail_json(msg=str(e), exception=traceback.format_exc())
|
||||||
|
finally:
|
||||||
|
connection.close(logout=auth.get('token') is None)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
123
plugins/modules/cloud/ovirt/ovirt_vmpool_facts.py
Normal file
123
plugins/modules/cloud/ovirt/ovirt_vmpool_facts.py
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# This file is part of Ansible
|
||||||
|
#
|
||||||
|
# Ansible is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Ansible is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: ovirt_vmpool_facts
|
||||||
|
short_description: Retrieve information about one or more oVirt/RHV vmpools
|
||||||
|
author: "Ondra Machacek (@machacekondra)"
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.13
|
||||||
|
why: When migrating to collection we decided to use only _info modules.
|
||||||
|
alternative: Use M(ovirt.ovirt.ovirt_vmpool_info) instead.
|
||||||
|
description:
|
||||||
|
- "Retrieve information about one or more oVirt/RHV vmpools."
|
||||||
|
notes:
|
||||||
|
- "This module returns a variable C(ovirt_vmpools), which
|
||||||
|
contains a list of vmpools. You need to register the result with
|
||||||
|
the I(register) keyword to use it."
|
||||||
|
options:
|
||||||
|
pattern:
|
||||||
|
description:
|
||||||
|
- "Search term which is accepted by oVirt/RHV search backend."
|
||||||
|
- "For example to search vmpool X: name=X"
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.general.ovirt_facts
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Examples don't contain auth parameter for simplicity,
|
||||||
|
# look at ovirt_auth module to see how to reuse authentication:
|
||||||
|
|
||||||
|
- name: Gather information about all vm pools which names start with centos
|
||||||
|
ovirt_vmpool_info:
|
||||||
|
pattern: name=centos*
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Print gathered information
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "{{ result.ovirt_vm_pools }}"
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
ovirt_vm_pools:
|
||||||
|
description: "List of dictionaries describing the vmpools. Vm pool attributes are mapped to dictionary keys,
|
||||||
|
all vmpools attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/vm_pool."
|
||||||
|
returned: On success.
|
||||||
|
type: list
|
||||||
|
'''
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from ansible.module_utils.common.removed import removed_module
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.community.general.plugins.module_utils._ovirt import (
|
||||||
|
check_sdk,
|
||||||
|
create_connection,
|
||||||
|
get_dict_of_struct,
|
||||||
|
ovirt_info_full_argument_spec,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = ovirt_info_full_argument_spec(
|
||||||
|
pattern=dict(default='', required=False),
|
||||||
|
)
|
||||||
|
module = AnsibleModule(argument_spec)
|
||||||
|
is_old_facts = module._name in ('ovirt_vmpool_facts', 'community.general.ovirt_vmpool_facts')
|
||||||
|
if is_old_facts:
|
||||||
|
module.deprecate("The 'ovirt_vmpool_facts' module has been renamed to 'ovirt_vmpool_info', "
|
||||||
|
"and the renamed one no longer returns ansible_facts",
|
||||||
|
version='3.0.0', collection_name='community.general') # was Ansible 2.13
|
||||||
|
|
||||||
|
check_sdk(module)
|
||||||
|
|
||||||
|
try:
|
||||||
|
auth = module.params.pop('auth')
|
||||||
|
connection = create_connection(auth)
|
||||||
|
vmpools_service = connection.system_service().vm_pools_service()
|
||||||
|
vmpools = vmpools_service.list(search=module.params['pattern'])
|
||||||
|
result = dict(
|
||||||
|
ovirt_vm_pools=[
|
||||||
|
get_dict_of_struct(
|
||||||
|
struct=c,
|
||||||
|
connection=connection,
|
||||||
|
fetch_nested=module.params.get('fetch_nested'),
|
||||||
|
attributes=module.params.get('nested_attributes'),
|
||||||
|
) for c in vmpools
|
||||||
|
],
|
||||||
|
)
|
||||||
|
if is_old_facts:
|
||||||
|
module.exit_json(changed=False, ansible_facts=result)
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False, **result)
|
||||||
|
except Exception as e:
|
||||||
|
module.fail_json(msg=str(e), exception=traceback.format_exc())
|
||||||
|
finally:
|
||||||
|
connection.close(logout=auth.get('token') is None)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
@@ -817,6 +817,7 @@ def main():
|
|||||||
meta=dict(type='dict', default={}),
|
meta=dict(type='dict', default={}),
|
||||||
name=dict(),
|
name=dict(),
|
||||||
networks=dict(type='list', elements='str', default=['public', 'private']),
|
networks=dict(type='list', elements='str', default=['public', 'private']),
|
||||||
|
service=dict(),
|
||||||
state=dict(default='present', choices=['present', 'absent']),
|
state=dict(default='present', choices=['present', 'absent']),
|
||||||
user_data=dict(no_log=True),
|
user_data=dict(no_log=True),
|
||||||
wait=dict(default=False, type='bool'),
|
wait=dict(default=False, type='bool'),
|
||||||
@@ -832,6 +833,13 @@ def main():
|
|||||||
if not HAS_PYRAX:
|
if not HAS_PYRAX:
|
||||||
module.fail_json(msg='pyrax is required for this module')
|
module.fail_json(msg='pyrax is required for this module')
|
||||||
|
|
||||||
|
service = module.params.get('service')
|
||||||
|
|
||||||
|
if service is not None:
|
||||||
|
module.fail_json(msg='The "service" attribute has been deprecated, '
|
||||||
|
'please remove "service: cloudservers" from your '
|
||||||
|
'playbook pertaining to the "rax" module')
|
||||||
|
|
||||||
auto_increment = module.params.get('auto_increment')
|
auto_increment = module.params.get('auto_increment')
|
||||||
boot_from_volume = module.params.get('boot_from_volume')
|
boot_from_volume = module.params.get('boot_from_volume')
|
||||||
boot_volume = module.params.get('boot_volume')
|
boot_volume = module.params.get('boot_volume')
|
||||||
|
|||||||
125
plugins/modules/cloud/scaleway/scaleway_image_facts.py
Normal file
125
plugins/modules/cloud/scaleway/scaleway_image_facts.py
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = r'''
|
||||||
|
---
|
||||||
|
module: scaleway_image_facts
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.13
|
||||||
|
why: Deprecated in favour of C(_info) module.
|
||||||
|
alternative: Use M(community.general.scaleway_image_info) instead.
|
||||||
|
short_description: Gather facts about the Scaleway images available.
|
||||||
|
description:
|
||||||
|
- Gather facts about the Scaleway images available.
|
||||||
|
author:
|
||||||
|
- "Yanis Guenane (@Spredzy)"
|
||||||
|
- "Remy Leone (@sieben)"
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.general.scaleway
|
||||||
|
|
||||||
|
|
||||||
|
options:
|
||||||
|
region:
|
||||||
|
type: str
|
||||||
|
description:
|
||||||
|
- Scaleway compute zone
|
||||||
|
required: true
|
||||||
|
choices:
|
||||||
|
- ams1
|
||||||
|
- EMEA-NL-EVS
|
||||||
|
- par1
|
||||||
|
- EMEA-FR-PAR1
|
||||||
|
- par2
|
||||||
|
- EMEA-FR-PAR2
|
||||||
|
- waw1
|
||||||
|
- EMEA-PL-WAW1
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = r'''
|
||||||
|
- name: Gather Scaleway images facts
|
||||||
|
community.general.scaleway_image_facts:
|
||||||
|
region: par1
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = r'''
|
||||||
|
---
|
||||||
|
scaleway_image_facts:
|
||||||
|
description: Response from Scaleway API
|
||||||
|
returned: success
|
||||||
|
type: complex
|
||||||
|
sample:
|
||||||
|
"scaleway_image_facts": [
|
||||||
|
{
|
||||||
|
"arch": "x86_64",
|
||||||
|
"creation_date": "2018-07-17T16:18:49.276456+00:00",
|
||||||
|
"default_bootscript": {
|
||||||
|
"architecture": "x86_64",
|
||||||
|
"bootcmdargs": "LINUX_COMMON scaleway boot=local nbd.max_part=16",
|
||||||
|
"default": false,
|
||||||
|
"dtb": "",
|
||||||
|
"id": "15fbd2f7-a0f9-412b-8502-6a44da8d98b8",
|
||||||
|
"initrd": "http://169.254.42.24/initrd/initrd-Linux-x86_64-v3.14.5.gz",
|
||||||
|
"kernel": "http://169.254.42.24/kernel/x86_64-mainline-lts-4.9-4.9.93-rev1/vmlinuz-4.9.93",
|
||||||
|
"organization": "11111111-1111-4111-8111-111111111111",
|
||||||
|
"public": true,
|
||||||
|
"title": "x86_64 mainline 4.9.93 rev1"
|
||||||
|
},
|
||||||
|
"extra_volumes": [],
|
||||||
|
"from_server": null,
|
||||||
|
"id": "00ae4a88-3252-4eda-9feb-5f6b56bf5ef0",
|
||||||
|
"modification_date": "2018-07-17T16:42:06.319315+00:00",
|
||||||
|
"name": "Debian Stretch",
|
||||||
|
"organization": "51b656e3-4865-41e8-adbc-0c45bdd780db",
|
||||||
|
"public": true,
|
||||||
|
"root_volume": {
|
||||||
|
"id": "da32dfbb-c5ff-476d-ae2d-c297dd09b7dd",
|
||||||
|
"name": "snapshot-2a7229dc-d431-4dc5-b66e-95db08b773af-2018-07-17_16:18",
|
||||||
|
"size": 25000000000,
|
||||||
|
"volume_type": "l_ssd"
|
||||||
|
},
|
||||||
|
"state": "available"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.community.general.plugins.module_utils.scaleway import (
|
||||||
|
Scaleway, ScalewayException, scaleway_argument_spec, SCALEWAY_LOCATION)
|
||||||
|
|
||||||
|
|
||||||
|
class ScalewayImageFacts(Scaleway):
|
||||||
|
|
||||||
|
def __init__(self, module):
|
||||||
|
super(ScalewayImageFacts, self).__init__(module)
|
||||||
|
self.name = 'images'
|
||||||
|
|
||||||
|
region = module.params["region"]
|
||||||
|
self.module.params['api_url'] = SCALEWAY_LOCATION[region]["api_endpoint"]
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = scaleway_argument_spec()
|
||||||
|
argument_spec.update(dict(
|
||||||
|
region=dict(required=True, choices=list(SCALEWAY_LOCATION.keys())),
|
||||||
|
))
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec=argument_spec,
|
||||||
|
supports_check_mode=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
module.exit_json(
|
||||||
|
ansible_facts={'scaleway_image_facts': ScalewayImageFacts(module).get_resources()}
|
||||||
|
)
|
||||||
|
except ScalewayException as exc:
|
||||||
|
module.fail_json(msg=exc.message)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
108
plugins/modules/cloud/scaleway/scaleway_ip_facts.py
Normal file
108
plugins/modules/cloud/scaleway/scaleway_ip_facts.py
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = r'''
|
||||||
|
---
|
||||||
|
module: scaleway_ip_facts
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.13
|
||||||
|
why: Deprecated in favour of C(_info) module.
|
||||||
|
alternative: Use M(community.general.scaleway_ip_info) instead.
|
||||||
|
short_description: Gather facts about the Scaleway ips available.
|
||||||
|
description:
|
||||||
|
- Gather facts about the Scaleway ips available.
|
||||||
|
author:
|
||||||
|
- "Yanis Guenane (@Spredzy)"
|
||||||
|
- "Remy Leone (@sieben)"
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.general.scaleway
|
||||||
|
|
||||||
|
options:
|
||||||
|
region:
|
||||||
|
type: str
|
||||||
|
description:
|
||||||
|
- Scaleway region to use (for example par1).
|
||||||
|
required: true
|
||||||
|
choices:
|
||||||
|
- ams1
|
||||||
|
- EMEA-NL-EVS
|
||||||
|
- par1
|
||||||
|
- EMEA-FR-PAR1
|
||||||
|
- par2
|
||||||
|
- EMEA-FR-PAR2
|
||||||
|
- waw1
|
||||||
|
- EMEA-PL-WAW1
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = r'''
|
||||||
|
- name: Gather Scaleway ips facts
|
||||||
|
community.general.scaleway_ip_facts:
|
||||||
|
region: par1
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = r'''
|
||||||
|
---
|
||||||
|
scaleway_ip_facts:
|
||||||
|
description: Response from Scaleway API
|
||||||
|
returned: success
|
||||||
|
type: complex
|
||||||
|
sample:
|
||||||
|
"scaleway_ip_facts": [
|
||||||
|
{
|
||||||
|
"address": "163.172.170.243",
|
||||||
|
"id": "ea081794-a581-8899-8451-386ddaf0a451",
|
||||||
|
"organization": "3f709602-5e6c-4619-b80c-e324324324af",
|
||||||
|
"reverse": null,
|
||||||
|
"server": {
|
||||||
|
"id": "12f19bc7-109c-4517-954c-e6b3d0311363",
|
||||||
|
"name": "scw-e0d158"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.community.general.plugins.module_utils.scaleway import (
|
||||||
|
Scaleway,
|
||||||
|
ScalewayException,
|
||||||
|
scaleway_argument_spec,
|
||||||
|
SCALEWAY_LOCATION,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ScalewayIpFacts(Scaleway):
|
||||||
|
|
||||||
|
def __init__(self, module):
|
||||||
|
super(ScalewayIpFacts, self).__init__(module)
|
||||||
|
self.name = 'ips'
|
||||||
|
|
||||||
|
region = module.params["region"]
|
||||||
|
self.module.params['api_url'] = SCALEWAY_LOCATION[region]["api_endpoint"]
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = scaleway_argument_spec()
|
||||||
|
argument_spec.update(dict(
|
||||||
|
region=dict(required=True, choices=list(SCALEWAY_LOCATION.keys())),
|
||||||
|
))
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec=argument_spec,
|
||||||
|
supports_check_mode=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
module.exit_json(
|
||||||
|
ansible_facts={'scaleway_ip_facts': ScalewayIpFacts(module).get_resources()}
|
||||||
|
)
|
||||||
|
except ScalewayException as exc:
|
||||||
|
module.fail_json(msg=exc.message)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
104
plugins/modules/cloud/scaleway/scaleway_organization_facts.py
Normal file
104
plugins/modules/cloud/scaleway/scaleway_organization_facts.py
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = r'''
|
||||||
|
---
|
||||||
|
module: scaleway_organization_facts
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.13
|
||||||
|
why: Deprecated in favour of C(_info) module.
|
||||||
|
alternative: Use M(community.general.scaleway_organization_info) instead.
|
||||||
|
short_description: Gather facts about the Scaleway organizations available.
|
||||||
|
description:
|
||||||
|
- Gather facts about the Scaleway organizations available.
|
||||||
|
author:
|
||||||
|
- "Yanis Guenane (@Spredzy)"
|
||||||
|
- "Remy Leone (@sieben)"
|
||||||
|
options:
|
||||||
|
api_url:
|
||||||
|
description:
|
||||||
|
- Scaleway API URL
|
||||||
|
default: 'https://account.scaleway.com'
|
||||||
|
aliases: ['base_url']
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.general.scaleway
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = r'''
|
||||||
|
- name: Gather Scaleway organizations facts
|
||||||
|
community.general.scaleway_organization_facts:
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = r'''
|
||||||
|
---
|
||||||
|
scaleway_organization_facts:
|
||||||
|
description: Response from Scaleway API
|
||||||
|
returned: success
|
||||||
|
type: complex
|
||||||
|
sample:
|
||||||
|
"scaleway_organization_facts": [
|
||||||
|
{
|
||||||
|
"address_city_name": "Paris",
|
||||||
|
"address_country_code": "FR",
|
||||||
|
"address_line1": "42 Rue de l'univers",
|
||||||
|
"address_line2": null,
|
||||||
|
"address_postal_code": "75042",
|
||||||
|
"address_subdivision_code": "FR-75",
|
||||||
|
"creation_date": "2018-08-06T13:43:28.508575+00:00",
|
||||||
|
"currency": "EUR",
|
||||||
|
"customer_class": "individual",
|
||||||
|
"id": "3f709602-5e6c-4619-b80c-e8432ferewtr",
|
||||||
|
"locale": "fr_FR",
|
||||||
|
"modification_date": "2018-08-06T14:56:41.401685+00:00",
|
||||||
|
"name": "James Bond",
|
||||||
|
"support_id": "694324",
|
||||||
|
"support_level": "basic",
|
||||||
|
"support_pin": "9324",
|
||||||
|
"users": [],
|
||||||
|
"vat_number": null,
|
||||||
|
"warnings": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule, env_fallback
|
||||||
|
from ansible_collections.community.general.plugins.module_utils.scaleway import (
|
||||||
|
Scaleway, ScalewayException, scaleway_argument_spec
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ScalewayOrganizationFacts(Scaleway):
|
||||||
|
|
||||||
|
def __init__(self, module):
|
||||||
|
super(ScalewayOrganizationFacts, self).__init__(module)
|
||||||
|
self.name = 'organizations'
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = scaleway_argument_spec()
|
||||||
|
argument_spec.update(dict(
|
||||||
|
api_url=dict(fallback=(env_fallback, ['SCW_API_URL']), default='https://account.scaleway.com', aliases=['base_url']),
|
||||||
|
))
|
||||||
|
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec=argument_spec,
|
||||||
|
supports_check_mode=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
module.exit_json(
|
||||||
|
ansible_facts={'scaleway_organization_facts': ScalewayOrganizationFacts(module).get_resources()}
|
||||||
|
)
|
||||||
|
except ScalewayException as exc:
|
||||||
|
module.fail_json(msg=exc.message)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
112
plugins/modules/cloud/scaleway/scaleway_security_group_facts.py
Normal file
112
plugins/modules/cloud/scaleway/scaleway_security_group_facts.py
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = r'''
|
||||||
|
---
|
||||||
|
module: scaleway_security_group_facts
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.13
|
||||||
|
why: Deprecated in favour of C(_info) module.
|
||||||
|
alternative: Use M(community.general.scaleway_security_group_info) instead.
|
||||||
|
short_description: Gather facts about the Scaleway security groups available.
|
||||||
|
description:
|
||||||
|
- Gather facts about the Scaleway security groups available.
|
||||||
|
author:
|
||||||
|
- "Yanis Guenane (@Spredzy)"
|
||||||
|
- "Remy Leone (@sieben)"
|
||||||
|
options:
|
||||||
|
region:
|
||||||
|
type: str
|
||||||
|
description:
|
||||||
|
- Scaleway region to use (for example par1).
|
||||||
|
required: true
|
||||||
|
choices:
|
||||||
|
- ams1
|
||||||
|
- EMEA-NL-EVS
|
||||||
|
- par1
|
||||||
|
- EMEA-FR-PAR1
|
||||||
|
- par2
|
||||||
|
- EMEA-FR-PAR2
|
||||||
|
- waw1
|
||||||
|
- EMEA-PL-WAW1
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.general.scaleway
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = r'''
|
||||||
|
- name: Gather Scaleway security groups facts
|
||||||
|
community.general.scaleway_security_group_facts:
|
||||||
|
region: par1
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = r'''
|
||||||
|
---
|
||||||
|
scaleway_security_group_facts:
|
||||||
|
description: Response from Scaleway API
|
||||||
|
returned: success
|
||||||
|
type: complex
|
||||||
|
sample:
|
||||||
|
"scaleway_security_group_facts": [
|
||||||
|
{
|
||||||
|
"description": "test-ams",
|
||||||
|
"enable_default_security": true,
|
||||||
|
"id": "7fcde327-8bed-43a6-95c4-6dfbc56d8b51",
|
||||||
|
"name": "test-ams",
|
||||||
|
"organization": "3f709602-5e6c-4619-b80c-e841c89734af",
|
||||||
|
"organization_default": false,
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"id": "12f19bc7-108c-4517-954c-e6b3d0311363",
|
||||||
|
"name": "scw-e0d158"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.community.general.plugins.module_utils.scaleway import (
|
||||||
|
Scaleway,
|
||||||
|
ScalewayException,
|
||||||
|
scaleway_argument_spec,
|
||||||
|
SCALEWAY_LOCATION,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ScalewaySecurityGroupFacts(Scaleway):
|
||||||
|
|
||||||
|
def __init__(self, module):
|
||||||
|
super(ScalewaySecurityGroupFacts, self).__init__(module)
|
||||||
|
self.name = 'security_groups'
|
||||||
|
|
||||||
|
region = module.params["region"]
|
||||||
|
self.module.params['api_url'] = SCALEWAY_LOCATION[region]["api_endpoint"]
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = scaleway_argument_spec()
|
||||||
|
argument_spec.update(dict(
|
||||||
|
region=dict(required=True, choices=list(SCALEWAY_LOCATION.keys())),
|
||||||
|
))
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec=argument_spec,
|
||||||
|
supports_check_mode=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
module.exit_json(
|
||||||
|
ansible_facts={'scaleway_security_group_facts': ScalewaySecurityGroupFacts(module).get_resources()}
|
||||||
|
)
|
||||||
|
except ScalewayException as exc:
|
||||||
|
module.fail_json(msg=exc.message)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
195
plugins/modules/cloud/scaleway/scaleway_server_facts.py
Normal file
195
plugins/modules/cloud/scaleway/scaleway_server_facts.py
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = r'''
|
||||||
|
---
|
||||||
|
module: scaleway_server_facts
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.13
|
||||||
|
why: Deprecated in favour of C(_info) module.
|
||||||
|
alternative: Use M(community.general.scaleway_server_info) instead.
|
||||||
|
short_description: Gather facts about the Scaleway servers available.
|
||||||
|
description:
|
||||||
|
- Gather facts about the Scaleway servers available.
|
||||||
|
author:
|
||||||
|
- "Yanis Guenane (@Spredzy)"
|
||||||
|
- "Remy Leone (@sieben)"
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.general.scaleway
|
||||||
|
|
||||||
|
options:
|
||||||
|
region:
|
||||||
|
type: str
|
||||||
|
description:
|
||||||
|
- Scaleway region to use (for example par1).
|
||||||
|
required: true
|
||||||
|
choices:
|
||||||
|
- ams1
|
||||||
|
- EMEA-NL-EVS
|
||||||
|
- par1
|
||||||
|
- EMEA-FR-PAR1
|
||||||
|
- par2
|
||||||
|
- EMEA-FR-PAR2
|
||||||
|
- waw1
|
||||||
|
- EMEA-PL-WAW1
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = r'''
|
||||||
|
- name: Gather Scaleway servers facts
|
||||||
|
community.general.scaleway_server_facts:
|
||||||
|
region: par1
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = r'''
|
||||||
|
---
|
||||||
|
scaleway_server_facts:
|
||||||
|
description: Response from Scaleway API
|
||||||
|
returned: success
|
||||||
|
type: complex
|
||||||
|
sample:
|
||||||
|
"scaleway_server_facts": [
|
||||||
|
{
|
||||||
|
"arch": "x86_64",
|
||||||
|
"boot_type": "local",
|
||||||
|
"bootscript": {
|
||||||
|
"architecture": "x86_64",
|
||||||
|
"bootcmdargs": "LINUX_COMMON scaleway boot=local nbd.max_part=16",
|
||||||
|
"default": true,
|
||||||
|
"dtb": "",
|
||||||
|
"id": "b1e68c26-a19c-4eac-9222-498b22bd7ad9",
|
||||||
|
"initrd": "http://169.254.42.24/initrd/initrd-Linux-x86_64-v3.14.5.gz",
|
||||||
|
"kernel": "http://169.254.42.24/kernel/x86_64-mainline-lts-4.4-4.4.127-rev1/vmlinuz-4.4.127",
|
||||||
|
"organization": "11111111-1111-4111-8111-111111111111",
|
||||||
|
"public": true,
|
||||||
|
"title": "x86_64 mainline 4.4.127 rev1"
|
||||||
|
},
|
||||||
|
"commercial_type": "START1-XS",
|
||||||
|
"creation_date": "2018-08-14T21:36:56.271545+00:00",
|
||||||
|
"dynamic_ip_required": false,
|
||||||
|
"enable_ipv6": false,
|
||||||
|
"extra_networks": [],
|
||||||
|
"hostname": "scw-e0d256",
|
||||||
|
"id": "12f19bc7-108c-4517-954c-e6b3d0311363",
|
||||||
|
"image": {
|
||||||
|
"arch": "x86_64",
|
||||||
|
"creation_date": "2018-04-26T12:42:21.619844+00:00",
|
||||||
|
"default_bootscript": {
|
||||||
|
"architecture": "x86_64",
|
||||||
|
"bootcmdargs": "LINUX_COMMON scaleway boot=local nbd.max_part=16",
|
||||||
|
"default": true,
|
||||||
|
"dtb": "",
|
||||||
|
"id": "b1e68c26-a19c-4eac-9222-498b22bd7ad9",
|
||||||
|
"initrd": "http://169.254.42.24/initrd/initrd-Linux-x86_64-v3.14.5.gz",
|
||||||
|
"kernel": "http://169.254.42.24/kernel/x86_64-mainline-lts-4.4-4.4.127-rev1/vmlinuz-4.4.127",
|
||||||
|
"organization": "11111111-1111-4111-8111-111111111111",
|
||||||
|
"public": true,
|
||||||
|
"title": "x86_64 mainline 4.4.127 rev1"
|
||||||
|
},
|
||||||
|
"extra_volumes": [],
|
||||||
|
"from_server": null,
|
||||||
|
"id": "67375eb1-f14d-4f02-bb42-6119cecbde51",
|
||||||
|
"modification_date": "2018-04-26T12:49:07.573004+00:00",
|
||||||
|
"name": "Ubuntu Xenial",
|
||||||
|
"organization": "51b656e3-4865-41e8-adbc-0c45bdd780db",
|
||||||
|
"public": true,
|
||||||
|
"root_volume": {
|
||||||
|
"id": "020b8d61-3867-4a0e-84a4-445c5393e05d",
|
||||||
|
"name": "snapshot-87fc282d-f252-4262-adad-86979d9074cf-2018-04-26_12:42",
|
||||||
|
"size": 25000000000,
|
||||||
|
"volume_type": "l_ssd"
|
||||||
|
},
|
||||||
|
"state": "available"
|
||||||
|
},
|
||||||
|
"ipv6": null,
|
||||||
|
"location": {
|
||||||
|
"cluster_id": "5",
|
||||||
|
"hypervisor_id": "412",
|
||||||
|
"node_id": "2",
|
||||||
|
"platform_id": "13",
|
||||||
|
"zone_id": "par1"
|
||||||
|
},
|
||||||
|
"maintenances": [],
|
||||||
|
"modification_date": "2018-08-14T21:37:28.630882+00:00",
|
||||||
|
"name": "scw-e0d256",
|
||||||
|
"organization": "3f709602-5e6c-4619-b80c-e841c89734af",
|
||||||
|
"private_ip": "10.14.222.131",
|
||||||
|
"protected": false,
|
||||||
|
"public_ip": {
|
||||||
|
"address": "163.172.170.197",
|
||||||
|
"dynamic": false,
|
||||||
|
"id": "ea081794-a581-4495-8451-386ddaf0a451"
|
||||||
|
},
|
||||||
|
"security_group": {
|
||||||
|
"id": "a37379d2-d8b0-4668-9cfb-1233fc436f7e",
|
||||||
|
"name": "Default security group"
|
||||||
|
},
|
||||||
|
"state": "running",
|
||||||
|
"state_detail": "booted",
|
||||||
|
"tags": [],
|
||||||
|
"volumes": {
|
||||||
|
"0": {
|
||||||
|
"creation_date": "2018-08-14T21:36:56.271545+00:00",
|
||||||
|
"export_uri": "device://dev/vda",
|
||||||
|
"id": "68386fae-4f55-4fbf-aabb-953036a85872",
|
||||||
|
"modification_date": "2018-08-14T21:36:56.271545+00:00",
|
||||||
|
"name": "snapshot-87fc282d-f252-4262-adad-86979d9074cf-2018-04-26_12:42",
|
||||||
|
"organization": "3f709602-5e6c-4619-b80c-e841c89734af",
|
||||||
|
"server": {
|
||||||
|
"id": "12f19bc7-108c-4517-954c-e6b3d0311363",
|
||||||
|
"name": "scw-e0d256"
|
||||||
|
},
|
||||||
|
"size": 25000000000,
|
||||||
|
"state": "available",
|
||||||
|
"volume_type": "l_ssd"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.community.general.plugins.module_utils.scaleway import (
|
||||||
|
Scaleway,
|
||||||
|
ScalewayException,
|
||||||
|
scaleway_argument_spec,
|
||||||
|
SCALEWAY_LOCATION,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ScalewayServerFacts(Scaleway):
|
||||||
|
|
||||||
|
def __init__(self, module):
|
||||||
|
super(ScalewayServerFacts, self).__init__(module)
|
||||||
|
self.name = 'servers'
|
||||||
|
|
||||||
|
region = module.params["region"]
|
||||||
|
self.module.params['api_url'] = SCALEWAY_LOCATION[region]["api_endpoint"]
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = scaleway_argument_spec()
|
||||||
|
argument_spec.update(dict(
|
||||||
|
region=dict(required=True, choices=list(SCALEWAY_LOCATION.keys())),
|
||||||
|
))
|
||||||
|
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec=argument_spec,
|
||||||
|
supports_check_mode=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
module.exit_json(
|
||||||
|
ansible_facts={'scaleway_server_facts': ScalewayServerFacts(module).get_resources()}
|
||||||
|
)
|
||||||
|
except ScalewayException as exc:
|
||||||
|
module.fail_json(msg=exc.message)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
113
plugins/modules/cloud/scaleway/scaleway_snapshot_facts.py
Normal file
113
plugins/modules/cloud/scaleway/scaleway_snapshot_facts.py
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = r'''
|
||||||
|
---
|
||||||
|
module: scaleway_snapshot_facts
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.13
|
||||||
|
why: Deprecated in favour of C(_info) module.
|
||||||
|
alternative: Use M(community.general.scaleway_snapshot_info) instead.
|
||||||
|
short_description: Gather facts about the Scaleway snapshots available.
|
||||||
|
description:
|
||||||
|
- Gather facts about the Scaleway snapshot available.
|
||||||
|
author:
|
||||||
|
- "Yanis Guenane (@Spredzy)"
|
||||||
|
- "Remy Leone (@sieben)"
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.general.scaleway
|
||||||
|
|
||||||
|
options:
|
||||||
|
region:
|
||||||
|
type: str
|
||||||
|
description:
|
||||||
|
- Scaleway region to use (for example par1).
|
||||||
|
required: true
|
||||||
|
choices:
|
||||||
|
- ams1
|
||||||
|
- EMEA-NL-EVS
|
||||||
|
- par1
|
||||||
|
- EMEA-FR-PAR1
|
||||||
|
- par2
|
||||||
|
- EMEA-FR-PAR2
|
||||||
|
- waw1
|
||||||
|
- EMEA-PL-WAW1
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = r'''
|
||||||
|
- name: Gather Scaleway snapshots facts
|
||||||
|
community.general.scaleway_snapshot_facts:
|
||||||
|
region: par1
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = r'''
|
||||||
|
---
|
||||||
|
scaleway_snapshot_facts:
|
||||||
|
description: Response from Scaleway API
|
||||||
|
returned: success
|
||||||
|
type: complex
|
||||||
|
sample:
|
||||||
|
"scaleway_snapshot_facts": [
|
||||||
|
{
|
||||||
|
"base_volume": {
|
||||||
|
"id": "68386fae-4f55-4fbf-aabb-953036a85872",
|
||||||
|
"name": "snapshot-87fc282d-f252-4262-adad-86979d9074cf-2018-04-26_12:42"
|
||||||
|
},
|
||||||
|
"creation_date": "2018-08-14T22:34:35.299461+00:00",
|
||||||
|
"id": "b61b4b03-a2e9-4da5-b5ea-e462ac0662d2",
|
||||||
|
"modification_date": "2018-08-14T22:34:54.520560+00:00",
|
||||||
|
"name": "snapshot-87fc282d-f252-4262-adad-86979d9074cf-2018-04-26_12:42 snapshot",
|
||||||
|
"organization": "3f709602-5e6c-4619-b80c-e841c89734af",
|
||||||
|
"size": 25000000000,
|
||||||
|
"state": "available",
|
||||||
|
"volume_type": "l_ssd"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.community.general.plugins.module_utils.scaleway import (
|
||||||
|
Scaleway,
|
||||||
|
ScalewayException,
|
||||||
|
scaleway_argument_spec,
|
||||||
|
SCALEWAY_LOCATION
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ScalewaySnapshotFacts(Scaleway):
|
||||||
|
|
||||||
|
def __init__(self, module):
|
||||||
|
super(ScalewaySnapshotFacts, self).__init__(module)
|
||||||
|
self.name = 'snapshots'
|
||||||
|
|
||||||
|
region = module.params["region"]
|
||||||
|
self.module.params['api_url'] = SCALEWAY_LOCATION[region]["api_endpoint"]
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = scaleway_argument_spec()
|
||||||
|
argument_spec.update(dict(
|
||||||
|
region=dict(required=True, choices=list(SCALEWAY_LOCATION.keys())),
|
||||||
|
))
|
||||||
|
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec=argument_spec,
|
||||||
|
supports_check_mode=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
module.exit_json(
|
||||||
|
ansible_facts={'scaleway_snapshot_facts': ScalewaySnapshotFacts(module).get_resources()}
|
||||||
|
)
|
||||||
|
except ScalewayException as exc:
|
||||||
|
module.fail_json(msg=exc.message)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
108
plugins/modules/cloud/scaleway/scaleway_volume_facts.py
Normal file
108
plugins/modules/cloud/scaleway/scaleway_volume_facts.py
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# (c) 2018, Yanis Guenane <yanis+ansible@guenane.org>
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = r'''
|
||||||
|
---
|
||||||
|
module: scaleway_volume_facts
|
||||||
|
deprecated:
|
||||||
|
removed_in: 3.0.0 # was Ansible 2.13
|
||||||
|
why: Deprecated in favour of C(_info) module.
|
||||||
|
alternative: Use M(community.general.scaleway_volume_info) instead.
|
||||||
|
short_description: Gather facts about the Scaleway volumes available.
|
||||||
|
description:
|
||||||
|
- Gather facts about the Scaleway volumes available.
|
||||||
|
author:
|
||||||
|
- "Yanis Guenane (@Spredzy)"
|
||||||
|
- "Remy Leone (@sieben)"
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- community.general.scaleway
|
||||||
|
|
||||||
|
options:
|
||||||
|
region:
|
||||||
|
type: str
|
||||||
|
description:
|
||||||
|
- Scaleway region to use (for example par1).
|
||||||
|
required: true
|
||||||
|
choices:
|
||||||
|
- ams1
|
||||||
|
- EMEA-NL-EVS
|
||||||
|
- par1
|
||||||
|
- EMEA-FR-PAR1
|
||||||
|
- par2
|
||||||
|
- EMEA-FR-PAR2
|
||||||
|
- waw1
|
||||||
|
- EMEA-PL-WAW1
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = r'''
|
||||||
|
- name: Gather Scaleway volumes facts
|
||||||
|
community.general.scaleway_volume_facts:
|
||||||
|
region: par1
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = r'''
|
||||||
|
---
|
||||||
|
scaleway_volume_facts:
|
||||||
|
description: Response from Scaleway API
|
||||||
|
returned: success
|
||||||
|
type: complex
|
||||||
|
sample:
|
||||||
|
"scaleway_volume_facts": [
|
||||||
|
{
|
||||||
|
"creation_date": "2018-08-14T20:56:24.949660+00:00",
|
||||||
|
"export_uri": null,
|
||||||
|
"id": "b8d51a06-daeb-4fef-9539-a8aea016c1ba",
|
||||||
|
"modification_date": "2018-08-14T20:56:24.949660+00:00",
|
||||||
|
"name": "test-volume",
|
||||||
|
"organization": "3f709602-5e6c-4619-b80c-e841c89734af",
|
||||||
|
"server": null,
|
||||||
|
"size": 50000000000,
|
||||||
|
"state": "available",
|
||||||
|
"volume_type": "l_ssd"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.community.general.plugins.module_utils.scaleway import (
|
||||||
|
Scaleway, ScalewayException, scaleway_argument_spec,
|
||||||
|
SCALEWAY_LOCATION)
|
||||||
|
|
||||||
|
|
||||||
|
class ScalewayVolumeFacts(Scaleway):
|
||||||
|
|
||||||
|
def __init__(self, module):
|
||||||
|
super(ScalewayVolumeFacts, self).__init__(module)
|
||||||
|
self.name = 'volumes'
|
||||||
|
|
||||||
|
region = module.params["region"]
|
||||||
|
self.module.params['api_url'] = SCALEWAY_LOCATION[region]["api_endpoint"]
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = scaleway_argument_spec()
|
||||||
|
argument_spec.update(dict(
|
||||||
|
region=dict(required=True, choices=list(SCALEWAY_LOCATION.keys())),
|
||||||
|
))
|
||||||
|
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec=argument_spec,
|
||||||
|
supports_check_mode=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
module.exit_json(
|
||||||
|
ansible_facts={'scaleway_volume_facts': ScalewayVolumeFacts(module).get_resources()}
|
||||||
|
)
|
||||||
|
except ScalewayException as exc:
|
||||||
|
module.fail_json(msg=exc.message)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
@@ -119,13 +119,20 @@ class NicTag(object):
|
|||||||
return is_mac(self.mac.lower())
|
return is_mac(self.mac.lower())
|
||||||
|
|
||||||
def nictag_exists(self):
|
def nictag_exists(self):
|
||||||
cmd = [self.nictagadm_bin, 'exists', self.name]
|
cmd = [self.nictagadm_bin]
|
||||||
|
|
||||||
|
cmd.append('exists')
|
||||||
|
cmd.append(self.name)
|
||||||
|
|
||||||
(rc, dummy, dummy) = self.module.run_command(cmd)
|
(rc, dummy, dummy) = self.module.run_command(cmd)
|
||||||
|
|
||||||
return rc == 0
|
return rc == 0
|
||||||
|
|
||||||
def add_nictag(self):
|
def add_nictag(self):
|
||||||
cmd = [self.nictagadm_bin, '-v', 'add']
|
cmd = [self.nictagadm_bin]
|
||||||
|
|
||||||
|
cmd.append('-v')
|
||||||
|
cmd.append('add')
|
||||||
|
|
||||||
if self.etherstub:
|
if self.etherstub:
|
||||||
cmd.append('-l')
|
cmd.append('-l')
|
||||||
@@ -143,7 +150,10 @@ class NicTag(object):
|
|||||||
return self.module.run_command(cmd)
|
return self.module.run_command(cmd)
|
||||||
|
|
||||||
def delete_nictag(self):
|
def delete_nictag(self):
|
||||||
cmd = [self.nictagadm_bin, '-v', 'delete']
|
cmd = [self.nictagadm_bin]
|
||||||
|
|
||||||
|
cmd.append('-v')
|
||||||
|
cmd.append('delete')
|
||||||
|
|
||||||
if self.force:
|
if self.force:
|
||||||
cmd.append('-f')
|
cmd.append('-f')
|
||||||
|
|||||||
1
plugins/modules/cloud/smartos/smartos_image_facts.py
Symbolic link
1
plugins/modules/cloud/smartos/smartos_image_facts.py
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
smartos_image_info.py
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user