mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-04-28 17:36:49 +00:00
Compare commits
277 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80fbcf2f98 | ||
|
|
a722e038cc | ||
|
|
19c8d2164d | ||
|
|
d4656ffca2 | ||
|
|
b49607f12d | ||
|
|
af0ce4284f | ||
|
|
f5f862617a | ||
|
|
a1a4ba4337 | ||
|
|
b0b783f8ff | ||
|
|
e670ca666a | ||
|
|
49b991527e | ||
|
|
e6cc671a0d | ||
|
|
797ea23e50 | ||
|
|
4d23b7a48b | ||
|
|
020b47a1a9 | ||
|
|
0da9d956a0 | ||
|
|
5691e3aff3 | ||
|
|
007333dbfe | ||
|
|
05666b0e4d | ||
|
|
c934d9aeb5 | ||
|
|
5b15e4089a | ||
|
|
a6379e45ce | ||
|
|
b95176dbc8 | ||
|
|
b752fea121 | ||
|
|
cf50990fed | ||
|
|
45343e6bc0 | ||
|
|
51540f6345 | ||
|
|
74eba52028 | ||
|
|
b920e8abf2 | ||
|
|
75c0004e1e | ||
|
|
be42fd4af7 | ||
|
|
1c05908ff6 | ||
|
|
ea42b75378 | ||
|
|
0330f4b52c | ||
|
|
1d8c659ba2 | ||
|
|
e784254679 | ||
|
|
d5e1edd284 | ||
|
|
2cc3ce0230 | ||
|
|
99c564398a | ||
|
|
ffd73296de | ||
|
|
aea12899cc | ||
|
|
1b79440896 | ||
|
|
5195536bd8 | ||
|
|
8ddb81a36f | ||
|
|
399c0ef849 | ||
|
|
f11f6595cc | ||
|
|
2799cd4ac7 | ||
|
|
e0b731e76f | ||
|
|
fb1b756d48 | ||
|
|
31c9ed0fe6 | ||
|
|
6f6b80fd89 | ||
|
|
ca48917b4f | ||
|
|
5ca19086a4 | ||
|
|
96ad40ac1c | ||
|
|
32d071e349 | ||
|
|
8db59ff02d | ||
|
|
e1d28cf052 | ||
|
|
c768060d95 | ||
|
|
68243063d1 | ||
|
|
cecbc2be2d | ||
|
|
fe2757f057 | ||
|
|
8ab19fc50b | ||
|
|
f7928d3eb7 | ||
|
|
fc12eca65d | ||
|
|
0231dad3e8 | ||
|
|
6ab9b05da3 | ||
|
|
5b4fab80e2 | ||
|
|
84a79c3da4 | ||
|
|
49c07dc18b | ||
|
|
7aaa26b591 | ||
|
|
412b4711c3 | ||
|
|
b10d707a8b | ||
|
|
04bf8137fa | ||
|
|
20401c63cd | ||
|
|
eb3ee83146 | ||
|
|
93046e0350 | ||
|
|
fbbd8ecd6f | ||
|
|
d5c26b6f70 | ||
|
|
f87a39b21d | ||
|
|
91a0264f38 | ||
|
|
6a8eb7b388 | ||
|
|
ec9c23437c | ||
|
|
721589827e | ||
|
|
f9e3e229dd | ||
|
|
1400051890 | ||
|
|
118d903e7d | ||
|
|
d09bc2525b | ||
|
|
3a8206fe62 | ||
|
|
f77aa51ab8 | ||
|
|
123b5a9a3c | ||
|
|
085c43b76b | ||
|
|
69a9a77b65 | ||
|
|
f4858d64f4 | ||
|
|
f97d5ca701 | ||
|
|
bfd6d2b3aa | ||
|
|
081c534d40 | ||
|
|
98af8161b2 | ||
|
|
1f001cafd9 | ||
|
|
8ab356520d | ||
|
|
89b7e7191f | ||
|
|
7356451aa1 | ||
|
|
31645ded11 | ||
|
|
fa13826273 | ||
|
|
5502e4ec17 | ||
|
|
8eb2331aea | ||
|
|
f0b7c6351e | ||
|
|
4b71e088c7 | ||
|
|
0cd0f0eaf6 | ||
|
|
b6ae47c455 | ||
|
|
4b6722d938 | ||
|
|
595d590862 | ||
|
|
7f91821bcc | ||
|
|
40ce0f995b | ||
|
|
7145204594 | ||
|
|
beb3b85a4f | ||
|
|
9aec9b502e | ||
|
|
9a5191d1f9 | ||
|
|
6bea8215c9 | ||
|
|
eb851d4208 | ||
|
|
d2070277e8 | ||
|
|
533e01a3f9 | ||
|
|
b81a7cdd16 | ||
|
|
b97e31dd55 | ||
|
|
d92d0632eb | ||
|
|
95156a11a1 | ||
|
|
c8885fdfbd | ||
|
|
3312ae08af | ||
|
|
1d1cbc4f56 | ||
|
|
f1dbef4143 | ||
|
|
604a5dbf49 | ||
|
|
3355e65781 | ||
|
|
19db6f24f7 | ||
|
|
eb24e33666 | ||
|
|
73bb0f1900 | ||
|
|
0de196413f | ||
|
|
0bc76c98b0 | ||
|
|
cdc415ea1f | ||
|
|
e7a0a12c3f | ||
|
|
62cd38a9a0 | ||
|
|
2558cd3f01 | ||
|
|
de8e2a83e2 | ||
|
|
db26514bf1 | ||
|
|
04f46f0435 | ||
|
|
94cf07efbf | ||
|
|
926c0a71d0 | ||
|
|
be13f41b30 | ||
|
|
7fe9dd7a60 | ||
|
|
09351d9010 | ||
|
|
88994ef2b7 | ||
|
|
af441aecfc | ||
|
|
5fc56676c2 | ||
|
|
6529390901 | ||
|
|
c147d2fb98 | ||
|
|
68fc48cd1f | ||
|
|
81f3ad45c9 | ||
|
|
606eb0df15 | ||
|
|
ff9f98795e | ||
|
|
f5a9584ae6 | ||
|
|
24f8be834a | ||
|
|
a23fc67f1f | ||
|
|
efd441407f | ||
|
|
79fb3e9852 | ||
|
|
0b2ebabd29 | ||
|
|
8225b745f3 | ||
|
|
fe61be3e11 | ||
|
|
4fbef900e1 | ||
|
|
0f61ae4841 | ||
|
|
3162ed6795 | ||
|
|
84b54ad6a2 | ||
|
|
f8859af377 | ||
|
|
49d9a257ef | ||
|
|
4676ca584b | ||
|
|
1ea080762b | ||
|
|
178209be27 | ||
|
|
d0bb74a03b | ||
|
|
7452a53647 | ||
|
|
36daa7c48e | ||
|
|
1ca9229c66 | ||
|
|
2906591c08 | ||
|
|
088743749b | ||
|
|
a013e69d67 | ||
|
|
ff4e4c055c | ||
|
|
53c6b49673 | ||
|
|
7425e9840d | ||
|
|
1133e5c865 | ||
|
|
f49cf2c22d | ||
|
|
5fdbe084e7 | ||
|
|
e9866a2ccd | ||
|
|
ac95ff5b45 | ||
|
|
dec345b818 | ||
|
|
ce5aea790d | ||
|
|
ad8aa1b1e6 | ||
|
|
3f882ee6a2 | ||
|
|
677ab8e383 | ||
|
|
4f98136771 | ||
|
|
585dd0b6ed | ||
|
|
bec43041a9 | ||
|
|
b4c136125e | ||
|
|
4a8d6cf7cc | ||
|
|
20bd065e77 | ||
|
|
ea65ce8e0d | ||
|
|
811b609b05 | ||
|
|
5447910a0b | ||
|
|
76d9fe4ec6 | ||
|
|
afe9d0fdb3 | ||
|
|
71706031c7 | ||
|
|
36dea9ab97 | ||
|
|
bb7ce740fe | ||
|
|
cf5e9bf44c | ||
|
|
434f383ae9 | ||
|
|
e353390e6c | ||
|
|
0b9893959f | ||
|
|
305748b333 | ||
|
|
abfbe2a48d | ||
|
|
c0f3a63e18 | ||
|
|
389b004879 | ||
|
|
fdb66d5567 | ||
|
|
57f56b02d8 | ||
|
|
a44ffdc20d | ||
|
|
682674dd5f | ||
|
|
5135587c16 | ||
|
|
e0dd4b240f | ||
|
|
a1badbb5b2 | ||
|
|
6165438689 | ||
|
|
3778eac1ba | ||
|
|
03b7b39424 | ||
|
|
6dd4cd0eb7 | ||
|
|
03fd6bd008 | ||
|
|
f33323ca89 | ||
|
|
5aac81bdd1 | ||
|
|
8fae693d9c | ||
|
|
1cce279424 | ||
|
|
d09a558fda | ||
|
|
bd372939bc | ||
|
|
41bc7816f3 | ||
|
|
865acdd4cf | ||
|
|
e247300523 | ||
|
|
367c3c43ff | ||
|
|
0a5f79724c | ||
|
|
f12df1d21b | ||
|
|
ba4a98b1be | ||
|
|
436bbb0077 | ||
|
|
e9551df5ed | ||
|
|
9a6031ab4e | ||
|
|
562ff7efb7 | ||
|
|
93e0aa7557 | ||
|
|
9aef0ed17e | ||
|
|
af64c9a432 | ||
|
|
d1e54d2fd1 | ||
|
|
e898e52d1b | ||
|
|
89ffb04dff | ||
|
|
c03ae754d2 | ||
|
|
909ac92fe2 | ||
|
|
29bd5a9486 | ||
|
|
f4e60e09ac | ||
|
|
d4f3a47d48 | ||
|
|
701a89eb1c | ||
|
|
dd0b54b9b5 | ||
|
|
f509f2c896 | ||
|
|
43da5b88db | ||
|
|
ae8edc02e1 | ||
|
|
2297f2f802 | ||
|
|
aa95d8a5b7 | ||
|
|
b40a5ef09a | ||
|
|
4e70c0c55a | ||
|
|
e8886fa711 | ||
|
|
8dbb13edd4 | ||
|
|
6d86564308 | ||
|
|
165719d084 | ||
|
|
1591d52b78 | ||
|
|
8afdd23be4 | ||
|
|
6af3c96d8e | ||
|
|
d0f097c871 | ||
|
|
9c648c8e3a | ||
|
|
00f5f7dfe7 | ||
|
|
b6774971a6 | ||
|
|
83afe0f868 |
38
.github/BOTMETA.yml
vendored
38
.github/BOTMETA.yml
vendored
@@ -63,6 +63,8 @@ files:
|
||||
maintainers: giner
|
||||
$filters/from_csv.py:
|
||||
maintainers: Ajpantuso
|
||||
$filters/hashids:
|
||||
maintainers: Ajpantuso
|
||||
$filters/jc.py:
|
||||
maintainers: kellyjonbrazil
|
||||
$filters/list.py:
|
||||
@@ -86,6 +88,8 @@ 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:
|
||||
@@ -153,7 +157,6 @@ 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
|
||||
@@ -197,8 +200,6 @@ files:
|
||||
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
|
||||
@@ -347,6 +348,8 @@ 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:
|
||||
@@ -360,8 +363,6 @@ 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:
|
||||
@@ -374,6 +375,8 @@ 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:
|
||||
@@ -466,8 +469,6 @@ 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:
|
||||
@@ -566,7 +567,7 @@ files:
|
||||
maintainers: dmtrs
|
||||
ignore: resmo
|
||||
$modules/packaging/language/cpanm.py:
|
||||
maintainers: fcuny
|
||||
maintainers: fcuny russoz
|
||||
$modules/packaging/language/easy_install.py:
|
||||
maintainers: mattupstate
|
||||
$modules/packaging/language/gem.py:
|
||||
@@ -715,12 +716,6 @@ files:
|
||||
labels: zypper
|
||||
$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
|
||||
@@ -740,8 +735,6 @@ 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:
|
||||
@@ -790,12 +783,6 @@ 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/:
|
||||
@@ -817,9 +804,6 @@ 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
|
||||
@@ -950,10 +934,6 @@ 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:
|
||||
|
||||
135
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
135
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
---
|
||||
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
Normal file
27
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
---
|
||||
# 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
Normal file
111
.github/ISSUE_TEMPLATE/documentation_report.yml
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
---
|
||||
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
Normal file
69
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
---
|
||||
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
|
||||
...
|
||||
1311
CHANGELOG.rst
1311
CHANGELOG.rst
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
# 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.
|
||||
@@ -78,7 +78,7 @@ Basic instructions without release branches:
|
||||
|
||||
## Release notes
|
||||
|
||||
See the [changelog](https://github.com/ansible-collections/community.general/blob/stable-2/CHANGELOG.rst).
|
||||
See the [changelog](https://github.com/ansible-collections/community.general/blob/stable-3/CHANGELOG.rst).
|
||||
|
||||
## Roadmap
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
namespace: community
|
||||
name: general
|
||||
version: 2.5.2
|
||||
version: 3.0.2
|
||||
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:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.ali_instance_info instead.
|
||||
docker_compose:
|
||||
@@ -159,8 +159,7 @@ plugin_routing:
|
||||
gcpubsub_info:
|
||||
redirect: community.google.gcpubsub_info
|
||||
gcpubsub_facts:
|
||||
redirect: community.google.gcpubsub_info
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.google.gcpubsub_info instead.
|
||||
gcspanner:
|
||||
@@ -171,22 +170,23 @@ plugin_routing:
|
||||
tombstone:
|
||||
removal_version: 2.0.0
|
||||
warning_text: Use community.general.github_webhook and community.general.github_webhook_info 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.
|
||||
# Adding tombstones burns the old name, so we simply remove the entries:
|
||||
# gluster_heal_info:
|
||||
# tombstone:
|
||||
# removal_version: 3.0.0
|
||||
# warning_text: The gluster modules have migrated to the gluster.gluster collection. Use gluster.gluster.gluster_heal_info instead.
|
||||
# gluster_peer:
|
||||
# tombstone:
|
||||
# removal_version: 3.0.0
|
||||
# warning_text: The gluster modules have migrated to the gluster.gluster collection. Use gluster.gluster.gluster_peer instead.
|
||||
# gluster_volume:
|
||||
# tombstone:
|
||||
# removal_version: 3.0.0
|
||||
# warning_text: The gluster modules have migrated to the gluster.gluster collection. Use gluster.gluster.gluster_volume instead.
|
||||
# helm:
|
||||
# tombstone:
|
||||
# removal_version: 3.0.0
|
||||
# warning_text: Use community.kubernetes.helm instead.
|
||||
hetzner_failover_ip:
|
||||
redirect: community.hrobot.failover_ip
|
||||
hetzner_failover_ip_info:
|
||||
@@ -196,15 +196,19 @@ plugin_routing:
|
||||
hetzner_firewall_info:
|
||||
redirect: community.hrobot.firewall_info
|
||||
hpilo_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.hpilo_info instead.
|
||||
idrac_firmware:
|
||||
redirect: dellemc.openmanage.idrac_firmware
|
||||
idrac_redfish_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
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:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.jenkins_job_info instead.
|
||||
katello:
|
||||
@@ -224,7 +228,7 @@ plugin_routing:
|
||||
kubevirt_vm:
|
||||
redirect: community.kubevirt.kubevirt_vm
|
||||
ldap_attr:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.ldap_attrs instead.
|
||||
logicmonitor:
|
||||
@@ -236,11 +240,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:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.memset_memstore_info instead.
|
||||
memset_server_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.memset_server_info instead.
|
||||
na_cdot_aggregate:
|
||||
@@ -276,159 +280,161 @@ plugin_routing:
|
||||
removal_version: 2.0.0
|
||||
warning_text: Use netapp.ontap.na_ontap_volume instead.
|
||||
na_ontap_gather_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use netapp.ontap.na_ontap_info instead.
|
||||
nginx_status_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
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:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.one_image_info instead.
|
||||
onepassword_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.onepassword_info instead.
|
||||
oneview_datacenter_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.oneview_datacenter_info instead.
|
||||
oneview_enclosure_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.oneview_enclosure_info instead.
|
||||
oneview_ethernet_network_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.oneview_ethernet_network_info instead.
|
||||
oneview_fc_network_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.oneview_fc_network_info instead.
|
||||
oneview_fcoe_network_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.oneview_fcoe_network_info instead.
|
||||
oneview_logical_interconnect_group_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.oneview_logical_interconnect_group_info instead.
|
||||
oneview_network_set_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.oneview_network_set_info instead.
|
||||
oneview_san_manager_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.oneview_san_manager_info instead.
|
||||
online_server_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.online_server_info instead.
|
||||
online_user_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.online_user_info instead.
|
||||
ovirt:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_vm instead.
|
||||
ovirt_affinity_label_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_affinity_label_info instead.
|
||||
ovirt_api_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_api_info instead.
|
||||
ovirt_cluster_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_cluster_info instead.
|
||||
ovirt_datacenter_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_datacenter_info instead.
|
||||
ovirt_disk_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_disk_info instead.
|
||||
ovirt_event_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_event_info instead.
|
||||
ovirt_external_provider_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_external_provider_info instead.
|
||||
ovirt_group_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_group_info instead.
|
||||
ovirt_host_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_host_info instead.
|
||||
ovirt_host_storage_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_host_storage_info instead.
|
||||
ovirt_network_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_network_info instead.
|
||||
ovirt_nic_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_nic_info instead.
|
||||
ovirt_permission_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_permission_info instead.
|
||||
ovirt_quota_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_quota_info instead.
|
||||
ovirt_scheduling_policy_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_scheduling_policy_info instead.
|
||||
ovirt_snapshot_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_snapshot_info instead.
|
||||
ovirt_storage_domain_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_storage_domain_info instead.
|
||||
ovirt_storage_template_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_storage_template_info instead.
|
||||
ovirt_storage_vm_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_storage_vm_info instead.
|
||||
ovirt_tag_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_tag_info instead.
|
||||
ovirt_template_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_template_info instead.
|
||||
ovirt_user_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_user_info instead.
|
||||
ovirt_vm_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_vm_info instead.
|
||||
ovirt_vmpool_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use ovirt.ovirt.ovirt_vmpool_info instead.
|
||||
postgresql_copy:
|
||||
@@ -476,47 +482,47 @@ plugin_routing:
|
||||
postgresql_user:
|
||||
redirect: community.postgresql.postgresql_user
|
||||
purefa_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use purestorage.flasharray.purefa_info instead.
|
||||
purefb_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use purestorage.flashblade.purefb_info instead.
|
||||
python_requirements_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.python_requirements_info instead.
|
||||
redfish_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.redfish_info instead.
|
||||
scaleway_image_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.scaleway_image_info instead.
|
||||
scaleway_ip_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.scaleway_ip_info instead.
|
||||
scaleway_organization_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.scaleway_organization_info instead.
|
||||
scaleway_security_group_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.scaleway_security_group_info instead.
|
||||
scaleway_server_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.scaleway_server_info instead.
|
||||
scaleway_snapshot_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.scaleway_snapshot_info instead.
|
||||
scaleway_volume_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.scaleway_volume_info instead.
|
||||
sf_account_manager:
|
||||
@@ -540,15 +546,15 @@ plugin_routing:
|
||||
removal_version: 2.0.0
|
||||
warning_text: Use netapp.elementsw.na_elementsw_volume instead.
|
||||
smartos_image_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.smartos_image_info instead.
|
||||
vertica_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.vertica_info instead.
|
||||
xenserver_guest_facts:
|
||||
deprecation:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.xenserver_guest_info instead.
|
||||
doc_fragments:
|
||||
@@ -565,6 +571,8 @@ 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:
|
||||
@@ -579,6 +587,8 @@ 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:
|
||||
|
||||
@@ -30,7 +30,6 @@ options:
|
||||
description:
|
||||
- Keycloak realm name to authenticate to for API access.
|
||||
type: str
|
||||
required: true
|
||||
|
||||
auth_client_secret:
|
||||
description:
|
||||
@@ -41,7 +40,6 @@ options:
|
||||
description:
|
||||
- Username to authenticate for API access with.
|
||||
type: str
|
||||
required: true
|
||||
aliases:
|
||||
- username
|
||||
|
||||
@@ -49,10 +47,15 @@ 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).
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
# -*- 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"
|
||||
'''
|
||||
97
plugins/filter/hashids.py
Normal file
97
plugins/filter/hashids.py
Normal file
@@ -0,0 +1,97 @@
|
||||
# -*- 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,
|
||||
}
|
||||
950
plugins/inventory/lxd.py
Normal file
950
plugins/inventory/lxd.py
Normal file
@@ -0,0 +1,950 @@
|
||||
# -*- 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()
|
||||
@@ -70,6 +70,13 @@ 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:
|
||||
@@ -234,13 +241,22 @@ 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'],
|
||||
'ip-addresses': [
|
||||
"%s/%s" % (ip['ip-address'], ip['prefix']) for ip in iface['ip-addresses']
|
||||
]
|
||||
'mac-address': iface['hardware-address'] if 'hardware-address' in iface else '',
|
||||
'ip-addresses': ["%s/%s" % (ip['ip-address'], ip['prefix']) for ip in iface['ip-addresses']] if 'ip-addresses' in iface else []
|
||||
})
|
||||
except requests.HTTPError:
|
||||
pass
|
||||
@@ -354,8 +370,9 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
self.inventory.add_child(nodes_group, node['node'])
|
||||
|
||||
# get node IP address
|
||||
ip = self._get_node_ip(node['node'])
|
||||
self.inventory.set_variable(node['node'], 'ansible_host', ip)
|
||||
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)
|
||||
|
||||
# get LXC containers for this node
|
||||
node_lxc_group = self.to_safe('%s%s' % (self.get_option('group_prefix'), ('%s_lxc' % node['node']).lower()))
|
||||
|
||||
@@ -1,871 +0,0 @@
|
||||
# -*- 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,12 +30,16 @@ 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"
|
||||
@@ -57,11 +61,12 @@ 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', required=True),
|
||||
auth_realm=dict(type='str'),
|
||||
auth_client_secret=dict(type='str', default=None, 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)
|
||||
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),
|
||||
)
|
||||
|
||||
|
||||
@@ -73,41 +78,58 @@ class KeycloakError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def get_token(base_url, validate_certs, auth_realm, client_id,
|
||||
auth_username, auth_password, client_secret):
|
||||
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')
|
||||
|
||||
if not base_url.lower().startswith(('http', 'https')):
|
||||
raise KeycloakError("auth_url '%s' should either start with 'http' or 'https'." % base_url)
|
||||
auth_url = URL_TOKEN.format(url=base_url, realm=auth_realm)
|
||||
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'
|
||||
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,
|
||||
}
|
||||
except KeyError:
|
||||
raise KeycloakError(
|
||||
'Could not obtain access token from %s' % auth_url)
|
||||
# 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'
|
||||
}
|
||||
|
||||
|
||||
class KeycloakAPI(object):
|
||||
@@ -120,6 +142,75 @@ 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,11 +19,10 @@ PATCH_HEADERS = {'content-type': 'application/json', 'accept': 'application/json
|
||||
'OData-Version': '4.0'}
|
||||
DELETE_HEADERS = {'accept': 'application/json', 'OData-Version': '4.0'}
|
||||
|
||||
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'
|
||||
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.'
|
||||
|
||||
|
||||
class RedfishUtils(object):
|
||||
@@ -267,8 +266,7 @@ class RedfishUtils(object):
|
||||
'ret': False,
|
||||
'msg': "System resource %s not found" % self.resource_id}
|
||||
elif len(self.systems_uris) > 1:
|
||||
self.module.deprecate(DEPRECATE_MSG % {'resource': 'System'},
|
||||
version='3.0.0', collection_name='community.general') # was Ansible 2.14
|
||||
self.module.fail_json(msg=FAIL_MSG % {'resource': 'System'})
|
||||
return {'ret': True}
|
||||
|
||||
def _find_updateservice_resource(self):
|
||||
@@ -318,8 +316,7 @@ class RedfishUtils(object):
|
||||
'ret': False,
|
||||
'msg': "Chassis resource %s not found" % self.resource_id}
|
||||
elif len(self.chassis_uris) > 1:
|
||||
self.module.deprecate(DEPRECATE_MSG % {'resource': 'Chassis'},
|
||||
version='3.0.0', collection_name='community.general') # was Ansible 2.14
|
||||
self.module.fail_json(msg=FAIL_MSG % {'resource': 'Chassis'})
|
||||
return {'ret': True}
|
||||
|
||||
def _find_managers_resource(self):
|
||||
@@ -348,8 +345,7 @@ class RedfishUtils(object):
|
||||
'ret': False,
|
||||
'msg': "Manager resource %s not found" % self.resource_id}
|
||||
elif len(self.manager_uris) > 1:
|
||||
self.module.deprecate(DEPRECATE_MSG % {'resource': 'Manager'},
|
||||
version='3.0.0', collection_name='community.general') # was Ansible 2.14
|
||||
self.module.fail_json(msg=FAIL_MSG % {'resource': 'Manager'})
|
||||
return {'ret': True}
|
||||
|
||||
def _get_all_action_info_values(self, action):
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
# -*- 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
|
||||
@@ -1,163 +0,0 @@
|
||||
# -*- 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
|
||||
@@ -1 +0,0 @@
|
||||
cloud/alicloud/ali_instance_facts.py
|
||||
@@ -1 +0,0 @@
|
||||
ali_instance_info.py
|
||||
@@ -383,9 +383,6 @@ 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,10 +30,6 @@ 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
|
||||
@@ -185,7 +181,6 @@ 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
|
||||
|
||||
@@ -53,6 +53,13 @@ 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
|
||||
tags:
|
||||
description:
|
||||
- The tags that the instance should be marked under. See
|
||||
@@ -237,6 +244,7 @@ def initialise_module():
|
||||
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'),
|
||||
@@ -282,6 +290,7 @@ 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 +0,0 @@
|
||||
memset_memstore_info.py
|
||||
@@ -151,9 +151,6 @@ 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 +0,0 @@
|
||||
memset_server_info.py
|
||||
@@ -276,9 +276,6 @@ 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()
|
||||
|
||||
@@ -1,216 +0,0 @@
|
||||
#!/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()
|
||||
@@ -1,502 +0,0 @@
|
||||
#!/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
|
||||
|
||||
|
||||
# ------------------------------------------------------------------- #
|
||||
# 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()
|
||||
@@ -33,6 +33,19 @@ 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.
|
||||
@@ -141,6 +154,28 @@ 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,7 +247,7 @@ def _state_args(state_file):
|
||||
return []
|
||||
|
||||
|
||||
def init_plugins(bin_path, project_path, backend_config, backend_config_files, init_reconfigure):
|
||||
def init_plugins(bin_path, project_path, backend_config, backend_config_files, init_reconfigure, plugin_paths):
|
||||
command = [bin_path, 'init', '-input=false']
|
||||
if backend_config:
|
||||
for key, val in backend_config.items():
|
||||
@@ -225,6 +260,9 @@ 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)
|
||||
|
||||
|
||||
@@ -295,6 +333,7 @@ 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']),
|
||||
@@ -316,6 +355,7 @@ 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')
|
||||
@@ -343,7 +383,7 @@ def main():
|
||||
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)
|
||||
init_plugins(command[0], project_path, backend_config, backend_config_files, init_reconfigure, plugin_paths)
|
||||
|
||||
workspace_ctx = get_workspace_context(command[0], project_path)
|
||||
if workspace_ctx["current"] != workspace:
|
||||
|
||||
@@ -1,175 +0,0 @@
|
||||
#!/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()
|
||||
@@ -1,76 +0,0 @@
|
||||
#!/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:
|
||||
- python-oca
|
||||
- pyone
|
||||
options:
|
||||
api_url:
|
||||
description:
|
||||
@@ -88,7 +88,7 @@ EXAMPLES = '''
|
||||
|
||||
- name: Print the IMAGE properties
|
||||
ansible.builtin.debug:
|
||||
msg: result
|
||||
var: result
|
||||
|
||||
- name: Rename existing IMAGE
|
||||
community.general.one_image:
|
||||
@@ -168,21 +168,20 @@ running_vms:
|
||||
'''
|
||||
|
||||
try:
|
||||
import oca
|
||||
HAS_OCA = True
|
||||
import pyone
|
||||
HAS_PYONE = True
|
||||
except ImportError:
|
||||
HAS_OCA = False
|
||||
HAS_PYONE = 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.info(filter=-2)
|
||||
pool = client.imagepool.info(-2, -1, -1, -1)
|
||||
|
||||
for image in pool:
|
||||
for image in pool.IMAGE:
|
||||
if predicate(image):
|
||||
return image
|
||||
|
||||
@@ -190,11 +189,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):
|
||||
@@ -208,30 +207,28 @@ 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, image, wait_timeout, state_predicate):
|
||||
def wait_for_state(module, client, image_id, wait_timeout, state_predicate):
|
||||
import time
|
||||
start_time = time.time()
|
||||
|
||||
while (time.time() - start_time) < wait_timeout:
|
||||
image.info()
|
||||
state = image.state
|
||||
image = client.image.info(image_id)
|
||||
state = image.STATE
|
||||
|
||||
if state_predicate(state):
|
||||
return image
|
||||
@@ -241,19 +238,19 @@ def wait_for_state(module, image, wait_timeout, state_predicate):
|
||||
module.fail_json(msg="Wait timeout has expired!")
|
||||
|
||||
|
||||
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_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_delete(module, image, wait_timeout=60):
|
||||
return wait_for_state(module, image, wait_timeout, lambda state: (state in [IMAGE_STATES.index('DELETE')]))
|
||||
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 enable_image(module, client, image, enable):
|
||||
image.info()
|
||||
image = client.image.info(image.ID)
|
||||
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:
|
||||
@@ -266,7 +263,7 @@ def enable_image(module, client, image, enable):
|
||||
changed = True
|
||||
|
||||
if changed and not module.check_mode:
|
||||
client.call('image.enable', image.id, enable)
|
||||
client.image.enable(image.ID, enable)
|
||||
|
||||
result = get_image_info(image)
|
||||
result['changed'] = changed
|
||||
@@ -276,7 +273,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:
|
||||
@@ -284,13 +281,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.call('image.clone', image.id, new_name)
|
||||
image = get_image_by_id(module, client, new_id)
|
||||
wait_for_ready(module, image)
|
||||
new_id = client.image.clone(image.ID, new_name)
|
||||
wait_for_ready(module, client, new_id)
|
||||
image = client.image.info(new_id)
|
||||
|
||||
result = get_image_info(image)
|
||||
result['changed'] = True
|
||||
@@ -302,7 +299,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
|
||||
@@ -312,7 +309,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.call('image.rename', image.id, new_name)
|
||||
client.image.rename(image.ID, new_name)
|
||||
|
||||
result = get_image_info(image)
|
||||
result['changed'] = True
|
||||
@@ -324,12 +321,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.call('image.delete', image.id)
|
||||
wait_for_delete(module, image)
|
||||
client.image.delete(image.ID)
|
||||
wait_for_delete(module, client, image.ID)
|
||||
|
||||
return {'changed': True}
|
||||
|
||||
@@ -378,8 +375,8 @@ def main():
|
||||
mutually_exclusive=[['id', 'name']],
|
||||
supports_check_mode=True)
|
||||
|
||||
if not HAS_OCA:
|
||||
module.fail_json(msg='This module requires python-oca to work!')
|
||||
if not HAS_PYONE:
|
||||
module.fail_json(msg='This module requires pyone to work!')
|
||||
|
||||
auth = get_connection_info(module)
|
||||
params = module.params
|
||||
@@ -388,7 +385,7 @@ def main():
|
||||
state = params.get('state')
|
||||
enabled = params.get('enabled')
|
||||
new_name = params.get('new_name')
|
||||
client = oca.Client(auth.username + ':' + auth.password, auth.url)
|
||||
client = pyone.OneServer(auth.url, session=auth.username + ':' + auth.password)
|
||||
|
||||
result = {}
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
one_image_info.py
|
||||
@@ -261,9 +261,6 @@ 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!')
|
||||
|
||||
@@ -1,195 +0,0 @@
|
||||
#!/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.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()
|
||||
@@ -1,97 +0,0 @@
|
||||
#!/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.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()
|
||||
@@ -1,124 +0,0 @@
|
||||
#!/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.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()
|
||||
@@ -1,107 +0,0 @@
|
||||
#!/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.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()
|
||||
@@ -1,124 +0,0 @@
|
||||
#!/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.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()
|
||||
@@ -1,169 +0,0 @@
|
||||
#!/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.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()
|
||||
@@ -1,164 +0,0 @@
|
||||
#!/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.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()
|
||||
@@ -1,122 +0,0 @@
|
||||
#!/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.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()
|
||||
@@ -1,148 +0,0 @@
|
||||
#!/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.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()
|
||||
@@ -1,186 +0,0 @@
|
||||
#!/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.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()
|
||||
@@ -1,124 +0,0 @@
|
||||
#!/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.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()
|
||||
@@ -1,142 +0,0 @@
|
||||
#!/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.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()
|
||||
@@ -1,165 +0,0 @@
|
||||
#!/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.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()
|
||||
@@ -1,142 +0,0 @@
|
||||
#!/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.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()
|
||||
@@ -1,140 +0,0 @@
|
||||
#!/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()
|
||||
@@ -1,136 +0,0 @@
|
||||
#!/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.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()
|
||||
@@ -1,125 +0,0 @@
|
||||
#!/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.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()
|
||||
@@ -1,141 +0,0 @@
|
||||
#!/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.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()
|
||||
@@ -1,141 +0,0 @@
|
||||
#!/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.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()
|
||||
@@ -1,171 +0,0 @@
|
||||
#!/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.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()
|
||||
@@ -1,123 +0,0 @@
|
||||
#!/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.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()
|
||||
@@ -1,122 +0,0 @@
|
||||
#!/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.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()
|
||||
@@ -1,165 +0,0 @@
|
||||
#!/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.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()
|
||||
@@ -1,122 +0,0 @@
|
||||
#!/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.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,7 +817,6 @@ 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'),
|
||||
@@ -833,13 +832,6 @@ 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')
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
#!/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()
|
||||
@@ -1,108 +0,0 @@
|
||||
#!/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()
|
||||
@@ -1,104 +0,0 @@
|
||||
#!/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()
|
||||
@@ -1,112 +0,0 @@
|
||||
#!/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()
|
||||
@@ -1,195 +0,0 @@
|
||||
#!/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()
|
||||
@@ -1,113 +0,0 @@
|
||||
#!/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()
|
||||
@@ -1,108 +0,0 @@
|
||||
#!/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 +0,0 @@
|
||||
smartos_image_info.py
|
||||
@@ -47,9 +47,6 @@ 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'] }}
|
||||
@@ -102,20 +99,12 @@ 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())
|
||||
|
||||
if is_old_facts:
|
||||
module.exit_json(ansible_facts=data)
|
||||
else:
|
||||
module.exit_json(**data)
|
||||
module.exit_json(**data)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -23,21 +23,24 @@ requirements:
|
||||
- Univention
|
||||
options:
|
||||
state:
|
||||
required: false
|
||||
type: str
|
||||
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,
|
||||
@@ -45,8 +48,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:
|
||||
required: false
|
||||
default: []
|
||||
type: dict
|
||||
default: {}
|
||||
description:
|
||||
- "Additional data for this record, e.g. ['a': '192.0.2.1'].
|
||||
Required if C(state=present)."
|
||||
@@ -98,7 +101,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,58 +22,64 @@ requirements:
|
||||
- Python >= 2.6
|
||||
options:
|
||||
state:
|
||||
required: false
|
||||
type: str
|
||||
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:
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
description:
|
||||
- List of appropriate name servers. Required if C(state=present).
|
||||
interfaces:
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
description:
|
||||
- List of interface IP addresses, on which the server should
|
||||
response this zone. Required if C(state=present).
|
||||
|
||||
refresh:
|
||||
required: false
|
||||
type: int
|
||||
default: 3600
|
||||
description:
|
||||
- Interval before the zone should be refreshed.
|
||||
retry:
|
||||
required: false
|
||||
type: int
|
||||
default: 1800
|
||||
description:
|
||||
- Interval that should elapse before a failed refresh should be retried.
|
||||
expire:
|
||||
required: false
|
||||
type: int
|
||||
default: 604800
|
||||
description:
|
||||
- Specifies the upper limit on the time interval that can elapse before the zone is no longer authoritative.
|
||||
ttl:
|
||||
required: false
|
||||
type: int
|
||||
default: 600
|
||||
description:
|
||||
- Minimum TTL field that should be exported with any RR from this zone.
|
||||
|
||||
contact:
|
||||
required: false
|
||||
type: str
|
||||
default: ''
|
||||
description:
|
||||
- Contact person in the SOA record.
|
||||
mx:
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
default: []
|
||||
description:
|
||||
- List of MX servers. (Must declared as A or AAAA records).
|
||||
@@ -128,9 +134,11 @@ def main():
|
||||
aliases=['name'],
|
||||
type='str'),
|
||||
nameserver=dict(default=[],
|
||||
type='list'),
|
||||
type='list',
|
||||
elements='str'),
|
||||
interfaces=dict(default=[],
|
||||
type='list'),
|
||||
type='list',
|
||||
elements='str'),
|
||||
refresh=dict(default=3600,
|
||||
type='int'),
|
||||
retry=dict(default=1800,
|
||||
@@ -142,7 +150,8 @@ def main():
|
||||
contact=dict(default='',
|
||||
type='str'),
|
||||
mx=dict(default=[],
|
||||
type='list'),
|
||||
type='list',
|
||||
elements='str'),
|
||||
state=dict(default='present',
|
||||
choices=['present', 'absent'],
|
||||
type='str')
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
xenserver_guest_info.py
|
||||
@@ -204,10 +204,6 @@ 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.
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
vertica_info.py
|
||||
@@ -233,11 +233,6 @@ 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)
|
||||
@@ -269,20 +264,12 @@ def main():
|
||||
configuration_facts = get_configuration_facts(cursor)
|
||||
node_facts = get_node_facts(cursor)
|
||||
|
||||
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)
|
||||
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:
|
||||
|
||||
483
plugins/modules/files/filesize.py
Normal file
483
plugins/modules/files/filesize.py
Normal file
@@ -0,0 +1,483 @@
|
||||
#!/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,10 +52,8 @@ 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.
|
||||
@@ -101,8 +99,7 @@ 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, aliases=['thirsty'],
|
||||
deprecated_aliases=[dict(name='thirsty', version='3.0.0', collection_name='community.general')]),
|
||||
force=dict(type='bool', default=True),
|
||||
executable=dict(type='path'), # No default on purpose
|
||||
),
|
||||
supports_check_mode=True,
|
||||
|
||||
1
plugins/modules/filesize.py
Symbolic link
1
plugins/modules/filesize.py
Symbolic link
@@ -0,0 +1 @@
|
||||
files/filesize.py
|
||||
@@ -1 +0,0 @@
|
||||
./storage/glusterfs/gluster_heal_info.py
|
||||
@@ -1 +0,0 @@
|
||||
./storage/glusterfs/gluster_peer.py
|
||||
@@ -1 +0,0 @@
|
||||
./storage/glusterfs/gluster_volume.py
|
||||
@@ -1 +0,0 @@
|
||||
./cloud/misc/helm.py
|
||||
@@ -1 +0,0 @@
|
||||
remote_management/hpilo/hpilo_facts.py
|
||||
@@ -511,20 +511,30 @@ author:
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Create or update Keycloak client (minimal example)
|
||||
local_action:
|
||||
module: keycloak_client
|
||||
auth_client_id: admin-cli
|
||||
- name: Create or update Keycloak client (minimal example), authentication with credentials
|
||||
community.general.keycloak_client:
|
||||
auth_keycloak_url: https://auth.example.com/auth
|
||||
auth_realm: master
|
||||
auth_username: USERNAME
|
||||
auth_password: PASSWORD
|
||||
client_id: test
|
||||
state: present
|
||||
delegate_to: localhost
|
||||
|
||||
|
||||
- name: Create or update Keycloak client (minimal example), authentication with token
|
||||
community.general.keycloak_client:
|
||||
auth_client_id: admin-cli
|
||||
auth_keycloak_url: https://auth.example.com/auth
|
||||
auth_realm: master
|
||||
token: TOKEN
|
||||
client_id: test
|
||||
state: present
|
||||
delegate_to: localhost
|
||||
|
||||
|
||||
- name: Delete a Keycloak client
|
||||
local_action:
|
||||
module: keycloak_client
|
||||
community.general.keycloak_client:
|
||||
auth_client_id: admin-cli
|
||||
auth_keycloak_url: https://auth.example.com/auth
|
||||
auth_realm: master
|
||||
@@ -532,10 +542,11 @@ EXAMPLES = '''
|
||||
auth_password: PASSWORD
|
||||
client_id: test
|
||||
state: absent
|
||||
delegate_to: localhost
|
||||
|
||||
|
||||
- name: Create or update a Keycloak client (with all the bells and whistles)
|
||||
local_action:
|
||||
module: keycloak_client
|
||||
community.general.keycloak_client:
|
||||
auth_client_id: admin-cli
|
||||
auth_keycloak_url: https://auth.example.com/auth
|
||||
auth_realm: master
|
||||
@@ -619,6 +630,7 @@ EXAMPLES = '''
|
||||
use.jwks.url: true
|
||||
jwks.url: JWKS_URL_FOR_CLIENT_AUTH_JWT
|
||||
jwt.credential.certificate: JWT_CREDENTIAL_CERTIFICATE_FOR_CLIENT_AUTH
|
||||
delegate_to: localhost
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
@@ -740,21 +752,15 @@ def main():
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
required_one_of=([['client_id', 'id']]))
|
||||
required_one_of=([['client_id', 'id'],
|
||||
['token', 'auth_realm', 'auth_username', 'auth_password']]),
|
||||
required_together=([['auth_realm', 'auth_username', 'auth_password']]))
|
||||
|
||||
result = dict(changed=False, msg='', diff={}, proposed={}, existing={}, end_state={})
|
||||
|
||||
# Obtain access token, initialize API
|
||||
try:
|
||||
connection_header = get_token(
|
||||
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'),
|
||||
)
|
||||
connection_header = get_token(module.params)
|
||||
except KeycloakError as e:
|
||||
module.fail_json(msg=str(e))
|
||||
|
||||
|
||||
@@ -169,9 +169,8 @@ author:
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Create or update Keycloak client template (minimal)
|
||||
local_action:
|
||||
module: keycloak_clienttemplate
|
||||
- name: Create or update Keycloak client template (minimal), authentication with credentials
|
||||
community.general.keycloak_client:
|
||||
auth_client_id: admin-cli
|
||||
auth_keycloak_url: https://auth.example.com/auth
|
||||
auth_realm: master
|
||||
@@ -179,10 +178,20 @@ EXAMPLES = '''
|
||||
auth_password: PASSWORD
|
||||
realm: master
|
||||
name: this_is_a_test
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Create or update Keycloak client template (minimal), authentication with token
|
||||
community.general.keycloak_clienttemplate:
|
||||
auth_client_id: admin-cli
|
||||
auth_keycloak_url: https://auth.example.com/auth
|
||||
auth_realm: master
|
||||
token: TOKEN
|
||||
realm: master
|
||||
name: this_is_a_test
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Delete Keycloak client template
|
||||
local_action:
|
||||
module: keycloak_clienttemplate
|
||||
community.general.keycloak_client:
|
||||
auth_client_id: admin-cli
|
||||
auth_keycloak_url: https://auth.example.com/auth
|
||||
auth_realm: master
|
||||
@@ -191,10 +200,10 @@ EXAMPLES = '''
|
||||
realm: master
|
||||
state: absent
|
||||
name: test01
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Create or update Keycloak client template (with a protocol mapper)
|
||||
local_action:
|
||||
module: keycloak_clienttemplate
|
||||
community.general.keycloak_client:
|
||||
auth_client_id: admin-cli
|
||||
auth_keycloak_url: https://auth.example.com/auth
|
||||
auth_realm: master
|
||||
@@ -217,6 +226,7 @@ EXAMPLES = '''
|
||||
protocolMapper: oidc-usermodel-property-mapper
|
||||
full_scope_allowed: false
|
||||
id: bce6f5e9-d7d3-4955-817e-c5b7f8d65b3f
|
||||
delegate_to: localhost
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
@@ -296,21 +306,15 @@ def main():
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
required_one_of=([['id', 'name']]))
|
||||
required_one_of=([['id', 'name'],
|
||||
['token', 'auth_realm', 'auth_username', 'auth_password']]),
|
||||
required_together=([['auth_realm', 'auth_username', 'auth_password']]))
|
||||
|
||||
result = dict(changed=False, msg='', diff={}, proposed={}, existing={}, end_state={})
|
||||
|
||||
# Obtain access token, initialize API
|
||||
try:
|
||||
connection_header = get_token(
|
||||
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'),
|
||||
)
|
||||
connection_header = get_token(module.params)
|
||||
except KeycloakError as e:
|
||||
module.fail_json(msg=str(e))
|
||||
kc = KeycloakAPI(module, connection_header)
|
||||
|
||||
@@ -81,7 +81,7 @@ author:
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Create a Keycloak group
|
||||
- name: Create a Keycloak group, authentication with credentials
|
||||
community.general.keycloak_group:
|
||||
name: my-new-kc-group
|
||||
realm: MyCustomRealm
|
||||
@@ -93,6 +93,16 @@ EXAMPLES = '''
|
||||
auth_password: PASSWORD
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Create a Keycloak group, authentication with token
|
||||
community.general.keycloak_group:
|
||||
name: my-new-kc-group
|
||||
realm: MyCustomRealm
|
||||
state: present
|
||||
auth_client_id: admin-cli
|
||||
auth_keycloak_url: https://auth.example.com/auth
|
||||
token: TOKEN
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Delete a keycloak group
|
||||
community.general.keycloak_group:
|
||||
id: '9d59aa76-2755-48c6-b1af-beb70a82c3cd'
|
||||
@@ -217,30 +227,25 @@ def main():
|
||||
realm=dict(default='master'),
|
||||
id=dict(type='str'),
|
||||
name=dict(type='str'),
|
||||
attributes=dict(type='dict')
|
||||
attributes=dict(type='dict'),
|
||||
)
|
||||
|
||||
argument_spec.update(meta_args)
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
required_one_of=([['id', 'name']]))
|
||||
required_one_of=([['id', 'name'],
|
||||
['token', 'auth_realm', 'auth_username', 'auth_password']]),
|
||||
required_together=([['auth_realm', 'auth_username', 'auth_password']]))
|
||||
|
||||
result = dict(changed=False, msg='', diff={}, group='')
|
||||
|
||||
# Obtain access token, initialize API
|
||||
try:
|
||||
connection_header = get_token(
|
||||
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'),
|
||||
)
|
||||
connection_header = get_token(module.params)
|
||||
except KeycloakError as e:
|
||||
module.fail_json(msg=str(e))
|
||||
|
||||
kc = KeycloakAPI(module, connection_header)
|
||||
|
||||
realm = module.params.get('realm')
|
||||
|
||||
787
plugins/modules/identity/keycloak/keycloak_realm.py
Normal file
787
plugins/modules/identity/keycloak/keycloak_realm.py
Normal file
@@ -0,0 +1,787 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2017, Eike Frost <ei@kefro.st>
|
||||
# Copyright (c) 2021, Christophe Gilles <christophe.gilles54@gmail.com>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: keycloak_realm
|
||||
|
||||
short_description: Allows administration of Keycloak realm via Keycloak API
|
||||
version_added: 3.0.0
|
||||
|
||||
|
||||
description:
|
||||
- This module allows the administration of Keycloak realm via the Keycloak REST API. It
|
||||
requires access to the REST API via OpenID Connect; the user connecting and the realm being
|
||||
used must have the requisite access rights. In a default Keycloak installation, admin-cli
|
||||
and an admin user would work, as would a separate realm definition with the scope tailored
|
||||
to your needs and a user having the expected roles.
|
||||
|
||||
- The names of module options are snake_cased versions of the camelCase ones found in the
|
||||
Keycloak API and its documentation at U(https://www.keycloak.org/docs-api/8.0/rest-api/index.html).
|
||||
Aliases are provided so camelCased versions can be used as well.
|
||||
|
||||
- The Keycloak API does not always sanity check inputs e.g. you can set
|
||||
SAML-specific settings on an OpenID Connect client for instance and vice versa. Be careful.
|
||||
If you do not specify a setting, usually a sensible default is chosen.
|
||||
|
||||
options:
|
||||
state:
|
||||
description:
|
||||
- State of the realm.
|
||||
- On C(present), the realm will be created (or updated if it exists already).
|
||||
- On C(absent), the realm will be removed if it exists.
|
||||
choices: ['present', 'absent']
|
||||
default: 'present'
|
||||
type: str
|
||||
|
||||
id:
|
||||
description:
|
||||
- The realm to create.
|
||||
type: str
|
||||
realm:
|
||||
description:
|
||||
- The realm name.
|
||||
type: str
|
||||
access_code_lifespan:
|
||||
description:
|
||||
- The realm access code lifespan.
|
||||
aliases:
|
||||
- accessCodeLifespan
|
||||
type: int
|
||||
access_code_lifespan_login:
|
||||
description:
|
||||
- The realm access code lifespan login.
|
||||
aliases:
|
||||
- accessCodeLifespanLogin
|
||||
type: int
|
||||
access_code_lifespan_user_action:
|
||||
description:
|
||||
- The realm access code lifespan user action.
|
||||
aliases:
|
||||
- accessCodeLifespanUserAction
|
||||
type: int
|
||||
access_token_lifespan:
|
||||
description:
|
||||
- The realm access token lifespan.
|
||||
aliases:
|
||||
- accessTokenLifespan
|
||||
type: int
|
||||
access_token_lifespan_for_implicit_flow:
|
||||
description:
|
||||
- The realm access token lifespan for implicit flow.
|
||||
aliases:
|
||||
- accessTokenLifespanForImplicitFlow
|
||||
type: int
|
||||
account_theme:
|
||||
description:
|
||||
- The realm account theme.
|
||||
aliases:
|
||||
- accountTheme
|
||||
type: str
|
||||
action_token_generated_by_admin_lifespan:
|
||||
description:
|
||||
- The realm action token generated by admin lifespan.
|
||||
aliases:
|
||||
- actionTokenGeneratedByAdminLifespan
|
||||
type: int
|
||||
action_token_generated_by_user_lifespan:
|
||||
description:
|
||||
- The realm action token generated by user lifespan.
|
||||
aliases:
|
||||
- actionTokenGeneratedByUserLifespan
|
||||
type: int
|
||||
admin_events_details_enabled:
|
||||
description:
|
||||
- The realm admin events details enabled.
|
||||
aliases:
|
||||
- adminEventsDetailsEnabled
|
||||
type: bool
|
||||
admin_events_enabled:
|
||||
description:
|
||||
- The realm admin events enabled.
|
||||
aliases:
|
||||
- adminEventsEnabled
|
||||
type: bool
|
||||
admin_theme:
|
||||
description:
|
||||
- The realm admin theme.
|
||||
aliases:
|
||||
- adminTheme
|
||||
type: str
|
||||
attributes:
|
||||
description:
|
||||
- The realm attributes.
|
||||
type: dict
|
||||
browser_flow:
|
||||
description:
|
||||
- The realm browser flow.
|
||||
aliases:
|
||||
- browserFlow
|
||||
type: str
|
||||
browser_security_headers:
|
||||
description:
|
||||
- The realm browser security headers.
|
||||
aliases:
|
||||
- browserSecurityHeaders
|
||||
type: dict
|
||||
brute_force_protected:
|
||||
description:
|
||||
- The realm brute force protected.
|
||||
aliases:
|
||||
- bruteForceProtected
|
||||
type: bool
|
||||
client_authentication_flow:
|
||||
description:
|
||||
- The realm client authentication flow.
|
||||
aliases:
|
||||
- clientAuthenticationFlow
|
||||
type: str
|
||||
client_scope_mappings:
|
||||
description:
|
||||
- The realm client scope mappings.
|
||||
aliases:
|
||||
- clientScopeMappings
|
||||
type: dict
|
||||
default_default_client_scopes:
|
||||
description:
|
||||
- The realm default default client scopes.
|
||||
aliases:
|
||||
- defaultDefaultClientScopes
|
||||
type: list
|
||||
elements: dict
|
||||
default_groups:
|
||||
description:
|
||||
- The realm default groups.
|
||||
aliases:
|
||||
- defaultGroups
|
||||
type: list
|
||||
elements: dict
|
||||
default_locale:
|
||||
description:
|
||||
- The realm default locale.
|
||||
aliases:
|
||||
- defaultLocale
|
||||
type: str
|
||||
default_optional_client_scopes:
|
||||
description:
|
||||
- The realm default optional client scopes.
|
||||
aliases:
|
||||
- defaultOptionalClientScopes
|
||||
type: list
|
||||
elements: dict
|
||||
default_roles:
|
||||
description:
|
||||
- The realm default roles.
|
||||
aliases:
|
||||
- defaultRoles
|
||||
type: list
|
||||
elements: dict
|
||||
default_signature_algorithm:
|
||||
description:
|
||||
- The realm default signature algorithm.
|
||||
aliases:
|
||||
- defaultSignatureAlgorithm
|
||||
type: str
|
||||
direct_grant_flow:
|
||||
description:
|
||||
- The realm direct grant flow.
|
||||
aliases:
|
||||
- directGrantFlow
|
||||
type: str
|
||||
display_name:
|
||||
description:
|
||||
- The realm display name.
|
||||
aliases:
|
||||
- displayName
|
||||
type: str
|
||||
display_name_html:
|
||||
description:
|
||||
- The realm display name HTML.
|
||||
aliases:
|
||||
- displayNameHtml
|
||||
type: str
|
||||
docker_authentication_flow:
|
||||
description:
|
||||
- The realm docker authentication flow.
|
||||
aliases:
|
||||
- dockerAuthenticationFlow
|
||||
type: str
|
||||
duplicate_emails_allowed:
|
||||
description:
|
||||
- The realm duplicate emails allowed option.
|
||||
aliases:
|
||||
- duplicateEmailsAllowed
|
||||
type: bool
|
||||
edit_username_allowed:
|
||||
description:
|
||||
- The realm edit username allowed option.
|
||||
aliases:
|
||||
- editUsernameAllowed
|
||||
type: bool
|
||||
email_theme:
|
||||
description:
|
||||
- The realm email theme.
|
||||
aliases:
|
||||
- emailTheme
|
||||
type: str
|
||||
enabled:
|
||||
description:
|
||||
- The realm enabled option.
|
||||
type: bool
|
||||
enabled_event_types:
|
||||
description:
|
||||
- The realm enabled event types.
|
||||
aliases:
|
||||
- enabledEventTypes
|
||||
type: list
|
||||
elements: str
|
||||
events_expiration:
|
||||
description:
|
||||
- The realm events expiration.
|
||||
aliases:
|
||||
- eventsExpiration
|
||||
type: int
|
||||
events_listeners:
|
||||
description:
|
||||
- The realm events listeners.
|
||||
aliases:
|
||||
- eventsListeners
|
||||
type: list
|
||||
elements: dict
|
||||
failure_factor:
|
||||
description:
|
||||
- The realm failure factor.
|
||||
aliases:
|
||||
- failureFactor
|
||||
type: int
|
||||
internationalization_enabled:
|
||||
description:
|
||||
- The realm internationalization enabled option.
|
||||
aliases:
|
||||
- internationalizationEnabled
|
||||
type: bool
|
||||
login_theme:
|
||||
description:
|
||||
- The realm login theme.
|
||||
aliases:
|
||||
- loginTheme
|
||||
type: str
|
||||
login_with_email_allowed:
|
||||
description:
|
||||
- The realm login with email allowed option.
|
||||
aliases:
|
||||
- loginWithEmailAllowed
|
||||
type: bool
|
||||
max_delta_time_seconds:
|
||||
description:
|
||||
- The realm max delta time in seconds.
|
||||
aliases:
|
||||
- maxDeltaTimeSeconds
|
||||
type: int
|
||||
max_failure_wait_seconds:
|
||||
description:
|
||||
- The realm max failure wait in seconds.
|
||||
aliases:
|
||||
- maxFailureWaitSeconds
|
||||
type: int
|
||||
minimum_quick_login_wait_seconds:
|
||||
description:
|
||||
- The realm minimum quick login wait in seconds.
|
||||
aliases:
|
||||
- minimumQuickLoginWaitSeconds
|
||||
type: int
|
||||
not_before:
|
||||
description:
|
||||
- The realm not before.
|
||||
aliases:
|
||||
- notBefore
|
||||
type: int
|
||||
offline_session_idle_timeout:
|
||||
description:
|
||||
- The realm offline session idle timeout.
|
||||
aliases:
|
||||
- offlineSessionIdleTimeout
|
||||
type: int
|
||||
offline_session_max_lifespan:
|
||||
description:
|
||||
- The realm offline session max lifespan.
|
||||
aliases:
|
||||
- offlineSessionMaxLifespan
|
||||
type: int
|
||||
offline_session_max_lifespan_enabled:
|
||||
description:
|
||||
- The realm offline session max lifespan enabled option.
|
||||
aliases:
|
||||
- offlineSessionMaxLifespanEnabled
|
||||
type: bool
|
||||
otp_policy_algorithm:
|
||||
description:
|
||||
- The realm otp policy algorithm.
|
||||
aliases:
|
||||
- otpPolicyAlgorithm
|
||||
type: str
|
||||
otp_policy_digits:
|
||||
description:
|
||||
- The realm otp policy digits.
|
||||
aliases:
|
||||
- otpPolicyDigits
|
||||
type: int
|
||||
otp_policy_initial_counter:
|
||||
description:
|
||||
- The realm otp policy initial counter.
|
||||
aliases:
|
||||
- otpPolicyInitialCounter
|
||||
type: int
|
||||
otp_policy_look_ahead_window:
|
||||
description:
|
||||
- The realm otp policy look ahead window.
|
||||
aliases:
|
||||
- otpPolicyLookAheadWindow
|
||||
type: int
|
||||
otp_policy_period:
|
||||
description:
|
||||
- The realm otp policy period.
|
||||
aliases:
|
||||
- otpPolicyPeriod
|
||||
type: int
|
||||
otp_policy_type:
|
||||
description:
|
||||
- The realm otp policy type.
|
||||
aliases:
|
||||
- otpPolicyType
|
||||
type: str
|
||||
otp_supported_applications:
|
||||
description:
|
||||
- The realm otp supported applications.
|
||||
aliases:
|
||||
- otpSupportedApplications
|
||||
type: list
|
||||
elements: str
|
||||
password_policy:
|
||||
description:
|
||||
- The realm password policy.
|
||||
aliases:
|
||||
- passwordPolicy
|
||||
type: str
|
||||
permanent_lockout:
|
||||
description:
|
||||
- The realm permanent lockout.
|
||||
aliases:
|
||||
- permanentLockout
|
||||
type: bool
|
||||
quick_login_check_milli_seconds:
|
||||
description:
|
||||
- The realm quick login check in milliseconds.
|
||||
aliases:
|
||||
- quickLoginCheckMilliSeconds
|
||||
type: int
|
||||
refresh_token_max_reuse:
|
||||
description:
|
||||
- The realm refresh token max reuse.
|
||||
aliases:
|
||||
- refreshTokenMaxReuse
|
||||
type: int
|
||||
registration_allowed:
|
||||
description:
|
||||
- The realm registration allowed option.
|
||||
aliases:
|
||||
- registrationAllowed
|
||||
type: bool
|
||||
registration_email_as_username:
|
||||
description:
|
||||
- The realm registration email as username option.
|
||||
aliases:
|
||||
- registrationEmailAsUsername
|
||||
type: bool
|
||||
registration_flow:
|
||||
description:
|
||||
- The realm registration flow.
|
||||
aliases:
|
||||
- registrationFlow
|
||||
type: str
|
||||
remember_me:
|
||||
description:
|
||||
- The realm remember me option.
|
||||
aliases:
|
||||
- rememberMe
|
||||
type: bool
|
||||
reset_credentials_flow:
|
||||
description:
|
||||
- The realm reset credentials flow.
|
||||
aliases:
|
||||
- resetCredentialsFlow
|
||||
type: str
|
||||
reset_password_allowed:
|
||||
description:
|
||||
- The realm reset password allowed option.
|
||||
aliases:
|
||||
- resetPasswordAllowed
|
||||
type: bool
|
||||
revoke_refresh_token:
|
||||
description:
|
||||
- The realm revoke refresh token option.
|
||||
aliases:
|
||||
- revokeRefreshToken
|
||||
type: bool
|
||||
smtp_server:
|
||||
description:
|
||||
- The realm smtp server.
|
||||
aliases:
|
||||
- smtpServer
|
||||
type: dict
|
||||
ssl_required:
|
||||
description:
|
||||
- The realm ssl required option.
|
||||
aliases:
|
||||
- sslRequired
|
||||
type: bool
|
||||
sso_session_idle_timeout:
|
||||
description:
|
||||
- The realm sso session idle timeout.
|
||||
aliases:
|
||||
- ssoSessionIdleTimeout
|
||||
type: int
|
||||
sso_session_idle_timeout_remember_me:
|
||||
description:
|
||||
- The realm sso session idle timeout remember me.
|
||||
aliases:
|
||||
- ssoSessionIdleTimeoutRememberMe
|
||||
type: int
|
||||
sso_session_max_lifespan:
|
||||
description:
|
||||
- The realm sso session max lifespan.
|
||||
aliases:
|
||||
- ssoSessionMaxLifespan
|
||||
type: int
|
||||
sso_session_max_lifespan_remember_me:
|
||||
description:
|
||||
- The realm sso session max lifespan remember me.
|
||||
aliases:
|
||||
- ssoSessionMaxLifespanRememberMe
|
||||
type: int
|
||||
supported_locales:
|
||||
description:
|
||||
- The realm supported locales.
|
||||
aliases:
|
||||
- supportedLocales
|
||||
type: list
|
||||
elements: str
|
||||
user_managed_access_allowed:
|
||||
description:
|
||||
- The realm user managed access allowed option.
|
||||
aliases:
|
||||
- userManagedAccessAllowed
|
||||
type: bool
|
||||
verify_email:
|
||||
description:
|
||||
- The realm verify email option.
|
||||
aliases:
|
||||
- verifyEmail
|
||||
type: bool
|
||||
wait_increment_seconds:
|
||||
description:
|
||||
- The realm wait increment in seconds.
|
||||
aliases:
|
||||
- waitIncrementSeconds
|
||||
type: int
|
||||
|
||||
extends_documentation_fragment:
|
||||
- community.general.keycloak
|
||||
|
||||
|
||||
author:
|
||||
- Christophe Gilles (@kris2kris)
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Create or update Keycloak realm (minimal example)
|
||||
community.general.keycloak_realm:
|
||||
auth_client_id: admin-cli
|
||||
auth_keycloak_url: https://auth.example.com/auth
|
||||
auth_realm: master
|
||||
auth_username: USERNAME
|
||||
auth_password: PASSWORD
|
||||
id: realm
|
||||
state: present
|
||||
|
||||
- name: Delete a Keycloak realm
|
||||
community.general.keycloak_realm:
|
||||
auth_client_id: admin-cli
|
||||
auth_keycloak_url: https://auth.example.com/auth
|
||||
auth_realm: master
|
||||
auth_username: USERNAME
|
||||
auth_password: PASSWORD
|
||||
id: test
|
||||
state: absent
|
||||
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
msg:
|
||||
description: Message as to what action was taken
|
||||
returned: always
|
||||
type: str
|
||||
sample: "Realm testrealm has been updated"
|
||||
|
||||
proposed:
|
||||
description: realm representation of proposed changes to realm
|
||||
returned: always
|
||||
type: dict
|
||||
sample: {
|
||||
id: "test"
|
||||
}
|
||||
existing:
|
||||
description: realm representation of existing realm (sample is truncated)
|
||||
returned: always
|
||||
type: dict
|
||||
sample: {
|
||||
"adminUrl": "http://www.example.com/admin_url",
|
||||
"attributes": {
|
||||
"request.object.signature.alg": "RS256",
|
||||
}
|
||||
}
|
||||
end_state:
|
||||
description: realm representation of realm after module execution (sample is truncated)
|
||||
returned: always
|
||||
type: dict
|
||||
sample: {
|
||||
"adminUrl": "http://www.example.com/admin_url",
|
||||
"attributes": {
|
||||
"request.object.signature.alg": "RS256",
|
||||
}
|
||||
}
|
||||
'''
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.identity.keycloak.keycloak import KeycloakAPI, camel, \
|
||||
keycloak_argument_spec, get_token, KeycloakError
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
|
||||
def sanitize_cr(realmrep):
|
||||
""" Removes probably sensitive details from a realm representation
|
||||
|
||||
:param realmrep: the realmrep dict to be sanitized
|
||||
:return: sanitized realmrep dict
|
||||
"""
|
||||
result = realmrep.copy()
|
||||
if 'secret' in result:
|
||||
result['secret'] = '********'
|
||||
if 'attributes' in result:
|
||||
if 'saml.signing.private.key' in result['attributes']:
|
||||
result['attributes'] = result['attributes'].copy()
|
||||
result['attributes']['saml.signing.private.key'] = '********'
|
||||
return result
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
Module execution
|
||||
|
||||
:return:
|
||||
"""
|
||||
argument_spec = keycloak_argument_spec()
|
||||
|
||||
meta_args = dict(
|
||||
state=dict(default='present', choices=['present', 'absent']),
|
||||
|
||||
id=dict(type='str'),
|
||||
realm=dict(type='str'),
|
||||
access_code_lifespan=dict(type='int', aliases=['accessCodeLifespan']),
|
||||
access_code_lifespan_login=dict(type='int', aliases=['accessCodeLifespanLogin']),
|
||||
access_code_lifespan_user_action=dict(type='int', aliases=['accessCodeLifespanUserAction']),
|
||||
access_token_lifespan=dict(type='int', aliases=['accessTokenLifespan'], no_log=False),
|
||||
access_token_lifespan_for_implicit_flow=dict(type='int', aliases=['accessTokenLifespanForImplicitFlow'], no_log=False),
|
||||
account_theme=dict(type='str', aliases=['accountTheme']),
|
||||
action_token_generated_by_admin_lifespan=dict(type='int', aliases=['actionTokenGeneratedByAdminLifespan'], no_log=False),
|
||||
action_token_generated_by_user_lifespan=dict(type='int', aliases=['actionTokenGeneratedByUserLifespan'], no_log=False),
|
||||
admin_events_details_enabled=dict(type='bool', aliases=['adminEventsDetailsEnabled']),
|
||||
admin_events_enabled=dict(type='bool', aliases=['adminEventsEnabled']),
|
||||
admin_theme=dict(type='str', aliases=['adminTheme']),
|
||||
attributes=dict(type='dict'),
|
||||
browser_flow=dict(type='str', aliases=['browserFlow']),
|
||||
browser_security_headers=dict(type='dict', aliases=['browserSecurityHeaders']),
|
||||
brute_force_protected=dict(type='bool', aliases=['bruteForceProtected']),
|
||||
client_authentication_flow=dict(type='str', aliases=['clientAuthenticationFlow']),
|
||||
client_scope_mappings=dict(type='dict', aliases=['clientScopeMappings']),
|
||||
default_default_client_scopes=dict(type='list', elements='dict', aliases=['defaultDefaultClientScopes']),
|
||||
default_groups=dict(type='list', elements='dict', aliases=['defaultGroups']),
|
||||
default_locale=dict(type='str', aliases=['defaultLocale']),
|
||||
default_optional_client_scopes=dict(type='list', elements='dict', aliases=['defaultOptionalClientScopes']),
|
||||
default_roles=dict(type='list', elements='dict', aliases=['defaultRoles']),
|
||||
default_signature_algorithm=dict(type='str', aliases=['defaultSignatureAlgorithm']),
|
||||
direct_grant_flow=dict(type='str', aliases=['directGrantFlow']),
|
||||
display_name=dict(type='str', aliases=['displayName']),
|
||||
display_name_html=dict(type='str', aliases=['displayNameHtml']),
|
||||
docker_authentication_flow=dict(type='str', aliases=['dockerAuthenticationFlow']),
|
||||
duplicate_emails_allowed=dict(type='bool', aliases=['duplicateEmailsAllowed']),
|
||||
edit_username_allowed=dict(type='bool', aliases=['editUsernameAllowed']),
|
||||
email_theme=dict(type='str', aliases=['emailTheme']),
|
||||
enabled=dict(type='bool'),
|
||||
enabled_event_types=dict(type='list', elements='str', aliases=['enabledEventTypes']),
|
||||
events_expiration=dict(type='int', aliases=['eventsExpiration']),
|
||||
events_listeners=dict(type='list', elements='dict', aliases=['eventsListeners']),
|
||||
failure_factor=dict(type='int', aliases=['failureFactor']),
|
||||
internationalization_enabled=dict(type='bool', aliases=['internationalizationEnabled']),
|
||||
login_theme=dict(type='str', aliases=['loginTheme']),
|
||||
login_with_email_allowed=dict(type='bool', aliases=['loginWithEmailAllowed']),
|
||||
max_delta_time_seconds=dict(type='int', aliases=['maxDeltaTimeSeconds']),
|
||||
max_failure_wait_seconds=dict(type='int', aliases=['maxFailureWaitSeconds']),
|
||||
minimum_quick_login_wait_seconds=dict(type='int', aliases=['minimumQuickLoginWaitSeconds']),
|
||||
not_before=dict(type='int', aliases=['notBefore']),
|
||||
offline_session_idle_timeout=dict(type='int', aliases=['offlineSessionIdleTimeout']),
|
||||
offline_session_max_lifespan=dict(type='int', aliases=['offlineSessionMaxLifespan']),
|
||||
offline_session_max_lifespan_enabled=dict(type='bool', aliases=['offlineSessionMaxLifespanEnabled']),
|
||||
otp_policy_algorithm=dict(type='str', aliases=['otpPolicyAlgorithm']),
|
||||
otp_policy_digits=dict(type='int', aliases=['otpPolicyDigits']),
|
||||
otp_policy_initial_counter=dict(type='int', aliases=['otpPolicyInitialCounter']),
|
||||
otp_policy_look_ahead_window=dict(type='int', aliases=['otpPolicyLookAheadWindow']),
|
||||
otp_policy_period=dict(type='int', aliases=['otpPolicyPeriod']),
|
||||
otp_policy_type=dict(type='str', aliases=['otpPolicyType']),
|
||||
otp_supported_applications=dict(type='list', elements='str', aliases=['otpSupportedApplications']),
|
||||
password_policy=dict(type='str', aliases=['passwordPolicy'], no_log=False),
|
||||
permanent_lockout=dict(type='bool', aliases=['permanentLockout']),
|
||||
quick_login_check_milli_seconds=dict(type='int', aliases=['quickLoginCheckMilliSeconds']),
|
||||
refresh_token_max_reuse=dict(type='int', aliases=['refreshTokenMaxReuse'], no_log=False),
|
||||
registration_allowed=dict(type='bool', aliases=['registrationAllowed']),
|
||||
registration_email_as_username=dict(type='bool', aliases=['registrationEmailAsUsername']),
|
||||
registration_flow=dict(type='str', aliases=['registrationFlow']),
|
||||
remember_me=dict(type='bool', aliases=['rememberMe']),
|
||||
reset_credentials_flow=dict(type='str', aliases=['resetCredentialsFlow']),
|
||||
reset_password_allowed=dict(type='bool', aliases=['resetPasswordAllowed']),
|
||||
revoke_refresh_token=dict(type='bool', aliases=['revokeRefreshToken']),
|
||||
smtp_server=dict(type='dict', aliases=['smtpServer']),
|
||||
ssl_required=dict(type='bool', aliases=['sslRequired']),
|
||||
sso_session_idle_timeout=dict(type='int', aliases=['ssoSessionIdleTimeout']),
|
||||
sso_session_idle_timeout_remember_me=dict(type='int', aliases=['ssoSessionIdleTimeoutRememberMe']),
|
||||
sso_session_max_lifespan=dict(type='int', aliases=['ssoSessionMaxLifespan']),
|
||||
sso_session_max_lifespan_remember_me=dict(type='int', aliases=['ssoSessionMaxLifespanRememberMe']),
|
||||
supported_locales=dict(type='list', elements='str', aliases=['supportedLocales']),
|
||||
user_managed_access_allowed=dict(type='bool', aliases=['userManagedAccessAllowed']),
|
||||
verify_email=dict(type='bool', aliases=['verifyEmail']),
|
||||
wait_increment_seconds=dict(type='int', aliases=['waitIncrementSeconds']),
|
||||
)
|
||||
argument_spec.update(meta_args)
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
required_one_of=([['id', 'realm', 'enabled'],
|
||||
['token', 'auth_realm', 'auth_username', 'auth_password']]),
|
||||
required_together=([['auth_realm', 'auth_username', 'auth_password']]))
|
||||
|
||||
result = dict(changed=False, msg='', diff={}, proposed={}, existing={}, end_state={})
|
||||
|
||||
# Obtain access token, initialize API
|
||||
try:
|
||||
connection_header = get_token(module.params)
|
||||
except KeycloakError as e:
|
||||
module.fail_json(msg=str(e))
|
||||
|
||||
kc = KeycloakAPI(module, connection_header)
|
||||
|
||||
realm = module.params.get('realm')
|
||||
state = module.params.get('state')
|
||||
|
||||
# convert module parameters to realm representation parameters (if they belong in there)
|
||||
params_to_ignore = list(keycloak_argument_spec().keys()) + ['state']
|
||||
realm_params = [x for x in module.params
|
||||
if x not in params_to_ignore and
|
||||
module.params.get(x) is not None]
|
||||
|
||||
# See whether the realm already exists in Keycloak
|
||||
before_realm = kc.get_realm_by_id(realm=realm) or {}
|
||||
|
||||
# Build a proposed changeset from parameters given to this module
|
||||
changeset = dict()
|
||||
|
||||
for realm_param in realm_params:
|
||||
new_param_value = module.params.get(realm_param)
|
||||
changeset[camel(realm_param)] = new_param_value
|
||||
|
||||
# Whether creating or updating a realm, take the before-state and merge the changeset into it
|
||||
updated_realm = before_realm.copy()
|
||||
updated_realm.update(changeset)
|
||||
|
||||
result['proposed'] = sanitize_cr(changeset)
|
||||
before_realm_sanitized = sanitize_cr(before_realm)
|
||||
result['existing'] = before_realm_sanitized
|
||||
|
||||
# If the realm does not exist yet, before_realm is still empty
|
||||
if not before_realm:
|
||||
if state == 'absent':
|
||||
# do nothing and exit
|
||||
if module._diff:
|
||||
result['diff'] = dict(before='', after='')
|
||||
result['msg'] = 'Realm does not exist, doing nothing.'
|
||||
module.exit_json(**result)
|
||||
|
||||
# create new realm
|
||||
result['changed'] = True
|
||||
if 'id' not in updated_realm:
|
||||
module.fail_json(msg='id needs to be specified when creating a new realm')
|
||||
|
||||
if module._diff:
|
||||
result['diff'] = dict(before='', after=sanitize_cr(updated_realm))
|
||||
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
|
||||
kc.create_realm(updated_realm)
|
||||
after_realm = kc.get_realm_by_id(updated_realm['id'])
|
||||
|
||||
result['end_state'] = sanitize_cr(after_realm)
|
||||
|
||||
result['msg'] = 'Realm %s has been created.' % updated_realm['id']
|
||||
module.exit_json(**result)
|
||||
else:
|
||||
if state == 'present':
|
||||
# update existing realm
|
||||
result['changed'] = True
|
||||
if module.check_mode:
|
||||
# We can only compare the current realm with the proposed updates we have
|
||||
if module._diff:
|
||||
result['diff'] = dict(before=before_realm_sanitized,
|
||||
after=sanitize_cr(updated_realm))
|
||||
result['changed'] = (before_realm != updated_realm)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
kc.update_realm(updated_realm, realm=realm)
|
||||
|
||||
after_realm = kc.get_realm_by_id(realm=realm)
|
||||
if before_realm == after_realm:
|
||||
result['changed'] = False
|
||||
if module._diff:
|
||||
result['diff'] = dict(before=before_realm_sanitized,
|
||||
after=sanitize_cr(after_realm))
|
||||
result['end_state'] = sanitize_cr(after_realm)
|
||||
|
||||
result['msg'] = 'Realm %s has been updated.' % updated_realm['id']
|
||||
module.exit_json(**result)
|
||||
else:
|
||||
# Delete existing realm
|
||||
result['changed'] = True
|
||||
if module._diff:
|
||||
result['diff']['before'] = before_realm_sanitized
|
||||
result['diff']['after'] = ''
|
||||
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
|
||||
kc.delete_realm(realm=realm)
|
||||
result['proposed'] = dict()
|
||||
result['end_state'] = dict()
|
||||
result['msg'] = 'Realm %s has been deleted.' % before_realm['id']
|
||||
module.exit_json(**result)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1 +0,0 @@
|
||||
onepassword_info.py
|
||||
@@ -20,9 +20,6 @@ requirements:
|
||||
notes:
|
||||
- Tested with C(op) version 0.5.5
|
||||
- "Based on the C(onepassword) lookup plugin by Scott Buchanan <sbuchanan@ri.pn>."
|
||||
- When this module is called with the deprecated C(onepassword_facts) name, potentially sensitive data
|
||||
from 1Password is returned as Ansible facts. Facts are subject to caching if enabled, which means this
|
||||
data could be stored in clear text on disk or in a database.
|
||||
short_description: Gather items from 1Password
|
||||
description:
|
||||
- M(community.general.onepassword_info) wraps the C(op) command line utility to fetch data about one or more 1Password items.
|
||||
@@ -380,13 +377,7 @@ def main():
|
||||
|
||||
results = {'onepassword': OnePasswordInfo().run()}
|
||||
|
||||
if module._name in ('onepassword_facts', 'community.general.onepassword_facts'):
|
||||
module.deprecate("The 'onepassword_facts' module has been renamed to 'onepassword_info'. "
|
||||
"When called with the new name it no longer returns 'ansible_facts'",
|
||||
version='3.0.0', collection_name='community.general') # was Ansible 2.13
|
||||
module.exit_json(changed=False, ansible_facts=results)
|
||||
else:
|
||||
module.exit_json(changed=False, **results)
|
||||
module.exit_json(changed=False, **results)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
./remote_management/dellemc/idrac_firmware.py
|
||||
@@ -1 +0,0 @@
|
||||
remote_management/redfish/idrac_redfish_facts.py
|
||||
@@ -1 +0,0 @@
|
||||
./remote_management/dellemc/idrac_server_config_profile.py
|
||||
@@ -1 +0,0 @@
|
||||
web_infrastructure/jenkins_job_facts.py
|
||||
1
plugins/modules/keycloak_realm.py
Symbolic link
1
plugins/modules/keycloak_realm.py
Symbolic link
@@ -0,0 +1 @@
|
||||
./identity/keycloak/keycloak_realm.py
|
||||
@@ -1 +0,0 @@
|
||||
./net_tools/ldap/ldap_attr.py
|
||||
@@ -1 +0,0 @@
|
||||
cloud/memset/memset_memstore_facts.py
|
||||
@@ -1 +0,0 @@
|
||||
cloud/memset/memset_server_facts.py
|
||||
@@ -17,18 +17,17 @@ author:
|
||||
short_description: Notify airbrake about app deployments
|
||||
description:
|
||||
- Notify airbrake about app deployments (see U(https://airbrake.io/docs/api/#deploys-v4)).
|
||||
- Parameter I(token) has been deprecated for community.general 0.2.0. Please remove entry.
|
||||
options:
|
||||
project_id:
|
||||
description:
|
||||
- Airbrake PROJECT_ID
|
||||
required: false
|
||||
required: true
|
||||
type: str
|
||||
version_added: '0.2.0'
|
||||
project_key:
|
||||
description:
|
||||
- Airbrake PROJECT_KEY.
|
||||
required: false
|
||||
required: true
|
||||
type: str
|
||||
version_added: '0.2.0'
|
||||
environment:
|
||||
@@ -70,11 +69,6 @@ options:
|
||||
required: false
|
||||
default: 'yes'
|
||||
type: bool
|
||||
token:
|
||||
description:
|
||||
- This parameter (API token) has been deprecated in community.general 0.2.0. Please remove it from your tasks.
|
||||
required: false
|
||||
type: str
|
||||
|
||||
requirements: []
|
||||
'''
|
||||
@@ -111,9 +105,8 @@ def main():
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
token=dict(required=False, no_log=True, type='str'),
|
||||
project_id=dict(required=False, no_log=True, type='str'),
|
||||
project_key=dict(required=False, no_log=True, type='str'),
|
||||
project_id=dict(required=True, no_log=True, type='str'),
|
||||
project_key=dict(required=True, no_log=True, type='str'),
|
||||
environment=dict(required=True, type='str'),
|
||||
user=dict(required=False, type='str'),
|
||||
repo=dict(required=False, type='str'),
|
||||
@@ -123,8 +116,6 @@ def main():
|
||||
validate_certs=dict(default=True, type='bool'),
|
||||
),
|
||||
supports_check_mode=True,
|
||||
required_together=[('project_id', 'project_key')],
|
||||
mutually_exclusive=[('project_id', 'token')],
|
||||
)
|
||||
|
||||
# Build list of params
|
||||
@@ -134,65 +125,32 @@ def main():
|
||||
if module.check_mode:
|
||||
module.exit_json(changed=True)
|
||||
|
||||
if module.params["token"]:
|
||||
# v2 API documented at https://airbrake.io/docs/legacy-xml-api/#tracking-deploys
|
||||
if module.params["environment"]:
|
||||
params["deploy[rails_env]"] = module.params["environment"]
|
||||
# v4 API documented at https://airbrake.io/docs/api/#create-deploy-v4
|
||||
if module.params["environment"]:
|
||||
params["environment"] = module.params["environment"]
|
||||
|
||||
if module.params["user"]:
|
||||
params["deploy[local_username]"] = module.params["user"]
|
||||
if module.params["user"]:
|
||||
params["username"] = module.params["user"]
|
||||
|
||||
if module.params["repo"]:
|
||||
params["deploy[scm_repository]"] = module.params["repo"]
|
||||
if module.params["repo"]:
|
||||
params["repository"] = module.params["repo"]
|
||||
|
||||
if module.params["revision"]:
|
||||
params["deploy[scm_revision]"] = module.params["revision"]
|
||||
if module.params["revision"]:
|
||||
params["revision"] = module.params["revision"]
|
||||
|
||||
# version not supported in v2 API; omit
|
||||
if module.params["version"]:
|
||||
params["version"] = module.params["version"]
|
||||
|
||||
module.deprecate("Parameter 'token' is deprecated since community.general 0.2.0. Please remove "
|
||||
"it and use 'project_id' and 'project_key' instead",
|
||||
version='3.0.0', collection_name='community.general') # was Ansible 2.14
|
||||
# Build deploy url
|
||||
url = module.params.get('url') + module.params["project_id"] + '/deploys?key=' + module.params["project_key"]
|
||||
json_body = module.jsonify(params)
|
||||
|
||||
params["api_key"] = module.params["token"]
|
||||
# Build header
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
|
||||
# Allow sending to Airbrake compliant v2 APIs
|
||||
if module.params["url"] == 'https://api.airbrake.io/api/v4/projects/':
|
||||
url = 'https://api.airbrake.io/deploys.txt'
|
||||
else:
|
||||
url = module.params["url"]
|
||||
|
||||
# Send the data to airbrake
|
||||
data = urlencode(params)
|
||||
response, info = fetch_url(module, url, data=data)
|
||||
|
||||
if module.params["project_id"] and module.params["project_key"]:
|
||||
# v4 API documented at https://airbrake.io/docs/api/#create-deploy-v4
|
||||
if module.params["environment"]:
|
||||
params["environment"] = module.params["environment"]
|
||||
|
||||
if module.params["user"]:
|
||||
params["username"] = module.params["user"]
|
||||
|
||||
if module.params["repo"]:
|
||||
params["repository"] = module.params["repo"]
|
||||
|
||||
if module.params["revision"]:
|
||||
params["revision"] = module.params["revision"]
|
||||
|
||||
if module.params["version"]:
|
||||
params["version"] = module.params["version"]
|
||||
|
||||
# Build deploy url
|
||||
url = module.params.get('url') + module.params["project_id"] + '/deploys?key=' + module.params["project_key"]
|
||||
json_body = module.jsonify(params)
|
||||
|
||||
# Build header
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
|
||||
# Notify Airbrake of deploy
|
||||
response, info = fetch_url(module, url, data=json_body,
|
||||
headers=headers, method='POST')
|
||||
# Notify Airbrake of deploy
|
||||
response, info = fetch_url(module, url, data=json_body,
|
||||
headers=headers, method='POST')
|
||||
|
||||
if info['status'] == 200 or info['status'] == 201:
|
||||
module.exit_json(changed=True)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user