mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-04-28 17:36:49 +00:00
Compare commits
188 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
72c1a17bd9 | ||
|
|
694584f907 | ||
|
|
73e2c2eb85 | ||
|
|
f3ddc8757d | ||
|
|
9241b853c0 | ||
|
|
1053b3c658 | ||
|
|
d9daa6b851 | ||
|
|
a876fa0262 | ||
|
|
f64ace97af | ||
|
|
b701b5893f | ||
|
|
24667e12d0 | ||
|
|
9d93760564 | ||
|
|
ec78558559 | ||
|
|
d5c8d7ddcc | ||
|
|
6338048c73 | ||
|
|
92b388817f | ||
|
|
c72b337327 | ||
|
|
e5080b7847 | ||
|
|
079925fe66 | ||
|
|
19a87874f7 | ||
|
|
809cdda9ef | ||
|
|
bec6f732ad | ||
|
|
d2cdca416c | ||
|
|
0f1ccc07c5 | ||
|
|
deb1071666 | ||
|
|
eb9c5eb796 | ||
|
|
5c8504323e | ||
|
|
ab391c2cfa | ||
|
|
a14b525bdc | ||
|
|
996ef6ab49 | ||
|
|
055c8dac9c | ||
|
|
f4a9c7cc8b | ||
|
|
0c1f96290a | ||
|
|
d260f7ffda | ||
|
|
35d81adabf | ||
|
|
10a61c9dc3 | ||
|
|
6f47bcc399 | ||
|
|
7140b456ae | ||
|
|
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-*
|
||||
|
||||
schedules:
|
||||
- cron: 0 8 * * *
|
||||
displayName: Nightly (main)
|
||||
- cron: 0 9 * * *
|
||||
displayName: Nightly
|
||||
always: true
|
||||
branches:
|
||||
include:
|
||||
- main
|
||||
- cron: 0 10 * * *
|
||||
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
|
||||
- stable-*
|
||||
|
||||
variables:
|
||||
- name: checkoutPath
|
||||
@@ -187,10 +175,10 @@ stages:
|
||||
test: rhel/7.9
|
||||
- name: RHEL 8.3
|
||||
test: rhel/8.3
|
||||
- name: FreeBSD 11.4
|
||||
test: freebsd/11.4
|
||||
- name: FreeBSD 12.2
|
||||
test: freebsd/12.2
|
||||
- name: FreeBSD 13.0
|
||||
test: freebsd/13.0
|
||||
groups:
|
||||
- 1
|
||||
- 2
|
||||
@@ -268,10 +256,10 @@ stages:
|
||||
test: centos7
|
||||
- name: CentOS 8
|
||||
test: centos8
|
||||
- name: Fedora 32
|
||||
test: fedora32
|
||||
- name: Fedora 33
|
||||
test: fedora33
|
||||
- name: Fedora 34
|
||||
test: fedora34
|
||||
- name: openSUSE 15 py2
|
||||
test: opensuse15py2
|
||||
- name: openSUSE 15 py3
|
||||
@@ -294,7 +282,7 @@ stages:
|
||||
targets:
|
||||
- name: CentOS 8
|
||||
test: centos8
|
||||
- name: Fedora 33
|
||||
- name: Fedora 32
|
||||
test: fedora33
|
||||
- name: openSUSE 15 py3
|
||||
test: opensuse15
|
||||
|
||||
@@ -7,7 +7,7 @@ set -o pipefail -eu
|
||||
|
||||
output_path="$1"
|
||||
|
||||
curl --silent --show-error https://ansible-ci-files.s3.us-east-1.amazonaws.com/codecov/codecov.sh > codecov.sh
|
||||
curl --silent --show-error https://codecov.io/bash > codecov.sh
|
||||
|
||||
for file in "${output_path}"/reports/coverage*.xml; do
|
||||
name="${file}"
|
||||
|
||||
77
.github/BOTMETA.yml
vendored
77
.github/BOTMETA.yml
vendored
@@ -17,8 +17,6 @@ files:
|
||||
labels: become
|
||||
$callbacks/:
|
||||
labels: callbacks
|
||||
$callbacks/loganalytics.py:
|
||||
maintainers: zhcli
|
||||
$callbacks/logstash.py:
|
||||
maintainers: ujenmr
|
||||
$callbacks/say.py:
|
||||
@@ -61,10 +59,6 @@ files:
|
||||
maintainers: felixfontein
|
||||
$filters/dict_kv.py:
|
||||
maintainers: giner
|
||||
$filters/from_csv.py:
|
||||
maintainers: Ajpantuso
|
||||
$filters/hashids:
|
||||
maintainers: Ajpantuso
|
||||
$filters/jc.py:
|
||||
maintainers: kellyjonbrazil
|
||||
$filters/list.py:
|
||||
@@ -73,8 +67,6 @@ files:
|
||||
maintainers: felixfontein
|
||||
$filters/time.py:
|
||||
maintainers: resmo
|
||||
$filters/version_sort.py:
|
||||
maintainers: ericzolf
|
||||
$httpapis/:
|
||||
maintainers: $team_networking
|
||||
labels: networking
|
||||
@@ -88,10 +80,6 @@ files:
|
||||
maintainers: $team_linode
|
||||
labels: cloud linode
|
||||
keywords: linode dynamic inventory script
|
||||
$inventories/lxd.py:
|
||||
maintainers: conloos
|
||||
$inventories/proxmox.py:
|
||||
maintainers: $team_virt ilijamt
|
||||
$inventories/scaleway.py:
|
||||
maintainers: $team_scaleway
|
||||
labels: cloud scaleway
|
||||
@@ -157,6 +145,7 @@ files:
|
||||
$module_utils/redfish_utils.py:
|
||||
maintainers: $team_redfish
|
||||
labels: redfish_utils
|
||||
$module_utils/remote_management/dellemc/: rajeevarakkal
|
||||
$module_utils/remote_management/lxca/common.py: navalkp prabhosa
|
||||
$module_utils/scaleway.py:
|
||||
maintainers: $team_scaleway
|
||||
@@ -192,14 +181,14 @@ files:
|
||||
maintainers: zbal
|
||||
$modules/cloud/lxc/lxc_container.py:
|
||||
maintainers: cloudnull
|
||||
$modules/cloud/lxc/lxc_profile.py:
|
||||
maintainers: conloos
|
||||
$modules/cloud/lxd/:
|
||||
ignore: hnakamur
|
||||
$modules/cloud/memset/:
|
||||
maintainers: glitchcrab
|
||||
$modules/cloud/misc/cloud_init_data_facts.py:
|
||||
maintainers: resmo
|
||||
$modules/cloud/misc/helm.py:
|
||||
maintainers: flaper87
|
||||
$modules/cloud/misc/proxmox.py:
|
||||
maintainers: $team_virt UnderGreen
|
||||
labels: proxmox virt
|
||||
@@ -227,7 +216,7 @@ files:
|
||||
$modules/cloud/misc/:
|
||||
ignore: ryansb
|
||||
$modules/cloud/misc/terraform.py:
|
||||
maintainers: m-yosefpor rainerleber
|
||||
maintainers: m-yosefpor
|
||||
$modules/cloud/misc/xenserver_facts.py:
|
||||
maintainers: caphrim007 cheese
|
||||
labels: xenserver_facts
|
||||
@@ -311,7 +300,6 @@ files:
|
||||
maintainers: bvitnik
|
||||
$modules/clustering/consul/:
|
||||
maintainers: $team_consul
|
||||
ignore: colin-nolan
|
||||
$modules/clustering/etcd3.py:
|
||||
maintainers: evrardjp
|
||||
ignore: vfauth
|
||||
@@ -348,8 +336,6 @@ files:
|
||||
maintainers: dareko
|
||||
$modules/files/archive.py:
|
||||
maintainers: bendoh
|
||||
$modules/files/filesize.py:
|
||||
maintainers: quidame
|
||||
$modules/files/ini_file.py:
|
||||
maintainers: jpmens noseka1
|
||||
$modules/files/iso_extract.py:
|
||||
@@ -363,6 +349,8 @@ files:
|
||||
maintainers: dagwieers magnus919 tbielawa cmprescott sm4rk0
|
||||
labels: m:xml xml
|
||||
ignore: magnus919
|
||||
$modules/identity/onepassword_facts.py:
|
||||
maintainers: Rylon
|
||||
$modules/identity/ipa/:
|
||||
maintainers: $team_ipa
|
||||
$modules/identity/ipa/ipa_pwpolicy.py:
|
||||
@@ -375,8 +363,6 @@ files:
|
||||
maintainers: $team_keycloak
|
||||
$modules/identity/keycloak/keycloak_group.py:
|
||||
maintainers: adamgoossens
|
||||
$modules/identity/keycloak/keycloak_realm.py:
|
||||
maintainers: kris2kris
|
||||
$modules/identity/onepassword_info.py:
|
||||
maintainers: Rylon
|
||||
$modules/identity/opendj/opendj_backendprop.py:
|
||||
@@ -438,8 +424,6 @@ files:
|
||||
maintainers: andsens
|
||||
$modules/monitoring/spectrum_device.py:
|
||||
maintainers: orgito
|
||||
$modules/monitoring/spectrum_model_attrs.py:
|
||||
maintainers: tgates81
|
||||
$modules/monitoring/stackdriver.py:
|
||||
maintainers: bwhaley
|
||||
$modules/monitoring/statsd.py:
|
||||
@@ -456,7 +440,7 @@ files:
|
||||
$modules/net_tools/dnsmadeeasy.py:
|
||||
maintainers: briceburg
|
||||
$modules/net_tools/haproxy.py:
|
||||
maintainers: ravibhure Normo
|
||||
maintainers: ravibhure
|
||||
$modules/net_tools/:
|
||||
maintainers: nerzhul
|
||||
$modules/net_tools/infinity/infinity.py:
|
||||
@@ -469,6 +453,8 @@ files:
|
||||
maintainers: akostyuk
|
||||
$modules/net_tools/ipwcli_dns.py:
|
||||
maintainers: cwollinger
|
||||
$modules/net_tools/ldap/ldap_attr.py:
|
||||
maintainers: jtyr
|
||||
$modules/net_tools/ldap/ldap_attrs.py:
|
||||
maintainers: drybjed jtyr noles
|
||||
$modules/net_tools/ldap/ldap_entry.py:
|
||||
@@ -564,10 +550,9 @@ files:
|
||||
$modules/packaging/language/bundler.py:
|
||||
maintainers: thoiberg
|
||||
$modules/packaging/language/composer.py:
|
||||
maintainers: dmtrs
|
||||
ignore: resmo
|
||||
maintainers: dmtrs resmo
|
||||
$modules/packaging/language/cpanm.py:
|
||||
maintainers: fcuny russoz
|
||||
maintainers: fcuny
|
||||
$modules/packaging/language/easy_install.py:
|
||||
maintainers: mattupstate
|
||||
$modules/packaging/language/gem.py:
|
||||
@@ -712,10 +697,15 @@ files:
|
||||
labels: zypper
|
||||
ignore: dirtyharrycallahan robinro
|
||||
$modules/packaging/os/zypper_repository.py:
|
||||
maintainers: $team_suse matze
|
||||
labels: zypper
|
||||
maintainers: matze
|
||||
$modules/remote_management/cobbler/:
|
||||
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/:
|
||||
maintainers: haad
|
||||
ignore: dagwieers
|
||||
@@ -735,6 +725,8 @@ files:
|
||||
maintainers: evertmulder
|
||||
$modules/remote_management/manageiq/manageiq_tenant.py:
|
||||
maintainers: evertmulder
|
||||
$modules/remote_management/oneview/oneview_datacenter_facts.py:
|
||||
maintainers: aalexmonteiro madhav-bharadwaj ricardogpsf soodpr
|
||||
$modules/remote_management/oneview/:
|
||||
maintainers: adriane-cardozo fgbulsoni tmiotto
|
||||
$modules/remote_management/oneview/oneview_datacenter_info.py:
|
||||
@@ -767,8 +759,6 @@ files:
|
||||
ignore: erydo
|
||||
$modules/source_control/github/github_release.py:
|
||||
maintainers: adrianmoisey
|
||||
$modules/source_control/github/github_repo.py:
|
||||
maintainers: atorrescogollo
|
||||
$modules/source_control/github/:
|
||||
maintainers: stpierre
|
||||
$modules/source_control/gitlab/:
|
||||
@@ -783,6 +773,12 @@ files:
|
||||
maintainers: yeukhon
|
||||
$modules/storage/emc/emc_vnx_sg_member.py:
|
||||
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:
|
||||
maintainers: farhan7500 gautamphegde
|
||||
$modules/storage/ibm/:
|
||||
@@ -804,6 +800,9 @@ files:
|
||||
maintainers: johanwiren
|
||||
$modules/storage/zfs/zfs_delegate_admin.py:
|
||||
maintainers: natefoo
|
||||
$modules/system/python_requirements_facts.py:
|
||||
maintainers: willthames
|
||||
ignore: ryansb
|
||||
$modules/system/aix:
|
||||
maintainers: $team_aix
|
||||
labels: aix
|
||||
@@ -843,7 +842,7 @@ files:
|
||||
$modules/system/iptables_state.py:
|
||||
maintainers: quidame
|
||||
$modules/system/java_cert.py:
|
||||
maintainers: haad absynth76
|
||||
maintainers: haad
|
||||
$modules/system/java_keystore.py:
|
||||
maintainers: Mogztter
|
||||
$modules/system/kernel_blacklist.py:
|
||||
@@ -934,6 +933,10 @@ files:
|
||||
labels: xfconf
|
||||
$modules/system/xfs_quota.py:
|
||||
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:
|
||||
maintainers: oboukili
|
||||
$modules/web_infrastructure/apache2_module.py:
|
||||
@@ -1009,14 +1012,14 @@ macros:
|
||||
terminals: plugins/terminal
|
||||
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_consul: sgargan
|
||||
team_consul: colin-nolan sgargan
|
||||
team_cyberark_conjur: jvanderhoof ryanprior
|
||||
team_e_spirit: MatrixCrawler getjack
|
||||
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_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_keycloak: eikef ndclt
|
||||
team_linode: InTheCloudDan decentral1se displague rmcintosh Charliekenney23 LBGarber
|
||||
@@ -1024,12 +1027,12 @@ macros:
|
||||
team_manageiq: abellotti cben gtanzillo yaacov zgalor dkorn evertmulder
|
||||
team_netapp: amit0701 carchi8py hulquest lmprice lonico ndswartz schmots1
|
||||
team_networking: NilashishC Qalthos danielmellado ganeshrn justjais trishnaguha sganesh-infoblox privateip
|
||||
team_opennebula: ilicmilan meerkampdvv rsmontero xorel nilsding
|
||||
team_opennebula: ilicmilan meerkampdvv rsmontero xorel
|
||||
team_oracle: manojmeda mross22 nalsaber
|
||||
team_purestorage: bannaych dnix101 genegr lionmax opslounge raekins sdodsley sile16
|
||||
team_redfish: mraineri tomasg2012 xmadsen renxulei
|
||||
team_rhn: FlossWare alikins barnabycourt vritant
|
||||
team_scaleway: QuentinBrosse abarbare jerome-quere kindermoumoute remyleone sieben
|
||||
team_solaris: bcoca fishman jasperla jpdasma mator scathatheworm troy2914 xen0l
|
||||
team_suse: commel dcermak evrardjp lrupp toabctl AnderEnder alxgu andytom sealor
|
||||
team_virt: joshainglis karmab tleguern Thulium-Drake Ajpantuso
|
||||
team_suse: commel dcermak evrardjp lrupp toabctl AnderEnder alxgu andytom
|
||||
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
|
||||
...
|
||||
1298
CHANGELOG.rst
1298
CHANGELOG.rst
File diff suppressed because it is too large
Load Diff
@@ -1,14 +1,12 @@
|
||||
# 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)
|
||||
|
||||
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/).
|
||||
|
||||
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 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.
|
||||
@@ -78,7 +76,7 @@ Basic instructions without release branches:
|
||||
|
||||
## 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
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
namespace: community
|
||||
name: general
|
||||
version: 3.0.2
|
||||
version: 2.5.0
|
||||
readme: README.md
|
||||
authors:
|
||||
- Ansible (https://github.com/ansible)
|
||||
|
||||
166
meta/runtime.yml
166
meta/runtime.yml
@@ -39,7 +39,7 @@ plugin_routing:
|
||||
redirect: community.hashi_vault.hashi_vault
|
||||
modules:
|
||||
ali_instance_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.ali_instance_info instead.
|
||||
docker_compose:
|
||||
@@ -159,7 +159,8 @@ plugin_routing:
|
||||
gcpubsub_info:
|
||||
redirect: community.google.gcpubsub_info
|
||||
gcpubsub_facts:
|
||||
tombstone:
|
||||
redirect: community.google.gcpubsub_info
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.google.gcpubsub_info instead.
|
||||
gcspanner:
|
||||
@@ -170,23 +171,22 @@ plugin_routing:
|
||||
tombstone:
|
||||
removal_version: 2.0.0
|
||||
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:
|
||||
# tombstone:
|
||||
# removal_version: 3.0.0
|
||||
# warning_text: The gluster modules have migrated to the gluster.gluster collection. Use gluster.gluster.gluster_heal_info instead.
|
||||
# gluster_peer:
|
||||
# tombstone:
|
||||
# removal_version: 3.0.0
|
||||
# warning_text: The gluster modules have migrated to the gluster.gluster collection. Use gluster.gluster.gluster_peer instead.
|
||||
# gluster_volume:
|
||||
# tombstone:
|
||||
# removal_version: 3.0.0
|
||||
# warning_text: The gluster modules have migrated to the gluster.gluster collection. Use gluster.gluster.gluster_volume instead.
|
||||
# helm:
|
||||
# tombstone:
|
||||
# removal_version: 3.0.0
|
||||
# warning_text: Use community.kubernetes.helm instead.
|
||||
gluster_heal_info:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: The gluster modules have migrated to the gluster.gluster collection. Use gluster.gluster.gluster_heal_info instead.
|
||||
gluster_peer:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: The gluster modules have migrated to the gluster.gluster collection. Use gluster.gluster.gluster_peer instead.
|
||||
gluster_volume:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: The gluster modules have migrated to the gluster.gluster collection. Use gluster.gluster.gluster_volume instead.
|
||||
helm:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: The helm module in community.general has been deprecated. Use community.kubernetes.helm instead.
|
||||
hetzner_failover_ip:
|
||||
redirect: community.hrobot.failover_ip
|
||||
hetzner_failover_ip_info:
|
||||
@@ -196,19 +196,15 @@ plugin_routing:
|
||||
hetzner_firewall_info:
|
||||
redirect: community.hrobot.firewall_info
|
||||
hpilo_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.hpilo_info instead.
|
||||
idrac_firmware:
|
||||
redirect: dellemc.openmanage.idrac_firmware
|
||||
idrac_redfish_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.idrac_redfish_info instead.
|
||||
idrac_server_config_profile:
|
||||
redirect: dellemc.openmanage.idrac_server_config_profile
|
||||
jenkins_job_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.jenkins_job_info instead.
|
||||
katello:
|
||||
@@ -228,7 +224,7 @@ plugin_routing:
|
||||
kubevirt_vm:
|
||||
redirect: community.kubevirt.kubevirt_vm
|
||||
ldap_attr:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.ldap_attrs instead.
|
||||
logicmonitor:
|
||||
@@ -240,11 +236,11 @@ plugin_routing:
|
||||
removal_version: 1.0.0
|
||||
warning_text: The logicmonitor_facts module is no longer maintained and the API used has been disabled in 2017.
|
||||
memset_memstore_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.memset_memstore_info instead.
|
||||
memset_server_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.memset_server_info instead.
|
||||
na_cdot_aggregate:
|
||||
@@ -280,161 +276,159 @@ plugin_routing:
|
||||
removal_version: 2.0.0
|
||||
warning_text: Use netapp.ontap.na_ontap_volume instead.
|
||||
na_ontap_gather_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use netapp.ontap.na_ontap_info instead.
|
||||
nginx_status_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.nginx_status_info instead.
|
||||
ome_device_info:
|
||||
redirect: dellemc.openmanage.ome_device_info
|
||||
one_image_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.one_image_info instead.
|
||||
onepassword_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.onepassword_info instead.
|
||||
oneview_datacenter_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.oneview_datacenter_info instead.
|
||||
oneview_enclosure_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.oneview_enclosure_info instead.
|
||||
oneview_ethernet_network_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.oneview_ethernet_network_info instead.
|
||||
oneview_fc_network_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.oneview_fc_network_info instead.
|
||||
oneview_fcoe_network_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.oneview_fcoe_network_info instead.
|
||||
oneview_logical_interconnect_group_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.oneview_logical_interconnect_group_info instead.
|
||||
oneview_network_set_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.oneview_network_set_info instead.
|
||||
oneview_san_manager_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.oneview_san_manager_info instead.
|
||||
online_server_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.online_server_info instead.
|
||||
online_user_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.online_user_info instead.
|
||||
ovirt:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_vm instead.
|
||||
ovirt_affinity_label_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_affinity_label_info instead.
|
||||
ovirt_api_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_api_info instead.
|
||||
ovirt_cluster_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_cluster_info instead.
|
||||
ovirt_datacenter_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_datacenter_info instead.
|
||||
ovirt_disk_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_disk_info instead.
|
||||
ovirt_event_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_event_info instead.
|
||||
ovirt_external_provider_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_external_provider_info instead.
|
||||
ovirt_group_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_group_info instead.
|
||||
ovirt_host_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_host_info instead.
|
||||
ovirt_host_storage_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_host_storage_info instead.
|
||||
ovirt_network_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_network_info instead.
|
||||
ovirt_nic_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_nic_info instead.
|
||||
ovirt_permission_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_permission_info instead.
|
||||
ovirt_quota_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_quota_info instead.
|
||||
ovirt_scheduling_policy_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_scheduling_policy_info instead.
|
||||
ovirt_snapshot_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_snapshot_info instead.
|
||||
ovirt_storage_domain_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_storage_domain_info instead.
|
||||
ovirt_storage_template_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_storage_template_info instead.
|
||||
ovirt_storage_vm_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_storage_vm_info instead.
|
||||
ovirt_tag_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_tag_info instead.
|
||||
ovirt_template_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_template_info instead.
|
||||
ovirt_user_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_user_info instead.
|
||||
ovirt_vm_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_vm_info instead.
|
||||
ovirt_vmpool_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_vmpool_info instead.
|
||||
postgresql_copy:
|
||||
@@ -482,47 +476,47 @@ plugin_routing:
|
||||
postgresql_user:
|
||||
redirect: community.postgresql.postgresql_user
|
||||
purefa_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use purestorage.flasharray.purefa_info instead.
|
||||
purefb_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use purestorage.flashblade.purefb_info instead.
|
||||
python_requirements_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.python_requirements_info instead.
|
||||
redfish_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.redfish_info instead.
|
||||
scaleway_image_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.scaleway_image_info instead.
|
||||
scaleway_ip_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.scaleway_ip_info instead.
|
||||
scaleway_organization_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.scaleway_organization_info instead.
|
||||
scaleway_security_group_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.scaleway_security_group_info instead.
|
||||
scaleway_server_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.scaleway_server_info instead.
|
||||
scaleway_snapshot_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.scaleway_snapshot_info instead.
|
||||
scaleway_volume_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.scaleway_volume_info instead.
|
||||
sf_account_manager:
|
||||
@@ -546,15 +540,15 @@ plugin_routing:
|
||||
removal_version: 2.0.0
|
||||
warning_text: Use netapp.elementsw.na_elementsw_volume instead.
|
||||
smartos_image_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.smartos_image_info instead.
|
||||
vertica_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.vertica_info instead.
|
||||
xenserver_guest_facts:
|
||||
tombstone:
|
||||
deprecation:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.xenserver_guest_info instead.
|
||||
doc_fragments:
|
||||
@@ -571,8 +565,6 @@ plugin_routing:
|
||||
postgresql:
|
||||
redirect: community.postgresql.postgresql
|
||||
module_utils:
|
||||
remote_management.dellemc.dellemc_idrac:
|
||||
redirect: dellemc.openmanage.dellemc_idrac
|
||||
docker.common:
|
||||
redirect: community.docker.common
|
||||
docker.swarm:
|
||||
@@ -587,8 +579,6 @@ plugin_routing:
|
||||
redirect: community.hrobot.robot
|
||||
kubevirt:
|
||||
redirect: community.kubevirt.kubevirt
|
||||
remote_management.dellemc.ome:
|
||||
redirect: dellemc.openmanage.ome
|
||||
postgresql:
|
||||
redirect: community.postgresql.postgresql
|
||||
callback:
|
||||
|
||||
@@ -5,7 +5,7 @@ from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = """
|
||||
name: sudosu
|
||||
become: sudosu
|
||||
short_description: Run tasks using sudo su -
|
||||
description:
|
||||
- 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
|
||||
|
||||
DOCUMENTATION = '''
|
||||
name: loganalytics
|
||||
callback: loganalytics
|
||||
type: aggregate
|
||||
short_description: Posts task results to Azure Log Analytics
|
||||
author: "Cyrus Li (@zhcli) <cyrus1006@gmail.com>"
|
||||
|
||||
@@ -37,13 +37,12 @@ import tempfile
|
||||
import shutil
|
||||
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.plugins.connection import ConnectionBase
|
||||
from ansible.utils.display import Display
|
||||
|
||||
display = Display()
|
||||
|
||||
|
||||
class Connection(ConnectionBase):
|
||||
class Connection(object):
|
||||
''' Func-based connections '''
|
||||
|
||||
has_pipelining = False
|
||||
|
||||
@@ -30,6 +30,7 @@ options:
|
||||
description:
|
||||
- Keycloak realm name to authenticate to for API access.
|
||||
type: str
|
||||
required: true
|
||||
|
||||
auth_client_secret:
|
||||
description:
|
||||
@@ -40,6 +41,7 @@ options:
|
||||
description:
|
||||
- Username to authenticate for API access with.
|
||||
type: str
|
||||
required: true
|
||||
aliases:
|
||||
- username
|
||||
|
||||
@@ -47,15 +49,10 @@ options:
|
||||
description:
|
||||
- Password to authenticate for API access with.
|
||||
type: str
|
||||
required: true
|
||||
aliases:
|
||||
- password
|
||||
|
||||
token:
|
||||
description:
|
||||
- Authentication token for Keycloak API.
|
||||
type: str
|
||||
version_added: 3.0.0
|
||||
|
||||
validate_certs:
|
||||
description:
|
||||
- Verify TLS certificates (do not disable this in production).
|
||||
|
||||
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,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,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
|
||||
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):
|
||||
|
||||
valid = False
|
||||
@@ -101,7 +82,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
|
||||
return valid
|
||||
|
||||
def parse(self, inventory, loader, path, cache=True):
|
||||
def parse(self, inventory, loader, path, cache=False):
|
||||
|
||||
try:
|
||||
self._nmap = get_bin_path('nmap')
|
||||
@@ -112,101 +93,75 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
|
||||
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
|
||||
# get the user's cache option too to see if we should save the cache if it is changing
|
||||
user_cache_setting = self.get_option('cache')
|
||||
if self._options['ipv4'] and not self._options['ipv6']:
|
||||
cmd.append('-4')
|
||||
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
|
||||
attempt_to_read_cache = user_cache_setting and cache
|
||||
# update if the user has caching enabled and the cache is being refreshed; update this value to True if the cache has expired below
|
||||
cache_needs_update = user_cache_setting and not cache
|
||||
if self._options['exclude']:
|
||||
cmd.append('--exclude')
|
||||
cmd.append(','.join(self._options['exclude']))
|
||||
|
||||
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:
|
||||
results = self._cache[cache_key]
|
||||
except KeyError:
|
||||
# This occurs if the cache_key is not in the cache or if the cache_key expired, so the cache needs to be updated
|
||||
cache_needs_update = True
|
||||
t_stdout = to_text(stdout, errors='surrogate_or_strict')
|
||||
except UnicodeError as e:
|
||||
raise AnsibleParserError('Invalid (non unicode) input returned: %s' % to_native(e))
|
||||
|
||||
if cache_needs_update:
|
||||
# setup command
|
||||
cmd = [self._nmap]
|
||||
if not self._options['ports']:
|
||||
cmd.append('-sP')
|
||||
for line in t_stdout.splitlines():
|
||||
hits = self.find_host.match(line)
|
||||
if hits:
|
||||
if host is not None:
|
||||
self.inventory.set_variable(host, 'ports', ports)
|
||||
|
||||
if self._options['ipv4'] and not self._options['ipv6']:
|
||||
cmd.append('-4')
|
||||
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')
|
||||
# if dns only shows arpa, just use ip instead as hostname
|
||||
if hits.group(1).endswith('.in-addr.arpa'):
|
||||
host = hits.group(2)
|
||||
else:
|
||||
host = hits.group(1)
|
||||
|
||||
if self._options['exclude']:
|
||||
cmd.append('--exclude')
|
||||
cmd.append(','.join(self._options['exclude']))
|
||||
# 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)
|
||||
|
||||
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)))
|
||||
if host is not None:
|
||||
# update inventory
|
||||
self.inventory.add_host(host)
|
||||
self.inventory.set_variable(host, 'ip', ip)
|
||||
ports = []
|
||||
continue
|
||||
|
||||
# parse results
|
||||
host = None
|
||||
ip = None
|
||||
ports = []
|
||||
results = []
|
||||
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
|
||||
|
||||
try:
|
||||
t_stdout = to_text(stdout, errors='surrogate_or_strict')
|
||||
except UnicodeError as e:
|
||||
raise AnsibleParserError('Invalid (non unicode) input returned: %s' % to_native(e))
|
||||
# TODO: parse more data, OS?
|
||||
|
||||
for line in t_stdout.splitlines():
|
||||
hits = self.find_host.match(line)
|
||||
if hits:
|
||||
if host is not None and ports:
|
||||
results[-1]['ports'] = ports
|
||||
# if any leftovers
|
||||
if host and ports:
|
||||
self.inventory.set_variable(host, 'ports', ports)
|
||||
|
||||
# if dns only shows arpa, just use ip instead as hostname
|
||||
if hits.group(1).endswith('.in-addr.arpa'):
|
||||
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)
|
||||
except Exception as e:
|
||||
raise AnsibleParserError("failed to parse %s: %s " % (to_native(path), to_native(e)))
|
||||
|
||||
@@ -70,13 +70,6 @@ DOCUMENTATION = '''
|
||||
description: Gather LXC/QEMU configuration facts.
|
||||
default: no
|
||||
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:
|
||||
@@ -241,22 +234,13 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
)
|
||||
)['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 []
|
||||
'mac-address': iface['hardware-address'],
|
||||
'ip-addresses': [
|
||||
"%s/%s" % (ip['ip-address'], ip['prefix']) for ip in iface['ip-addresses']
|
||||
]
|
||||
})
|
||||
except requests.HTTPError:
|
||||
pass
|
||||
@@ -297,9 +281,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
parsed_value = [tag.strip() for tag in value.split(",")]
|
||||
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]):
|
||||
if config == 'agent' and int(value):
|
||||
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:
|
||||
@@ -370,9 +352,8 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
self.inventory.add_child(nodes_group, node['node'])
|
||||
|
||||
# get node IP address
|
||||
if self.get_option("want_proxmox_nodes_ansible_host"):
|
||||
ip = self._get_node_ip(node['node'])
|
||||
self.inventory.set_variable(node['node'], 'ansible_host', ip)
|
||||
ip = self._get_node_ip(node['node'])
|
||||
self.inventory.set_variable(node['node'], 'ansible_host', ip)
|
||||
|
||||
# get LXC containers for this node
|
||||
node_lxc_group = self.to_safe('%s%s' % (self.get_option('group_prefix'), ('%s_lxc' % node['node']).lower()))
|
||||
|
||||
@@ -102,13 +102,13 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
raise AnsibleError("plugin doesn't match this plugin")
|
||||
try:
|
||||
client_id = config['client_id']
|
||||
if len(client_id) != 32:
|
||||
if client_id != 32:
|
||||
raise AnsibleError("client_id must be 32 characters long")
|
||||
except KeyError:
|
||||
raise AnsibleError("config missing client_id, a required option")
|
||||
try:
|
||||
client_secret = config['client_secret']
|
||||
if len(client_secret) != 64:
|
||||
if client_secret != 64:
|
||||
raise AnsibleError("client_secret must be 64 characters long")
|
||||
except KeyError:
|
||||
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)
|
||||
ansible.builtin.template:
|
||||
src: '{{ item.src }}'
|
||||
# Your template files should be stored with a .j2 file extension,
|
||||
# but should not be deployed with it. splitext|first removes it.
|
||||
dest: /web/{{ item.path | splitext | first }}
|
||||
dest: /web/{{ item.path }}
|
||||
mode: '{{ item.mode }}'
|
||||
with_community.general.filetree: web/
|
||||
when: item.state == 'file'
|
||||
@@ -43,7 +41,6 @@ EXAMPLES = r"""
|
||||
src: '{{ item.src }}'
|
||||
dest: /web/{{ item.path }}
|
||||
state: link
|
||||
follow: false # avoid corrupting target files if the link already exists
|
||||
force: yes
|
||||
mode: '{{ item.mode }}'
|
||||
with_community.general.filetree: web/
|
||||
|
||||
@@ -63,7 +63,6 @@ import os
|
||||
|
||||
from ansible.plugins.lookup import LookupBase
|
||||
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_BIN = os.getenv('ANSIBLE_HIERA_BIN', '/usr/bin/hiera')
|
||||
@@ -79,7 +78,7 @@ class Hiera(object):
|
||||
rc, output, err = run_cmd("{0} -c {1} {2}".format(
|
||||
ANSIBLE_HIERA_BIN, ANSIBLE_HIERA_CFG, hiera_key[0]))
|
||||
|
||||
return to_text(output.strip())
|
||||
return output.strip()
|
||||
|
||||
|
||||
class LookupModule(LookupBase):
|
||||
|
||||
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
|
||||
|
||||
import json
|
||||
import traceback
|
||||
|
||||
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.error import HTTPError
|
||||
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_CLIENT = "{url}/admin/realms/{realm}/clients/{id}"
|
||||
URL_CLIENTS = "{url}/admin/realms/{realm}/clients"
|
||||
@@ -61,12 +57,11 @@ def keycloak_argument_spec():
|
||||
return dict(
|
||||
auth_keycloak_url=dict(type='str', aliases=['url'], required=True, no_log=False),
|
||||
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_username=dict(type='str', aliases=['username']),
|
||||
auth_password=dict(type='str', aliases=['password'], no_log=True),
|
||||
validate_certs=dict(type='bool', default=True),
|
||||
token=dict(type='str', no_log=True),
|
||||
auth_username=dict(type='str', aliases=['username'], required=True),
|
||||
auth_password=dict(type='str', aliases=['password'], required=True, no_log=True),
|
||||
validate_certs=dict(type='bool', default=True)
|
||||
)
|
||||
|
||||
|
||||
@@ -78,58 +73,41 @@ class KeycloakError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def get_token(module_params):
|
||||
""" Obtains connection header with token for the authentication,
|
||||
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')
|
||||
|
||||
def get_token(base_url, validate_certs, auth_realm, client_id,
|
||||
auth_username, auth_password, client_secret):
|
||||
if not base_url.lower().startswith(('http', 'https')):
|
||||
raise KeycloakError("auth_url '%s' should either start with 'http' or 'https'." % base_url)
|
||||
|
||||
if token is None:
|
||||
base_url = module_params.get('auth_keycloak_url')
|
||||
validate_certs = module_params.get('validate_certs')
|
||||
auth_realm = module_params.get('auth_realm')
|
||||
client_id = module_params.get('auth_client_id')
|
||||
auth_username = module_params.get('auth_username')
|
||||
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'
|
||||
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:
|
||||
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):
|
||||
@@ -142,75 +120,6 @@ class KeycloakAPI(object):
|
||||
self.validate_certs = self.module.params.get('validate_certs')
|
||||
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):
|
||||
""" Obtains client representations for clients in a realm
|
||||
|
||||
|
||||
@@ -19,10 +19,11 @@ PATCH_HEADERS = {'content-type': 'application/json', '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 '\
|
||||
'ID of the target %(resource)s resource when there is more '\
|
||||
'than one %(resource)s is no longer allowed. Use the `resource_id` '\
|
||||
'option to specify the target %(resource)s ID.'
|
||||
DEPRECATE_MSG = 'Issuing a data modification command without specifying the '\
|
||||
'ID of the target %(resource)s resource when there is more '\
|
||||
'than one %(resource)s will use the first one in the '\
|
||||
'collection. Use the `resource_id` option to specify the '\
|
||||
'target %(resource)s ID'
|
||||
|
||||
|
||||
class RedfishUtils(object):
|
||||
@@ -266,7 +267,8 @@ class RedfishUtils(object):
|
||||
'ret': False,
|
||||
'msg': "System resource %s not found" % self.resource_id}
|
||||
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}
|
||||
|
||||
def _find_updateservice_resource(self):
|
||||
@@ -316,7 +318,8 @@ class RedfishUtils(object):
|
||||
'ret': False,
|
||||
'msg': "Chassis resource %s not found" % self.resource_id}
|
||||
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}
|
||||
|
||||
def _find_managers_resource(self):
|
||||
@@ -345,7 +348,8 @@ class RedfishUtils(object):
|
||||
'ret': False,
|
||||
'msg': "Manager resource %s not found" % self.resource_id}
|
||||
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}
|
||||
|
||||
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()
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
||||
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)
|
||||
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:
|
||||
module.fail_json(msg=missing_required_lib('footmark'), exception=FOOTMARK_IMP_ERR)
|
||||
|
||||
@@ -30,6 +30,10 @@ options:
|
||||
required: False
|
||||
default: present
|
||||
choices: ['present','absent']
|
||||
wait:
|
||||
description:
|
||||
- This option does nothing and will be removed in community.general 3.0.0.
|
||||
type: bool
|
||||
requirements:
|
||||
- python = 2.7
|
||||
- requests >= 2.5.0
|
||||
@@ -181,6 +185,7 @@ class ClcAntiAffinityPolicy:
|
||||
argument_spec = dict(
|
||||
name=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']),
|
||||
)
|
||||
return argument_spec
|
||||
|
||||
@@ -28,6 +28,7 @@ options:
|
||||
- The region of the instance. This is a required parameter only when
|
||||
creating Linode instances. See
|
||||
U(https://www.linode.com/docs/api/regions/).
|
||||
required: false
|
||||
type: str
|
||||
image:
|
||||
description:
|
||||
@@ -35,12 +36,14 @@ options:
|
||||
creating Linode instances. See
|
||||
U(https://www.linode.com/docs/api/images/).
|
||||
type: str
|
||||
required: false
|
||||
type:
|
||||
description:
|
||||
- The type of the instance. This is a required parameter only when
|
||||
creating Linode instances. See
|
||||
U(https://www.linode.com/docs/api/linode-types/).
|
||||
type: str
|
||||
required: false
|
||||
label:
|
||||
description:
|
||||
- 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
|
||||
method for marking instances is to use tags.
|
||||
type: str
|
||||
private_ip:
|
||||
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
|
||||
required: false
|
||||
tags:
|
||||
description:
|
||||
- The tags that the instance should be marked under. See
|
||||
U(https://www.linode.com/docs/api/tags/).
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
root_pass:
|
||||
@@ -71,10 +69,12 @@ options:
|
||||
- The password for the root user. If not specified, one will be
|
||||
generated. This generated password will be available in the task
|
||||
success JSON.
|
||||
required: false
|
||||
type: str
|
||||
authorized_keys:
|
||||
description:
|
||||
- A list of SSH public key parts to deploy for the root user.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
state:
|
||||
@@ -208,8 +208,9 @@ def create_linode(module, client, **kwargs):
|
||||
else:
|
||||
return response._raw_json
|
||||
except TypeError:
|
||||
module.fail_json(msg='Unable to parse Linode instance creation response. Please raise a bug against this'
|
||||
' module on https://github.com/ansible-collections/community.general/issues'
|
||||
module.fail_json(msg='Unable to parse Linode instance creation'
|
||||
' 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,
|
||||
fallback=(env_fallback, ['LINODE_ACCESS_TOKEN']),
|
||||
),
|
||||
authorized_keys=dict(type='list', elements='str', no_log=False),
|
||||
group=dict(type='str'),
|
||||
image=dict(type='str'),
|
||||
private_ip=dict(type='bool', default=False),
|
||||
region=dict(type='str'),
|
||||
root_pass=dict(type='str', no_log=True),
|
||||
tags=dict(type='list', elements='str'),
|
||||
type=dict(type='str'),
|
||||
stackscript_id=dict(type='int'),
|
||||
stackscript_data=dict(type='dict'),
|
||||
authorized_keys=dict(type='list', elements='str', required=False, no_log=False),
|
||||
group=dict(type='str', required=False),
|
||||
image=dict(type='str', required=False),
|
||||
region=dict(type='str', required=False),
|
||||
root_pass=dict(type='str', required=False, no_log=True),
|
||||
tags=dict(type='list', elements='str', required=False),
|
||||
type=dict(type='str', required=False),
|
||||
stackscript_id=dict(type='int', required=False),
|
||||
stackscript_data=dict(type='dict', required=False),
|
||||
),
|
||||
supports_check_mode=False,
|
||||
required_one_of=(
|
||||
@@ -290,7 +290,6 @@ def main():
|
||||
group=module.params['group'],
|
||||
image=module.params['image'],
|
||||
label=module.params['label'],
|
||||
private_ip=module.params['private_ip'],
|
||||
region=module.params['region'],
|
||||
root_pass=module.params['root_pass'],
|
||||
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
|
||||
)
|
||||
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.
|
||||
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
|
||||
)
|
||||
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.
|
||||
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
|
||||
# -*- 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)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
@@ -21,7 +21,7 @@ options:
|
||||
- Restrict results to a specific authentication realm.
|
||||
aliases: ['realm', 'name']
|
||||
type: str
|
||||
author: Tristan Le Guern (@tleguern)
|
||||
author: Tristan Le Guern (@Aversiste)
|
||||
extends_documentation_fragment: community.general.proxmox.documentation
|
||||
'''
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ options:
|
||||
- Restrict results to a specific group.
|
||||
aliases: ['groupid', 'name']
|
||||
type: str
|
||||
author: Tristan Le Guern (@tleguern)
|
||||
author: Tristan Le Guern (@Aversiste)
|
||||
extends_documentation_fragment: community.general.proxmox.documentation
|
||||
'''
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/python
|
||||
# -*- 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)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
@@ -25,7 +25,7 @@ options:
|
||||
description:
|
||||
- Filter on a specifc storage type.
|
||||
type: str
|
||||
author: Tristan Le Guern (@tleguern)
|
||||
author: Tristan Le Guern (@Aversiste)
|
||||
extends_documentation_fragment: community.general.proxmox.documentation
|
||||
notes:
|
||||
- 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:
|
||||
- Restrict results to a specific user ID, which is a concatenation of a user and domain parts.
|
||||
type: str
|
||||
author: Tristan Le Guern (@tleguern)
|
||||
author: Tristan Le Guern (@Aversiste)
|
||||
extends_documentation_fragment: community.general.proxmox.documentation
|
||||
'''
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: terraform
|
||||
short_description: Manages a Terraform deployment (and plans)
|
||||
@@ -33,19 +33,6 @@ options:
|
||||
vars.tf/main.tf/etc to use.
|
||||
type: path
|
||||
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:
|
||||
description:
|
||||
- The terraform workspace to work with.
|
||||
@@ -154,28 +141,6 @@ EXAMPLES = """
|
||||
backend_config_files:
|
||||
- /path/to/backend_config_file_1
|
||||
- /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 = """
|
||||
@@ -212,31 +177,24 @@ command:
|
||||
import os
|
||||
import json
|
||||
import tempfile
|
||||
from distutils.version import LooseVersion
|
||||
from ansible.module_utils.six.moves import shlex_quote
|
||||
|
||||
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
|
||||
|
||||
|
||||
def get_version(bin_path):
|
||||
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):
|
||||
def preflight_validation(bin_path, project_path, variables_args=None, plan_file=None):
|
||||
if project_path in [None, ''] or '/' not in project_path:
|
||||
module.fail_json(msg="Path for Terraform project can not be None or ''.")
|
||||
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))
|
||||
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))
|
||||
if LooseVersion(version) < LooseVersion('0.15.0'):
|
||||
rc, out, err = module.run_command([bin_path, 'validate'] + variables_args, check_rc=True, cwd=project_path)
|
||||
else:
|
||||
rc, out, err = module.run_command([bin_path, 'validate'], 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)
|
||||
|
||||
|
||||
def _state_args(state_file):
|
||||
@@ -247,7 +205,7 @@ def _state_args(state_file):
|
||||
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']
|
||||
if backend_config:
|
||||
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])
|
||||
if init_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)
|
||||
|
||||
|
||||
@@ -312,7 +267,7 @@ def build_plan(command, project_path, variables_args, state_file, targets, state
|
||||
|
||||
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:
|
||||
# no changes
|
||||
@@ -333,7 +288,6 @@ def main():
|
||||
argument_spec=dict(
|
||||
project_path=dict(required=True, type='path'),
|
||||
binary_path=dict(type='path'),
|
||||
plugin_paths=dict(type='list', elements='path'),
|
||||
workspace=dict(required=False, type='str', default='default'),
|
||||
purge_workspace=dict(type='bool', default=False),
|
||||
state=dict(default='present', choices=['present', 'absent', 'planned']),
|
||||
@@ -355,7 +309,6 @@ def main():
|
||||
|
||||
project_path = module.params.get('project_path')
|
||||
bin_path = module.params.get('binary_path')
|
||||
plugin_paths = module.params.get('plugin_paths')
|
||||
workspace = module.params.get('workspace')
|
||||
purge_workspace = module.params.get('purge_workspace')
|
||||
state = module.params.get('state')
|
||||
@@ -373,17 +326,8 @@ def main():
|
||||
else:
|
||||
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:
|
||||
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)
|
||||
if workspace_ctx["current"] != workspace:
|
||||
@@ -407,7 +351,7 @@ def main():
|
||||
for f in variables_files:
|
||||
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'):
|
||||
|
||||
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:
|
||||
- Manages OpenNebula images
|
||||
requirements:
|
||||
- pyone
|
||||
- python-oca
|
||||
options:
|
||||
api_url:
|
||||
description:
|
||||
@@ -88,7 +88,7 @@ EXAMPLES = '''
|
||||
|
||||
- name: Print the IMAGE properties
|
||||
ansible.builtin.debug:
|
||||
var: result
|
||||
msg: result
|
||||
|
||||
- name: Rename existing IMAGE
|
||||
community.general.one_image:
|
||||
@@ -168,20 +168,21 @@ running_vms:
|
||||
'''
|
||||
|
||||
try:
|
||||
import pyone
|
||||
HAS_PYONE = True
|
||||
import oca
|
||||
HAS_OCA = True
|
||||
except ImportError:
|
||||
HAS_PYONE = False
|
||||
HAS_OCA = False
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
import os
|
||||
|
||||
|
||||
def get_image(module, client, predicate):
|
||||
pool = oca.ImagePool(client)
|
||||
# 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):
|
||||
return image
|
||||
|
||||
@@ -189,11 +190,11 @@ def get_image(module, client, predicate):
|
||||
|
||||
|
||||
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):
|
||||
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):
|
||||
@@ -207,28 +208,30 @@ IMAGE_STATES = ['INIT', 'READY', 'USED', 'DISABLED', 'LOCKED', 'ERROR', 'CLONE',
|
||||
|
||||
|
||||
def get_image_info(image):
|
||||
image.info()
|
||||
|
||||
info = {
|
||||
'id': image.ID,
|
||||
'name': image.NAME,
|
||||
'state': IMAGE_STATES[image.STATE],
|
||||
'running_vms': image.RUNNING_VMS,
|
||||
'used': bool(image.RUNNING_VMS),
|
||||
'user_name': image.UNAME,
|
||||
'user_id': image.UID,
|
||||
'group_name': image.GNAME,
|
||||
'group_id': image.GID,
|
||||
'id': image.id,
|
||||
'name': image.name,
|
||||
'state': IMAGE_STATES[image.state],
|
||||
'running_vms': image.running_vms,
|
||||
'used': bool(image.running_vms),
|
||||
'user_name': image.uname,
|
||||
'user_id': image.uid,
|
||||
'group_name': image.gname,
|
||||
'group_id': image.gid,
|
||||
}
|
||||
|
||||
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
|
||||
start_time = time.time()
|
||||
|
||||
while (time.time() - start_time) < wait_timeout:
|
||||
image = client.image.info(image_id)
|
||||
state = image.STATE
|
||||
image.info()
|
||||
state = image.state
|
||||
|
||||
if state_predicate(state):
|
||||
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!")
|
||||
|
||||
|
||||
def wait_for_ready(module, client, image_id, wait_timeout=60):
|
||||
return wait_for_state(module, client, image_id, wait_timeout, lambda state: (state in [IMAGE_STATES.index('READY')]))
|
||||
def wait_for_ready(module, image, wait_timeout=60):
|
||||
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):
|
||||
return wait_for_state(module, client, image_id, wait_timeout, lambda state: (state in [IMAGE_STATES.index('DELETE')]))
|
||||
def wait_for_delete(module, image, wait_timeout=60):
|
||||
return wait_for_state(module, image, wait_timeout, lambda state: (state in [IMAGE_STATES.index('DELETE')]))
|
||||
|
||||
|
||||
def enable_image(module, client, image, enable):
|
||||
image = client.image.info(image.ID)
|
||||
image.info()
|
||||
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 enable:
|
||||
@@ -263,7 +266,7 @@ def enable_image(module, client, image, enable):
|
||||
changed = True
|
||||
|
||||
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['changed'] = changed
|
||||
@@ -273,7 +276,7 @@ def enable_image(module, client, image, enable):
|
||||
|
||||
def clone_image(module, client, image, new_name):
|
||||
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)
|
||||
if tmp_image:
|
||||
@@ -281,13 +284,13 @@ def clone_image(module, client, image, new_name):
|
||||
result['changed'] = False
|
||||
return result
|
||||
|
||||
if image.STATE == IMAGE_STATES.index('DISABLED'):
|
||||
if image.state == IMAGE_STATES.index('DISABLED'):
|
||||
module.fail_json(msg="Cannot clone DISABLED image")
|
||||
|
||||
if not module.check_mode:
|
||||
new_id = client.image.clone(image.ID, new_name)
|
||||
wait_for_ready(module, client, new_id)
|
||||
image = client.image.info(new_id)
|
||||
new_id = client.call('image.clone', image.id, new_name)
|
||||
image = get_image_by_id(module, client, new_id)
|
||||
wait_for_ready(module, image)
|
||||
|
||||
result = get_image_info(image)
|
||||
result['changed'] = True
|
||||
@@ -299,7 +302,7 @@ def rename_image(module, client, image, new_name):
|
||||
if new_name is None:
|
||||
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['changed'] = False
|
||||
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))
|
||||
|
||||
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['changed'] = True
|
||||
@@ -321,12 +324,12 @@ def delete_image(module, client, image):
|
||||
if not image:
|
||||
return {'changed': False}
|
||||
|
||||
if image.RUNNING_VMS > 0:
|
||||
module.fail_json(msg="Cannot delete image. There are " + str(image.RUNNING_VMS) + " VMs using it.")
|
||||
if image.running_vms > 0:
|
||||
module.fail_json(msg="Cannot delete image. There are " + str(image.running_vms) + " VMs using it.")
|
||||
|
||||
if not module.check_mode:
|
||||
client.image.delete(image.ID)
|
||||
wait_for_delete(module, client, image.ID)
|
||||
client.call('image.delete', image.id)
|
||||
wait_for_delete(module, image)
|
||||
|
||||
return {'changed': True}
|
||||
|
||||
@@ -375,8 +378,8 @@ def main():
|
||||
mutually_exclusive=[['id', 'name']],
|
||||
supports_check_mode=True)
|
||||
|
||||
if not HAS_PYONE:
|
||||
module.fail_json(msg='This module requires pyone to work!')
|
||||
if not HAS_OCA:
|
||||
module.fail_json(msg='This module requires python-oca to work!')
|
||||
|
||||
auth = get_connection_info(module)
|
||||
params = module.params
|
||||
@@ -385,7 +388,7 @@ def main():
|
||||
state = params.get('state')
|
||||
enabled = params.get('enabled')
|
||||
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 = {}
|
||||
|
||||
|
||||
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,
|
||||
mutually_exclusive=[['ids', 'name']],
|
||||
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:
|
||||
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 isinstance(vm.TEMPLATE['NIC'], list):
|
||||
for nic in vm.TEMPLATE['NIC']:
|
||||
networks_info.append({
|
||||
'ip': nic.get('IP', ''),
|
||||
'mac': nic.get('MAC', ''),
|
||||
'name': nic.get('NETWORK', ''),
|
||||
'security_groups': nic.get('SECURITY_GROUPS', '')
|
||||
})
|
||||
networks_info.append({'ip': nic['IP'], 'mac': nic['MAC'], 'name': nic['NETWORK'], 'security_groups': nic['SECURITY_GROUPS']})
|
||||
else:
|
||||
networks_info.append({
|
||||
'ip': vm.TEMPLATE['NIC'].get('IP', ''),
|
||||
'mac': vm.TEMPLATE['NIC'].get('MAC', ''),
|
||||
'name': vm.TEMPLATE['NIC'].get('NETWORK', ''),
|
||||
'security_groups':
|
||||
vm.TEMPLATE['NIC'].get('SECURITY_GROUPS', '')
|
||||
})
|
||||
networks_info.append(
|
||||
{'ip': vm.TEMPLATE['NIC']['IP'], 'mac': vm.TEMPLATE['NIC']['MAC'],
|
||||
'name': vm.TEMPLATE['NIC']['NETWORK'], 'security_groups': vm.TEMPLATE['NIC']['SECURITY_GROUPS']})
|
||||
import time
|
||||
|
||||
current_time = time.localtime()
|
||||
|
||||
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={}),
|
||||
name=dict(),
|
||||
networks=dict(type='list', elements='str', default=['public', 'private']),
|
||||
service=dict(),
|
||||
state=dict(default='present', choices=['present', 'absent']),
|
||||
user_data=dict(no_log=True),
|
||||
wait=dict(default=False, type='bool'),
|
||||
@@ -832,6 +833,13 @@ def main():
|
||||
if not HAS_PYRAX:
|
||||
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')
|
||||
boot_from_volume = module.params.get('boot_from_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()
|
||||
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
|
||||
@@ -47,6 +47,9 @@ EXAMPLES = '''
|
||||
has {{ result.smartos_images[item]['clones'] }} VM(s)"
|
||||
with_items: "{{ result.smartos_images.keys() | list }}"
|
||||
|
||||
# When the module is called as smartos_image_facts, return values are published
|
||||
# in ansible_facts['smartos_images'] and can be used as follows.
|
||||
# Note that this is deprecated and will stop working in community.general 3.0.0.
|
||||
- name: Print information
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ smartos_images[item]['name'] }}-{{ smartos_images[item]['version'] }}
|
||||
@@ -99,12 +102,20 @@ def main():
|
||||
),
|
||||
supports_check_mode=False,
|
||||
)
|
||||
is_old_facts = module._name in ('smartos_image_facts', 'community.general.smartos_image_facts')
|
||||
if is_old_facts:
|
||||
module.deprecate("The 'smartos_image_facts' module has been renamed to 'smartos_image_info', "
|
||||
"and the renamed one no longer returns ansible_facts",
|
||||
version='3.0.0', collection_name='community.general') # was Ansible 2.13
|
||||
|
||||
image_facts = ImageFacts(module)
|
||||
|
||||
data = dict(smartos_images=image_facts.return_all_installed_images())
|
||||
|
||||
module.exit_json(**data)
|
||||
if is_old_facts:
|
||||
module.exit_json(ansible_facts=data)
|
||||
else:
|
||||
module.exit_json(**data)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -23,24 +23,21 @@ requirements:
|
||||
- Univention
|
||||
options:
|
||||
state:
|
||||
type: str
|
||||
required: false
|
||||
default: "present"
|
||||
choices: [ present, absent ]
|
||||
description:
|
||||
- Whether the dns record is present or not.
|
||||
name:
|
||||
type: str
|
||||
required: true
|
||||
description:
|
||||
- "Name of the record, this is also the DNS record. E.g. www for
|
||||
www.example.com."
|
||||
zone:
|
||||
type: str
|
||||
required: true
|
||||
description:
|
||||
- Corresponding DNS zone for this record, e.g. example.com.
|
||||
type:
|
||||
type: str
|
||||
required: true
|
||||
description:
|
||||
- "Define the record type. C(host_record) is a A or AAAA record,
|
||||
@@ -48,8 +45,8 @@ options:
|
||||
is a SRV record and C(txt_record) is a TXT record."
|
||||
- "The available choices are: C(host_record), C(alias), C(ptr_record), C(srv_record), C(txt_record)."
|
||||
data:
|
||||
type: dict
|
||||
default: {}
|
||||
required: false
|
||||
default: []
|
||||
description:
|
||||
- "Additional data for this record, e.g. ['a': '192.0.2.1'].
|
||||
Required if C(state=present)."
|
||||
@@ -101,7 +98,7 @@ def main():
|
||||
type='str'),
|
||||
name=dict(required=True,
|
||||
type='str'),
|
||||
data=dict(default={},
|
||||
data=dict(default=[],
|
||||
type='dict'),
|
||||
state=dict(default='present',
|
||||
choices=['present', 'absent'],
|
||||
|
||||
@@ -22,64 +22,58 @@ requirements:
|
||||
- Python >= 2.6
|
||||
options:
|
||||
state:
|
||||
type: str
|
||||
required: false
|
||||
default: "present"
|
||||
choices: [ present, absent ]
|
||||
description:
|
||||
- Whether the dns zone is present or not.
|
||||
type:
|
||||
type: str
|
||||
required: true
|
||||
description:
|
||||
- Define if the zone is a forward or reverse DNS zone.
|
||||
- "The available choices are: C(forward_zone), C(reverse_zone)."
|
||||
zone:
|
||||
type: str
|
||||
required: true
|
||||
description:
|
||||
- DNS zone name, e.g. C(example.com).
|
||||
aliases: [name]
|
||||
nameserver:
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
description:
|
||||
- List of appropriate name servers. Required if C(state=present).
|
||||
interfaces:
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
description:
|
||||
- List of interface IP addresses, on which the server should
|
||||
response this zone. Required if C(state=present).
|
||||
|
||||
refresh:
|
||||
type: int
|
||||
required: false
|
||||
default: 3600
|
||||
description:
|
||||
- Interval before the zone should be refreshed.
|
||||
retry:
|
||||
type: int
|
||||
required: false
|
||||
default: 1800
|
||||
description:
|
||||
- Interval that should elapse before a failed refresh should be retried.
|
||||
expire:
|
||||
type: int
|
||||
required: false
|
||||
default: 604800
|
||||
description:
|
||||
- Specifies the upper limit on the time interval that can elapse before the zone is no longer authoritative.
|
||||
ttl:
|
||||
type: int
|
||||
required: false
|
||||
default: 600
|
||||
description:
|
||||
- Minimum TTL field that should be exported with any RR from this zone.
|
||||
|
||||
contact:
|
||||
type: str
|
||||
required: false
|
||||
default: ''
|
||||
description:
|
||||
- Contact person in the SOA record.
|
||||
mx:
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
default: []
|
||||
description:
|
||||
- List of MX servers. (Must declared as A or AAAA records).
|
||||
@@ -134,11 +128,9 @@ def main():
|
||||
aliases=['name'],
|
||||
type='str'),
|
||||
nameserver=dict(default=[],
|
||||
type='list',
|
||||
elements='str'),
|
||||
type='list'),
|
||||
interfaces=dict(default=[],
|
||||
type='list',
|
||||
elements='str'),
|
||||
type='list'),
|
||||
refresh=dict(default=3600,
|
||||
type='int'),
|
||||
retry=dict(default=1800,
|
||||
@@ -150,8 +142,7 @@ def main():
|
||||
contact=dict(default='',
|
||||
type='str'),
|
||||
mx=dict(default=[],
|
||||
type='list',
|
||||
elements='str'),
|
||||
type='list'),
|
||||
state=dict(default='present',
|
||||
choices=['present', 'absent'],
|
||||
type='str')
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
# Copyright: (c) 2018, Bojan Vitnik <bvitnik@mainstream.rs>
|
||||
# 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
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
@@ -24,14 +24,14 @@ notes:
|
||||
Citrix Hypervisor/XenServer SDK (downloadable from Citrix website). Copy the XenAPI.py file from the SDK to your Python site-packages on your
|
||||
Ansible Control Node to use it. Latest version of the library can also be acquired from GitHub:
|
||||
U(https://raw.githubusercontent.com/xapi-project/xen-api/master/scripts/examples/python/XenAPI/XenAPI.py)'
|
||||
- 'If no scheme is specified in I(hostname), module defaults to C(http://) because C(https://) is problematic in most setups. Make sure you are
|
||||
- 'If no scheme is specified in C(hostname), module defaults to C(http://) because C(https://) is problematic in most setups. Make sure you are
|
||||
accessing XenServer host in trusted environment or use C(https://) scheme explicitly.'
|
||||
- 'To use C(https://) scheme for I(hostname) you have to either import host certificate to your OS certificate store or use I(validate_certs): C(no)
|
||||
- 'To use C(https://) scheme for C(hostname) you have to either import host certificate to your OS certificate store or use C(validate_certs: no)
|
||||
which requires XenAPI library from XenServer 7.2 SDK or newer and Python 2.7.9 or newer.'
|
||||
- 'Network configuration inside a guest OS, by using I(networks.type), I(networks.ip), I(networks.gateway) etc. parameters, is supported on
|
||||
- 'Network configuration inside a guest OS, by using C(networks.type), C(networks.ip), C(networks.gateway) etc. parameters, is supported on
|
||||
XenServer 7.0 or newer for Windows guests by using official XenServer Guest agent support for network configuration. The module will try to
|
||||
detect if such support is available and utilize it, else it will use a custom method of configuration via xenstore. Since XenServer Guest
|
||||
agent only support None and Static types of network configuration, where None means DHCP configured interface, I(networks.type) and I(networks.type6)
|
||||
agent only support None and Static types of network configuration, where None means DHCP configured interface, C(networks.type) and C(networks.type6)
|
||||
values C(none) and C(dhcp) have same effect. More info here:
|
||||
U(https://www.citrix.com/community/citrix-developer/citrix-hypervisor-developer/citrix-hypervisor-developing-products/citrix-hypervisor-staticip.html)'
|
||||
- 'On platforms without official support for network configuration inside a guest OS, network parameters will be written to xenstore
|
||||
@@ -49,10 +49,10 @@ options:
|
||||
state:
|
||||
description:
|
||||
- Specify the state VM should be in.
|
||||
- If I(state) is set to C(present) and VM exists, ensure the VM configuration conforms to given parameters.
|
||||
- If I(state) is set to C(present) and VM does not exist, then VM is deployed with given parameters.
|
||||
- If I(state) is set to C(absent) and VM exists, then VM is removed with its associated components.
|
||||
- If I(state) is set to C(poweredon) and VM does not exist, then VM is deployed with given parameters and powered on automatically.
|
||||
- If C(state) is set to C(present) and VM exists, ensure the VM configuration conforms to given parameters.
|
||||
- If C(state) is set to C(present) and VM does not exist, then VM is deployed with given parameters.
|
||||
- If C(state) is set to C(absent) and VM exists, then VM is removed with its associated components.
|
||||
- If C(state) is set to C(poweredon) and VM does not exist, then VM is deployed with given parameters and powered on automatically.
|
||||
type: str
|
||||
default: present
|
||||
choices: [ present, absent, poweredon ]
|
||||
@@ -60,9 +60,10 @@ options:
|
||||
description:
|
||||
- Name of the VM to work with.
|
||||
- VMs running on XenServer do not necessarily have unique names. The module will fail if multiple VMs with same name are found.
|
||||
- In case of multiple VMs with same name, use I(uuid) to uniquely specify VM to manage.
|
||||
- In case of multiple VMs with same name, use C(uuid) to uniquely specify VM to manage.
|
||||
- This parameter is case sensitive.
|
||||
type: str
|
||||
required: yes
|
||||
aliases: [ name_label ]
|
||||
name_desc:
|
||||
description:
|
||||
@@ -78,7 +79,7 @@ options:
|
||||
description:
|
||||
- Name of a template, an existing VM (must be shut down) or a snapshot that should be used to create VM.
|
||||
- Templates/VMs/snapshots on XenServer do not necessarily have unique names. The module will fail if multiple templates with same name are found.
|
||||
- In case of multiple templates/VMs/snapshots with same name, use I(template_uuid) to uniquely specify source template.
|
||||
- In case of multiple templates/VMs/snapshots with same name, use C(template_uuid) to uniquely specify source template.
|
||||
- If VM already exists, this setting will be ignored.
|
||||
- This parameter is case sensitive.
|
||||
type: str
|
||||
@@ -103,138 +104,56 @@ options:
|
||||
hardware:
|
||||
description:
|
||||
- Manage VM's hardware parameters. VM needs to be shut down to reconfigure these parameters.
|
||||
- 'Valid parameters are:'
|
||||
- ' - C(num_cpus) (integer): Number of CPUs.'
|
||||
- ' - C(num_cpu_cores_per_socket) (integer): Number of Cores Per Socket. C(num_cpus) has to be a multiple of C(num_cpu_cores_per_socket).'
|
||||
- ' - C(memory_mb) (integer): Amount of memory in MB.'
|
||||
type: dict
|
||||
suboptions:
|
||||
num_cpus:
|
||||
description:
|
||||
- Number of CPUs.
|
||||
type: int
|
||||
num_cpu_cores_per_socket:
|
||||
description:
|
||||
- Number of Cores Per Socket. I(num_cpus) has to be a multiple of I(num_cpu_cores_per_socket).
|
||||
type: int
|
||||
memory_mb:
|
||||
description:
|
||||
- Amount of memory in MB.
|
||||
type: int
|
||||
disks:
|
||||
description:
|
||||
- A list of disks to add to VM.
|
||||
- All parameters are case sensitive.
|
||||
- Removing or detaching existing disks of VM is not supported.
|
||||
- New disks are required to have either a I(size) or one of I(size_[tb,gb,mb,kb,b]) parameters specified.
|
||||
- VM needs to be shut down to reconfigure disk size.
|
||||
- 'Required parameters per entry:'
|
||||
- ' - C(size_[tb,gb,mb,kb,b]) (integer): Disk storage size in specified unit. VM needs to be shut down to reconfigure this parameter.'
|
||||
- 'Optional parameters per entry:'
|
||||
- ' - C(name) (string): Disk name. You can also use C(name_label) as an alias.'
|
||||
- ' - C(name_desc) (string): Disk description.'
|
||||
- ' - C(sr) (string): Storage Repository to create disk on. If not specified, will use default SR. Cannot be used for moving disk to other SR.'
|
||||
- ' - C(sr_uuid) (string): UUID of a SR to create disk on. Use if SR name is not unique.'
|
||||
type: list
|
||||
elements: dict
|
||||
aliases: [ disk ]
|
||||
suboptions:
|
||||
size:
|
||||
description:
|
||||
- 'Disk size with unit. Unit must be: C(b), C(kb), C(mb), C(gb), C(tb). VM needs to be shut down to reconfigure this parameter.'
|
||||
- If no unit is specified, size is assumed to be in bytes.
|
||||
type: str
|
||||
size_b:
|
||||
description:
|
||||
- Disk size in bytes.
|
||||
type: str
|
||||
size_kb:
|
||||
description:
|
||||
- Disk size in kilobytes.
|
||||
type: str
|
||||
size_mb:
|
||||
description:
|
||||
- Disk size in megabytes.
|
||||
type: str
|
||||
size_gb:
|
||||
description:
|
||||
- Disk size in gigabytes.
|
||||
type: str
|
||||
size_tb:
|
||||
description:
|
||||
- Disk size in terabytes.
|
||||
type: str
|
||||
name:
|
||||
description:
|
||||
- Disk name.
|
||||
type: str
|
||||
aliases: [ name_label ]
|
||||
name_desc:
|
||||
description:
|
||||
- Disk description.
|
||||
type: str
|
||||
sr:
|
||||
description:
|
||||
- Storage Repository to create disk on. If not specified, will use default SR. Cannot be used for moving disk to other SR.
|
||||
type: str
|
||||
sr_uuid:
|
||||
description:
|
||||
- UUID of a SR to create disk on. Use if SR name is not unique.
|
||||
type: str
|
||||
cdrom:
|
||||
description:
|
||||
- A CD-ROM configuration for the VM.
|
||||
- All parameters are case sensitive.
|
||||
- 'Valid parameters are:'
|
||||
- ' - C(type) (string): The type of CD-ROM, valid options are C(none) or C(iso). With C(none) the CD-ROM device will be present but empty.'
|
||||
- ' - C(iso_name) (string): The file name of an ISO image from one of the XenServer ISO Libraries (implies C(type: iso)).
|
||||
Required if C(type) is set to C(iso).'
|
||||
type: dict
|
||||
suboptions:
|
||||
type:
|
||||
description:
|
||||
- The type of CD-ROM. With C(none) the CD-ROM device will be present but empty.
|
||||
type: str
|
||||
choices: [ none, iso ]
|
||||
iso_name:
|
||||
description:
|
||||
- 'The file name of an ISO image from one of the XenServer ISO Libraries (implies I(type): C(iso)).'
|
||||
- Required if I(type) is set to C(iso).
|
||||
type: str
|
||||
networks:
|
||||
description:
|
||||
- A list of networks (in the order of the NICs).
|
||||
- All parameters are case sensitive.
|
||||
- Name is required for new NICs. Other parameters are optional in all cases.
|
||||
- 'Required parameters per entry:'
|
||||
- ' - C(name) (string): Name of a XenServer network to attach the network interface to. You can also use C(name_label) as an alias.'
|
||||
- 'Optional parameters per entry (used for VM hardware):'
|
||||
- ' - C(mac) (string): Customize MAC address of the interface.'
|
||||
- 'Optional parameters per entry (used for OS customization):'
|
||||
- ' - C(type) (string): Type of IPv4 assignment, valid options are C(none), C(dhcp) or C(static). Value C(none) means whatever is default for OS.
|
||||
On some operating systems it could be DHCP configured (e.g. Windows) or unconfigured interface (e.g. Linux).'
|
||||
- ' - C(ip) (string): Static IPv4 address (implies C(type: static)). Can include prefix in format <IPv4 address>/<prefix> instead of using C(netmask).'
|
||||
- ' - C(netmask) (string): Static IPv4 netmask required for C(ip) if prefix is not specified.'
|
||||
- ' - C(gateway) (string): Static IPv4 gateway.'
|
||||
- ' - C(type6) (string): Type of IPv6 assignment, valid options are C(none), C(dhcp) or C(static). Value C(none) means whatever is default for OS.
|
||||
On some operating systems it could be DHCP configured (e.g. Windows) or unconfigured interface (e.g. Linux).'
|
||||
- ' - C(ip6) (string): Static IPv6 address (implies C(type6: static)) with prefix in format <IPv6 address>/<prefix>.'
|
||||
- ' - C(gateway6) (string): Static IPv6 gateway.'
|
||||
type: list
|
||||
elements: dict
|
||||
aliases: [ network ]
|
||||
suboptions:
|
||||
name:
|
||||
description:
|
||||
- Name of a XenServer network to attach the network interface to.
|
||||
type: str
|
||||
aliases: [ name_label ]
|
||||
mac:
|
||||
description:
|
||||
- Customize MAC address of the interface.
|
||||
type: str
|
||||
type:
|
||||
description:
|
||||
- Type of IPv4 assignment. Value C(none) means whatever is default for OS.
|
||||
- On some operating systems it could be DHCP configured (e.g. Windows) or unconfigured interface (e.g. Linux).
|
||||
type: str
|
||||
choices: [ none, dhcp, static ]
|
||||
ip:
|
||||
description:
|
||||
- 'Static IPv4 address (implies I(type): C(static)). Can include prefix in format C(<IPv4 address>/<prefix>) instead of using C(netmask).'
|
||||
type: str
|
||||
netmask:
|
||||
description:
|
||||
- Static IPv4 netmask required for I(ip) if prefix is not specified.
|
||||
type: str
|
||||
gateway:
|
||||
description:
|
||||
- Static IPv4 gateway.
|
||||
type: str
|
||||
type6:
|
||||
description:
|
||||
- Type of IPv6 assignment. Value C(none) means whatever is default for OS.
|
||||
type: str
|
||||
choices: [ none, dhcp, static ]
|
||||
ip6:
|
||||
description:
|
||||
- 'Static IPv6 address (implies I(type6): C(static)) with prefix in format C(<IPv6 address>/<prefix>).'
|
||||
type: str
|
||||
gateway6:
|
||||
description:
|
||||
- Static IPv6 gateway.
|
||||
type: str
|
||||
home_server:
|
||||
description:
|
||||
- Name of a XenServer host that will be a Home Server for the VM.
|
||||
@@ -244,29 +163,18 @@ options:
|
||||
description:
|
||||
- Define a list of custom VM params to set on VM.
|
||||
- Useful for advanced users familiar with managing VM params trough xe CLI.
|
||||
- A custom value object takes two fields I(key) and I(value) (see example below).
|
||||
- A custom value object takes two fields C(key) and C(value) (see example below).
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
key:
|
||||
description:
|
||||
- VM param name.
|
||||
type: str
|
||||
required: yes
|
||||
value:
|
||||
description:
|
||||
- VM param value.
|
||||
type: raw
|
||||
required: yes
|
||||
wait_for_ip_address:
|
||||
description:
|
||||
- Wait until XenServer detects an IP address for the VM. If I(state) is set to C(absent), this parameter is ignored.
|
||||
- Wait until XenServer detects an IP address for the VM. If C(state) is set to C(absent), this parameter is ignored.
|
||||
- This requires XenServer Tools to be preinstalled on the VM to work properly.
|
||||
type: bool
|
||||
default: no
|
||||
state_change_timeout:
|
||||
description:
|
||||
- 'By default, module will wait indefinitely for VM to accquire an IP address if I(wait_for_ip_address): C(yes).'
|
||||
- 'By default, module will wait indefinitely for VM to accquire an IP address if C(wait_for_ip_address: yes).'
|
||||
- If this parameter is set to positive value, the module will instead wait specified number of seconds for the state change.
|
||||
- In case of timeout, module will generate an error message.
|
||||
type: int
|
||||
@@ -533,12 +441,11 @@ except ImportError:
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.common.network import is_mac
|
||||
from ansible.module_utils import six
|
||||
from ansible_collections.community.general.plugins.module_utils.xenserver import (
|
||||
xenserver_common_argument_spec, XenServerObject, get_object_ref,
|
||||
gather_vm_params, gather_vm_facts, set_vm_power_state,
|
||||
wait_for_vm_ip_address, is_valid_ip_addr, is_valid_ip_netmask,
|
||||
is_valid_ip_prefix, ip_prefix_to_netmask, ip_netmask_to_prefix,
|
||||
is_valid_ip6_addr, is_valid_ip6_prefix)
|
||||
from ansible_collections.community.general.plugins.module_utils.xenserver import (xenserver_common_argument_spec, XAPI, XenServerObject, get_object_ref,
|
||||
gather_vm_params, gather_vm_facts, set_vm_power_state,
|
||||
wait_for_vm_ip_address, is_valid_ip_addr, is_valid_ip_netmask,
|
||||
is_valid_ip_prefix, ip_prefix_to_netmask, ip_netmask_to_prefix,
|
||||
is_valid_ip6_addr, is_valid_ip6_prefix)
|
||||
|
||||
|
||||
class XenServerVM(XenServerObject):
|
||||
|
||||
1
plugins/modules/cloud/xenserver/xenserver_guest_facts.py
Symbolic link
1
plugins/modules/cloud/xenserver/xenserver_guest_facts.py
Symbolic link
@@ -0,0 +1 @@
|
||||
xenserver_guest_info.py
|
||||
@@ -204,6 +204,10 @@ def main():
|
||||
],
|
||||
)
|
||||
|
||||
if module._name in ('xenserver_guest_facts', 'community.general.xenserver_guest_facts'):
|
||||
module.deprecate("The 'xenserver_guest_facts' module has been renamed to 'xenserver_guest_info'",
|
||||
version='3.0.0', collection_name='community.general') # was Ansible 2.13
|
||||
|
||||
result = {'failed': False, 'changed': False}
|
||||
|
||||
# Module will exit with an error message if no VM is found.
|
||||
|
||||
@@ -36,13 +36,13 @@ seealso:
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Get info for job awx
|
||||
community.general.nomad_job_info:
|
||||
community.general.nomad_job:
|
||||
host: localhost
|
||||
name: awx
|
||||
register: result
|
||||
|
||||
- name: List Nomad jobs
|
||||
community.general.nomad_job_info:
|
||||
community.general.nomad_job:
|
||||
host: localhost
|
||||
register: result
|
||||
|
||||
|
||||
@@ -31,9 +31,7 @@ options:
|
||||
type: str
|
||||
duration:
|
||||
description:
|
||||
- Determines how long InfluxDB should keep the data. If specified, it
|
||||
should be C(INF) or at least one hour. If not specified, C(INF) is
|
||||
assumed. Supports complex duration expressions with multiple units.
|
||||
- Determines how long InfluxDB should keep the data.
|
||||
required: true
|
||||
type: str
|
||||
replication:
|
||||
@@ -48,10 +46,9 @@ options:
|
||||
default: false
|
||||
shard_group_duration:
|
||||
description:
|
||||
- Determines the time range covered by a shard group. If specified it
|
||||
must be at least one hour. If none, it's determined by InfluxDB by
|
||||
the rentention policy's duration. Supports complex duration expressions
|
||||
with multiple units.
|
||||
- Determines the size of a shard group.
|
||||
- Value needs to be integer literal followed immediately (with no spaces) by a duration unit.
|
||||
Supported duration units are C(h) for hours, C(d) for days, and C(w) for weeks. For example C(10d), C(1h), C(2w).
|
||||
type: str
|
||||
version_added: '2.0.0'
|
||||
extends_documentation_fragment:
|
||||
@@ -99,17 +96,6 @@ EXAMPLES = r'''
|
||||
ssl: no
|
||||
validate_certs: no
|
||||
shard_group_duration: 1w
|
||||
|
||||
- name: Create retention policy with complex durations
|
||||
community.general.influxdb_retention_policy:
|
||||
hostname: "{{influxdb_ip_address}}"
|
||||
database_name: "{{influxdb_database_name}}"
|
||||
policy_name: test
|
||||
duration: 5d1h30m
|
||||
replication: 1
|
||||
ssl: no
|
||||
validate_certs: no
|
||||
shard_group_duration: 1d10h30m
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
@@ -129,51 +115,6 @@ from ansible_collections.community.general.plugins.module_utils.influxdb import
|
||||
from ansible.module_utils._text import to_native
|
||||
|
||||
|
||||
VALID_DURATION_REGEX = re.compile(r'^(INF|(\d+(ns|u|µ|ms|s|m|h|d|w)))+$')
|
||||
|
||||
DURATION_REGEX = re.compile(r'(\d+)(ns|u|µ|ms|s|m|h|d|w)')
|
||||
EXTENDED_DURATION_REGEX = re.compile(r'(?:(\d+)(ns|u|µ|ms|m|h|d|w)|(\d+(?:\.\d+)?)(s))')
|
||||
|
||||
|
||||
def check_duration_literal(value):
|
||||
return VALID_DURATION_REGEX.search(value) is not None
|
||||
|
||||
|
||||
def parse_duration_literal(value, extended=False):
|
||||
duration = 0.0
|
||||
|
||||
if value == "INF":
|
||||
return duration
|
||||
|
||||
lookup = (EXTENDED_DURATION_REGEX if extended else DURATION_REGEX).findall(value)
|
||||
|
||||
for duration_literal in lookup:
|
||||
if extended and duration_literal[3] == 's':
|
||||
duration_val = float(duration_literal[2])
|
||||
duration += duration_val * 1000 * 1000 * 1000
|
||||
else:
|
||||
duration_val = int(duration_literal[0])
|
||||
|
||||
if duration_literal[1] == 'ns':
|
||||
duration += duration_val
|
||||
elif duration_literal[1] == 'u' or duration_literal[1] == 'µ':
|
||||
duration += duration_val * 1000
|
||||
elif duration_literal[1] == 'ms':
|
||||
duration += duration_val * 1000 * 1000
|
||||
elif duration_literal[1] == 's':
|
||||
duration += duration_val * 1000 * 1000 * 1000
|
||||
elif duration_literal[1] == 'm':
|
||||
duration += duration_val * 1000 * 1000 * 1000 * 60
|
||||
elif duration_literal[1] == 'h':
|
||||
duration += duration_val * 1000 * 1000 * 1000 * 60 * 60
|
||||
elif duration_literal[1] == 'd':
|
||||
duration += duration_val * 1000 * 1000 * 1000 * 60 * 60 * 24
|
||||
elif duration_literal[1] == 'w':
|
||||
duration += duration_val * 1000 * 1000 * 1000 * 60 * 60 * 24 * 7
|
||||
|
||||
return duration
|
||||
|
||||
|
||||
def find_retention_policy(module, client):
|
||||
database_name = module.params['database_name']
|
||||
policy_name = module.params['policy_name']
|
||||
@@ -188,11 +129,6 @@ def find_retention_policy(module, client):
|
||||
break
|
||||
except requests.exceptions.ConnectionError as e:
|
||||
module.fail_json(msg="Cannot connect to database %s on %s : %s" % (database_name, hostname, to_native(e)))
|
||||
|
||||
if retention_policy is not None:
|
||||
retention_policy["duration"] = parse_duration_literal(retention_policy["duration"], extended=True)
|
||||
retention_policy["shardGroupDuration"] = parse_duration_literal(retention_policy["shardGroupDuration"], extended=True)
|
||||
|
||||
return retention_policy
|
||||
|
||||
|
||||
@@ -204,21 +140,6 @@ def create_retention_policy(module, client):
|
||||
default = module.params['default']
|
||||
shard_group_duration = module.params['shard_group_duration']
|
||||
|
||||
if not check_duration_literal(duration):
|
||||
module.fail_json(msg="Failed to parse value of duration")
|
||||
|
||||
influxdb_duration_format = parse_duration_literal(duration)
|
||||
if influxdb_duration_format != 0 and influxdb_duration_format < 3600000000000:
|
||||
module.fail_json(msg="duration value must be at least 1h")
|
||||
|
||||
if shard_group_duration is not None:
|
||||
if not check_duration_literal(shard_group_duration):
|
||||
module.fail_json(msg="Failed to parse value of shard_group_duration")
|
||||
|
||||
influxdb_shard_group_duration_format = parse_duration_literal(shard_group_duration)
|
||||
if influxdb_shard_group_duration_format < 3600000000000:
|
||||
module.fail_json(msg="shard_group_duration value must be finite and at least 1h")
|
||||
|
||||
if not module.check_mode:
|
||||
try:
|
||||
if shard_group_duration:
|
||||
@@ -238,30 +159,38 @@ def alter_retention_policy(module, client, retention_policy):
|
||||
replication = module.params['replication']
|
||||
default = module.params['default']
|
||||
shard_group_duration = module.params['shard_group_duration']
|
||||
|
||||
duration_regexp = re.compile(r'(\d+)([hdw]{1})|(^INF$){1}')
|
||||
changed = False
|
||||
|
||||
if not check_duration_literal(duration):
|
||||
module.fail_json(msg="Failed to parse value of duration")
|
||||
duration_lookup = duration_regexp.search(duration)
|
||||
|
||||
influxdb_duration_format = parse_duration_literal(duration)
|
||||
if influxdb_duration_format != 0 and influxdb_duration_format < 3600000000000:
|
||||
module.fail_json(msg="duration value must be at least 1h")
|
||||
if duration_lookup.group(2) == 'h':
|
||||
influxdb_duration_format = '%s0m0s' % duration
|
||||
elif duration_lookup.group(2) == 'd':
|
||||
influxdb_duration_format = '%sh0m0s' % (int(duration_lookup.group(1)) * 24)
|
||||
elif duration_lookup.group(2) == 'w':
|
||||
influxdb_duration_format = '%sh0m0s' % (int(duration_lookup.group(1)) * 24 * 7)
|
||||
elif duration == 'INF':
|
||||
influxdb_duration_format = '0'
|
||||
|
||||
if shard_group_duration is None:
|
||||
influxdb_shard_group_duration_format = retention_policy["shardGroupDuration"]
|
||||
if shard_group_duration:
|
||||
shard_group_duration_lookup = duration_regexp.search(shard_group_duration)
|
||||
if not shard_group_duration_lookup:
|
||||
module.fail_json(
|
||||
msg="Failed to parse value of shard_group_duration. Please see the documentation for valid values")
|
||||
if shard_group_duration_lookup.group(2) == 'h':
|
||||
influxdb_shard_group_duration_format = '%s0m0s' % duration
|
||||
elif shard_group_duration_lookup.group(2) == 'd':
|
||||
influxdb_shard_group_duration_format = '%sh0m0s' % (int(shard_group_duration_lookup.group(1)) * 24)
|
||||
elif shard_group_duration_lookup.group(2) == 'w':
|
||||
influxdb_shard_group_duration_format = '%sh0m0s' % (int(shard_group_duration_lookup.group(1)) * 24 * 7)
|
||||
else:
|
||||
if not check_duration_literal(shard_group_duration):
|
||||
module.fail_json(msg="Failed to parse value of shard_group_duration")
|
||||
influxdb_shard_group_duration_format = retention_policy['shardGroupDuration']
|
||||
|
||||
influxdb_shard_group_duration_format = parse_duration_literal(shard_group_duration)
|
||||
if influxdb_shard_group_duration_format < 3600000000000:
|
||||
module.fail_json(msg="shard_group_duration value must be finite and at least 1h")
|
||||
|
||||
if (retention_policy['duration'] != influxdb_duration_format or
|
||||
retention_policy['shardGroupDuration'] != influxdb_shard_group_duration_format or
|
||||
retention_policy['replicaN'] != int(replication) or
|
||||
retention_policy['default'] != default):
|
||||
if (not retention_policy['duration'] == influxdb_duration_format or
|
||||
not retention_policy['replicaN'] == int(replication) or
|
||||
not retention_policy['shardGroupDuration'] == influxdb_shard_group_duration_format or
|
||||
not retention_policy['default'] == default):
|
||||
if not module.check_mode:
|
||||
try:
|
||||
client.alter_retention_policy(policy_name, database_name, duration, replication, default,
|
||||
|
||||
1
plugins/modules/database/vertica/vertica_facts.py
Symbolic link
1
plugins/modules/database/vertica/vertica_facts.py
Symbolic link
@@ -0,0 +1 @@
|
||||
vertica_info.py
|
||||
@@ -233,6 +233,11 @@ def main():
|
||||
login_user=dict(default='dbadmin'),
|
||||
login_password=dict(default=None, no_log=True),
|
||||
), supports_check_mode=True)
|
||||
is_old_facts = module._name in ('vertica_facts', 'community.general.vertica_facts')
|
||||
if is_old_facts:
|
||||
module.deprecate("The 'vertica_facts' module has been renamed to 'vertica_info', "
|
||||
"and the renamed one no longer returns ansible_facts",
|
||||
version='3.0.0', collection_name='community.general') # was Ansible 2.13
|
||||
|
||||
if not pyodbc_found:
|
||||
module.fail_json(msg=missing_required_lib('pyodbc'), exception=PYODBC_IMP_ERR)
|
||||
@@ -264,12 +269,20 @@ def main():
|
||||
configuration_facts = get_configuration_facts(cursor)
|
||||
node_facts = get_node_facts(cursor)
|
||||
|
||||
module.exit_json(changed=False,
|
||||
vertica_schemas=schema_facts,
|
||||
vertica_users=user_facts,
|
||||
vertica_roles=role_facts,
|
||||
vertica_configuration=configuration_facts,
|
||||
vertica_nodes=node_facts)
|
||||
if is_old_facts:
|
||||
module.exit_json(changed=False,
|
||||
ansible_facts={'vertica_schemas': schema_facts,
|
||||
'vertica_users': user_facts,
|
||||
'vertica_roles': role_facts,
|
||||
'vertica_configuration': configuration_facts,
|
||||
'vertica_nodes': node_facts})
|
||||
else:
|
||||
module.exit_json(changed=False,
|
||||
vertica_schemas=schema_facts,
|
||||
vertica_users=user_facts,
|
||||
vertica_roles=role_facts,
|
||||
vertica_configuration=configuration_facts,
|
||||
vertica_nodes=node_facts)
|
||||
except NotSupportedError as e:
|
||||
module.fail_json(msg=to_native(e), exception=traceback.format_exc())
|
||||
except SystemExit:
|
||||
|
||||
@@ -1,483 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright: (c) 2021, quidame <quidame@poivron.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: filesize
|
||||
|
||||
short_description: Create a file with a given size, or resize it if it exists
|
||||
|
||||
description:
|
||||
- This module is a simple wrapper around C(dd) to create, extend or truncate
|
||||
a file, given its size. It can be used to manage swap files (that require
|
||||
contiguous blocks) or alternatively, huge sparse files.
|
||||
|
||||
author:
|
||||
- quidame (@quidame)
|
||||
|
||||
version_added: "3.0.0"
|
||||
|
||||
options:
|
||||
path:
|
||||
description:
|
||||
- Path of the regular file to create or resize.
|
||||
type: path
|
||||
required: true
|
||||
size:
|
||||
description:
|
||||
- Requested size of the file.
|
||||
- The value is a number (either C(int) or C(float)) optionally followed
|
||||
by a multiplicative suffix, that can be one of C(B) (bytes), C(KB) or
|
||||
C(kB) (= 1000B), C(MB) or C(mB) (= 1000kB), C(GB) or C(gB) (= 1000MB),
|
||||
and so on for C(T), C(P), C(E), C(Z) and C(Y); or alternatively one of
|
||||
C(K), C(k) or C(KiB) (= 1024B); C(M), C(m) or C(MiB) (= 1024KiB);
|
||||
C(G), C(g) or C(GiB) (= 1024MiB); and so on.
|
||||
- If the multiplicative suffix is not provided, the value is treated as
|
||||
an integer number of blocks of I(blocksize) bytes each (float values
|
||||
are rounded to the closest integer).
|
||||
- When the I(size) value is equal to the current file size, does nothing.
|
||||
- When the I(size) value is bigger than the current file size, bytes from
|
||||
I(source) (if I(sparse) is not C(false)) are appended to the file
|
||||
without truncating it, in other words, without modifying the existing
|
||||
bytes of the file.
|
||||
- When the I(size) value is smaller than the current file size, it is
|
||||
truncated to the requested value without modifying bytes before this
|
||||
value.
|
||||
- That means that a file of any arbitrary size can be grown to any other
|
||||
arbitrary size, and then resized down to its initial size without
|
||||
modifying its initial content.
|
||||
type: raw
|
||||
required: true
|
||||
blocksize:
|
||||
description:
|
||||
- Size of blocks, in bytes if not followed by a multiplicative suffix.
|
||||
- The numeric value (before the unit) C(MUST) be an integer (or a C(float)
|
||||
if it equals an integer).
|
||||
- If not set, the size of blocks is guessed from the OS and commonly
|
||||
results in C(512) or C(4096) bytes, that is used internally by the
|
||||
module or when I(size) has no unit.
|
||||
type: raw
|
||||
source:
|
||||
description:
|
||||
- Device or file that provides input data to provision the file.
|
||||
- This parameter is ignored when I(sparse=true).
|
||||
type: path
|
||||
default: /dev/zero
|
||||
force:
|
||||
description:
|
||||
- Whether or not to overwrite the file if it exists, in other words, to
|
||||
truncate it from 0. When C(true), the module is not idempotent, that
|
||||
means it always reports I(changed=true).
|
||||
- I(force=true) and I(sparse=true) are mutually exclusive.
|
||||
type: bool
|
||||
default: false
|
||||
sparse:
|
||||
description:
|
||||
- Whether or not the file to create should be a sparse file.
|
||||
- This option is effective only on newly created files, or when growing a
|
||||
file, only for the bytes to append.
|
||||
- This option is not supported on OpenBSD, Solaris and AIX.
|
||||
- I(force=true) and I(sparse=true) are mutually exclusive.
|
||||
type: bool
|
||||
default: false
|
||||
|
||||
notes:
|
||||
- This module supports C(check_mode) and C(diff).
|
||||
|
||||
requirements:
|
||||
- dd (Data Duplicator) in PATH
|
||||
|
||||
extends_documentation_fragment:
|
||||
- ansible.builtin.files
|
||||
|
||||
seealso:
|
||||
- name: dd(1) manpage for Linux
|
||||
description: Manual page of the GNU/Linux's dd implementation (from GNU coreutils).
|
||||
link: https://man7.org/linux/man-pages/man1/dd.1.html
|
||||
|
||||
- name: dd(1) manpage for IBM AIX
|
||||
description: Manual page of the IBM AIX's dd implementation.
|
||||
link: https://www.ibm.com/support/knowledgecenter/ssw_aix_72/d_commands/dd.html
|
||||
|
||||
- name: dd(1) manpage for Mac OSX
|
||||
description: Manual page of the Mac OSX's dd implementation.
|
||||
link: https://www.unix.com/man-page/osx/1/dd/
|
||||
|
||||
- name: dd(1M) manpage for Solaris
|
||||
description: Manual page of the Oracle Solaris's dd implementation.
|
||||
link: https://docs.oracle.com/cd/E36784_01/html/E36871/dd-1m.html
|
||||
|
||||
- name: dd(1) manpage for FreeBSD
|
||||
description: Manual page of the FreeBSD's dd implementation.
|
||||
link: https://www.freebsd.org/cgi/man.cgi?dd(1)
|
||||
|
||||
- name: dd(1) manpage for OpenBSD
|
||||
description: Manual page of the OpenBSD's dd implementation.
|
||||
link: https://man.openbsd.org/dd
|
||||
|
||||
- name: dd(1) manpage for NetBSD
|
||||
description: Manual page of the NetBSD's dd implementation.
|
||||
link: https://man.netbsd.org/dd.1
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
- name: Create a file of 1G filled with null bytes
|
||||
community.general.filesize:
|
||||
path: /var/bigfile
|
||||
size: 1G
|
||||
|
||||
- name: Extend the file to 2G (2*1024^3)
|
||||
community.general.filesize:
|
||||
path: /var/bigfile
|
||||
size: 2G
|
||||
|
||||
- name: Reduce the file to 2GB (2*1000^3)
|
||||
community.general.filesize:
|
||||
path: /var/bigfile
|
||||
size: 2GB
|
||||
|
||||
- name: Fill a file with random bytes for backing a LUKS device
|
||||
community.general.filesize:
|
||||
path: ~/diskimage.luks
|
||||
size: 512.0 MiB
|
||||
source: /dev/urandom
|
||||
|
||||
- name: Take a backup of MBR boot code into a file, overwriting it if it exists
|
||||
community.general.filesize:
|
||||
path: /media/sdb1/mbr.bin
|
||||
size: 440B
|
||||
source: /dev/sda
|
||||
force: true
|
||||
|
||||
- name: Create/resize a sparse file of/to 8TB
|
||||
community.general.filesize:
|
||||
path: /var/local/sparsefile
|
||||
size: 8TB
|
||||
sparse: true
|
||||
|
||||
- name: Create a file with specific size and attributes, to be used as swap space
|
||||
community.general.filesize:
|
||||
path: /var/swapfile
|
||||
size: 2G
|
||||
blocksize: 512B
|
||||
mode: u=rw,go=
|
||||
owner: root
|
||||
group: root
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
cmd:
|
||||
description: Command executed to create or resize the file.
|
||||
type: str
|
||||
returned: when changed or failed
|
||||
sample: /usr/bin/dd if=/dev/zero of=/var/swapfile bs=1048576 seek=3072 count=1024
|
||||
|
||||
filesize:
|
||||
description: Dictionary of sizes related to the file.
|
||||
type: dict
|
||||
returned: always
|
||||
contains:
|
||||
blocks:
|
||||
description: Number of blocks in the file.
|
||||
type: int
|
||||
sample: 500
|
||||
blocksize:
|
||||
description: Size of the blocks in bytes.
|
||||
type: int
|
||||
sample: 1024
|
||||
bytes:
|
||||
description: Size of the file, in bytes, as the product of C(blocks) and C(blocksize).
|
||||
type: int
|
||||
sample: 512000
|
||||
iec:
|
||||
description: Size of the file, in human-readable format, following IEC standard.
|
||||
type: str
|
||||
sample: 500.0 KiB
|
||||
si:
|
||||
description: Size of the file, in human-readable format, following SI standard.
|
||||
type: str
|
||||
sample: 512.0 kB
|
||||
|
||||
size_diff:
|
||||
description: Difference (positive or negative) between old size and new size, in bytes.
|
||||
type: int
|
||||
sample: -1234567890
|
||||
returned: always
|
||||
|
||||
path:
|
||||
description: Realpath of the file if it is a symlink, otherwise the same than module's param.
|
||||
type: str
|
||||
sample: /var/swap0
|
||||
returned: always
|
||||
'''
|
||||
|
||||
|
||||
import re
|
||||
import os
|
||||
import math
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils._text import to_native
|
||||
|
||||
|
||||
# These are the multiplicative suffixes understood (or returned) by dd and
|
||||
# others (ls, df, lvresize, lsblk...).
|
||||
SIZE_UNITS = dict(
|
||||
B=1,
|
||||
kB=1000**1, KB=1000**1, KiB=1024**1, K=1024**1, k=1024**1,
|
||||
MB=1000**2, mB=1000**2, MiB=1024**2, M=1024**2, m=1024**2,
|
||||
GB=1000**3, gB=1000**3, GiB=1024**3, G=1024**3, g=1024**3,
|
||||
TB=1000**4, tB=1000**4, TiB=1024**4, T=1024**4, t=1024**4,
|
||||
PB=1000**5, pB=1000**5, PiB=1024**5, P=1024**5, p=1024**5,
|
||||
EB=1000**6, eB=1000**6, EiB=1024**6, E=1024**6, e=1024**6,
|
||||
ZB=1000**7, zB=1000**7, ZiB=1024**7, Z=1024**7, z=1024**7,
|
||||
YB=1000**8, yB=1000**8, YiB=1024**8, Y=1024**8, y=1024**8,
|
||||
)
|
||||
|
||||
|
||||
def bytes_to_human(size, iec=False):
|
||||
"""Return human-readable size (with SI or IEC suffix) from bytes. This is
|
||||
only to populate the returned result of the module, not to handle the
|
||||
file itself (we only rely on bytes for that).
|
||||
"""
|
||||
unit = 'B'
|
||||
for (u, v) in SIZE_UNITS.items():
|
||||
if size < v:
|
||||
continue
|
||||
if iec:
|
||||
if 'i' not in u or size / v >= 1024:
|
||||
continue
|
||||
else:
|
||||
if v % 5 or size / v >= 1000:
|
||||
continue
|
||||
unit = u
|
||||
|
||||
hsize = round(size / SIZE_UNITS[unit], 2)
|
||||
if unit == 'B':
|
||||
hsize = int(hsize)
|
||||
|
||||
unit = re.sub(r'^(.)', lambda m: m.expand(r'\1').upper(), unit)
|
||||
if unit == 'KB':
|
||||
unit = 'kB'
|
||||
|
||||
return '%s %s' % (str(hsize), unit)
|
||||
|
||||
|
||||
def smart_blocksize(size, unit, product, bsize):
|
||||
"""Ensure the total size can be written as blocks*blocksize, with blocks
|
||||
and blocksize being integers.
|
||||
"""
|
||||
if not product % bsize:
|
||||
return bsize
|
||||
|
||||
# Basically, for a file of 8kB (=8000B), system's block size of 4096 bytes
|
||||
# is not usable. The smallest integer number of kB to work with 512B blocks
|
||||
# is 64, the nexts are 128, 192, 256, and so on.
|
||||
|
||||
unit_size = SIZE_UNITS[unit]
|
||||
|
||||
if size == int(size):
|
||||
if unit_size > SIZE_UNITS['MiB']:
|
||||
if unit_size % 5:
|
||||
return SIZE_UNITS['MiB']
|
||||
return SIZE_UNITS['MB']
|
||||
return unit_size
|
||||
|
||||
if unit == 'B':
|
||||
raise AssertionError("byte is the smallest unit and requires an integer value")
|
||||
|
||||
if 0 < product < bsize:
|
||||
return product
|
||||
|
||||
for bsz in (1024, 1000, 512, 256, 128, 100, 64, 32, 16, 10, 8, 4, 2):
|
||||
if not product % bsz:
|
||||
return bsz
|
||||
return 1
|
||||
|
||||
|
||||
def split_size_unit(string, isint=False):
|
||||
"""Split a string between the size value (int or float) and the unit.
|
||||
Support optional space(s) between the numeric value and the unit.
|
||||
"""
|
||||
unit = re.sub(r'(\d|\.)', r'', string).strip()
|
||||
value = float(re.sub(r'%s' % unit, r'', string).strip())
|
||||
if isint and unit in ('B', ''):
|
||||
if int(value) != value:
|
||||
raise AssertionError("invalid blocksize value: bytes require an integer value")
|
||||
|
||||
if not unit:
|
||||
unit = None
|
||||
product = int(round(value))
|
||||
else:
|
||||
if unit not in SIZE_UNITS.keys():
|
||||
raise AssertionError("invalid size unit (%s): unit must be one of %s, or none." %
|
||||
(unit, ', '.join(sorted(SIZE_UNITS, key=SIZE_UNITS.get))))
|
||||
product = int(round(value * SIZE_UNITS[unit]))
|
||||
return value, unit, product
|
||||
|
||||
|
||||
def size_string(value):
|
||||
"""Convert a raw value to a string, but only if it is an integer, a float
|
||||
or a string itself.
|
||||
"""
|
||||
if not isinstance(value, (int, float, str)):
|
||||
raise AssertionError("invalid value type (%s): size must be integer, float or string" % type(value))
|
||||
return str(value)
|
||||
|
||||
|
||||
def size_spec(args):
|
||||
"""Return a dictionary with size specifications, especially the size in
|
||||
bytes (after rounding it to an integer number of blocks).
|
||||
"""
|
||||
blocksize_in_bytes = split_size_unit(args['blocksize'], True)[2]
|
||||
if blocksize_in_bytes == 0:
|
||||
raise AssertionError("block size cannot be equal to zero")
|
||||
|
||||
size_value, size_unit, size_result = split_size_unit(args['size'])
|
||||
if not size_unit:
|
||||
blocks = int(math.ceil(size_value))
|
||||
else:
|
||||
blocksize_in_bytes = smart_blocksize(size_value, size_unit, size_result, blocksize_in_bytes)
|
||||
blocks = int(math.ceil(size_result / blocksize_in_bytes))
|
||||
|
||||
args['size_diff'] = round_bytes = int(blocks * blocksize_in_bytes)
|
||||
args['size_spec'] = dict(blocks=blocks, blocksize=blocksize_in_bytes, bytes=round_bytes,
|
||||
iec=bytes_to_human(round_bytes, True),
|
||||
si=bytes_to_human(round_bytes))
|
||||
return args['size_spec']
|
||||
|
||||
|
||||
def current_size(args):
|
||||
"""Return the size of the file at the given location if it exists, or None."""
|
||||
path = args['path']
|
||||
if os.path.exists(path):
|
||||
if not os.path.isfile(path):
|
||||
raise AssertionError("%s exists but is not a regular file" % path)
|
||||
args['file_size'] = os.stat(path).st_size
|
||||
else:
|
||||
args['file_size'] = None
|
||||
return args['file_size']
|
||||
|
||||
|
||||
def complete_dd_cmdline(args, dd_cmd):
|
||||
"""Compute dd options to grow or truncate a file."""
|
||||
if args['file_size'] == args['size_spec']['bytes'] and not args['force']:
|
||||
# Nothing to do.
|
||||
return list()
|
||||
|
||||
bs = args['size_spec']['blocksize']
|
||||
conv = list()
|
||||
|
||||
# For sparse files (create, truncate, grow): write count=0 block.
|
||||
if args['sparse']:
|
||||
seek = args['size_spec']['blocks']
|
||||
conv += ['sparse']
|
||||
elif args['force'] or not os.path.exists(args['path']): # Create file
|
||||
seek = 0
|
||||
elif args['size_diff'] < 0: # Truncate file
|
||||
seek = args['size_spec']['blocks']
|
||||
elif args['size_diff'] % bs: # Grow file
|
||||
seek = int(args['file_size'] / bs) + 1
|
||||
else:
|
||||
seek = int(args['file_size'] / bs)
|
||||
|
||||
count = args['size_spec']['blocks'] - seek
|
||||
dd_cmd += ['bs=%s' % str(bs), 'seek=%s' % str(seek), 'count=%s' % str(count)]
|
||||
if conv:
|
||||
dd_cmd += ['conv=%s' % ','.join(conv)]
|
||||
|
||||
return dd_cmd
|
||||
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
path=dict(type='path', required=True),
|
||||
size=dict(type='raw', required=True),
|
||||
blocksize=dict(type='raw'),
|
||||
source=dict(type='path', default='/dev/zero'),
|
||||
sparse=dict(type='bool', default=False),
|
||||
force=dict(type='bool', default=False),
|
||||
),
|
||||
supports_check_mode=True,
|
||||
add_file_common_args=True,
|
||||
)
|
||||
args = dict(**module.params)
|
||||
diff = dict(before=dict(), after=dict())
|
||||
|
||||
if args['sparse'] and args['force']:
|
||||
module.fail_json(msg='parameters values are mutually exclusive: force=true|sparse=true')
|
||||
if not os.path.exists(os.path.dirname(args['path'])):
|
||||
module.fail_json(msg='parent directory of the file must exist prior to run this module')
|
||||
if not args['blocksize']:
|
||||
args['blocksize'] = str(os.statvfs(os.path.dirname(args['path'])).f_frsize)
|
||||
|
||||
try:
|
||||
args['size'] = size_string(args['size'])
|
||||
args['blocksize'] = size_string(args['blocksize'])
|
||||
initial_filesize = current_size(args)
|
||||
size_descriptors = size_spec(args)
|
||||
except AssertionError as err:
|
||||
module.fail_json(msg=to_native(err))
|
||||
|
||||
expected_filesize = size_descriptors['bytes']
|
||||
if initial_filesize:
|
||||
args['size_diff'] = expected_filesize - initial_filesize
|
||||
diff['after']['size'] = expected_filesize
|
||||
diff['before']['size'] = initial_filesize
|
||||
|
||||
result = dict(
|
||||
changed=args['force'],
|
||||
size_diff=args['size_diff'],
|
||||
path=args['path'],
|
||||
filesize=size_descriptors)
|
||||
|
||||
dd_bin = module.get_bin_path('dd', True)
|
||||
dd_cmd = [dd_bin, 'if=%s' % args['source'], 'of=%s' % args['path']]
|
||||
|
||||
if expected_filesize != initial_filesize or args['force']:
|
||||
result['cmd'] = ' '.join(complete_dd_cmdline(args, dd_cmd))
|
||||
if module.check_mode:
|
||||
result['changed'] = True
|
||||
else:
|
||||
result['rc'], dummy, result['stderr'] = module.run_command(dd_cmd)
|
||||
|
||||
diff['after']['size'] = result_filesize = result['size_diff'] = current_size(args)
|
||||
if initial_filesize:
|
||||
result['size_diff'] = result_filesize - initial_filesize
|
||||
if not args['force']:
|
||||
result['changed'] = result_filesize != initial_filesize
|
||||
|
||||
if result['rc']:
|
||||
msg = "dd error while creating file %s with size %s from source %s: see stderr for details" % (
|
||||
args['path'], args['size'], args['source'])
|
||||
module.fail_json(msg=msg, **result)
|
||||
if result_filesize != expected_filesize:
|
||||
msg = "module error while creating file %s with size %s from source %s: file is %s bytes long" % (
|
||||
args['path'], args['size'], args['source'], result_filesize)
|
||||
module.fail_json(msg=msg, **result)
|
||||
|
||||
# dd follows symlinks, and so does this module, while file module doesn't.
|
||||
# If we call it, this is to manage file's mode, owner and so on, not the
|
||||
# symlink's ones.
|
||||
file_params = dict(**module.params)
|
||||
if os.path.islink(args['path']):
|
||||
file_params['path'] = result['path'] = os.path.realpath(args['path'])
|
||||
|
||||
if args['file_size'] is not None:
|
||||
file_args = module.load_file_common_arguments(file_params)
|
||||
result['changed'] = module.set_fs_attributes_if_different(file_args, result['changed'], diff=diff)
|
||||
result['diff'] = diff
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -52,8 +52,10 @@ options:
|
||||
description:
|
||||
- If C(yes), which will replace the remote file when contents are different than the source.
|
||||
- If C(no), the file will only be extracted and copied if the destination does not already exist.
|
||||
- Alias C(thirsty) has been deprecated and will be removed in community.general 3.0.0.
|
||||
type: bool
|
||||
default: yes
|
||||
aliases: [ thirsty ]
|
||||
executable:
|
||||
description:
|
||||
- The path to the C(7z) executable to use for extracting files from the ISO.
|
||||
@@ -99,7 +101,8 @@ def main():
|
||||
image=dict(type='path', required=True, aliases=['path', 'src']),
|
||||
dest=dict(type='path', required=True),
|
||||
files=dict(type='list', elements='str', required=True),
|
||||
force=dict(type='bool', default=True),
|
||||
force=dict(type='bool', default=True, aliases=['thirsty'],
|
||||
deprecated_aliases=[dict(name='thirsty', version='3.0.0', collection_name='community.general')]),
|
||||
executable=dict(type='path'), # No default on purpose
|
||||
),
|
||||
supports_check_mode=True,
|
||||
|
||||
@@ -285,22 +285,6 @@ EXAMPLES = r'''
|
||||
z: http://z.test
|
||||
attribute: z:my_namespaced_attribute
|
||||
value: 'false'
|
||||
|
||||
- name: Adding building nodes with floor subnodes from a YAML variable
|
||||
community.general.xml:
|
||||
path: /foo/bar.xml
|
||||
xpath: /business
|
||||
add_children:
|
||||
- building:
|
||||
# Attributes
|
||||
name: Scumm bar
|
||||
location: Monkey island
|
||||
# Subnodes
|
||||
_:
|
||||
- floor: Pirate hall
|
||||
- floor: Grog storage
|
||||
- construction_date: "1990" # Only strings are valid
|
||||
- building: Grog factory
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
files/filesize.py
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user