mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-05-01 02:43:16 +00:00
Compare commits
75 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d483fd9482 | ||
|
|
8da9cf3276 | ||
|
|
3c5c3a0113 | ||
|
|
7def57a71f | ||
|
|
e5930aabcb | ||
|
|
48bfba435f | ||
|
|
9740b76f3c | ||
|
|
24cf561135 | ||
|
|
61324ed9eb | ||
|
|
99336ba5fe | ||
|
|
9d99ccef2d | ||
|
|
a146eb3118 | ||
|
|
c7f7bd6050 | ||
|
|
54099d77ff | ||
|
|
ee07d8320a | ||
|
|
0729f0c262 | ||
|
|
57cd48f3cf | ||
|
|
afd2151672 | ||
|
|
ea9b272043 | ||
|
|
60addb332d | ||
|
|
1ade62c5bc | ||
|
|
7c8cc96d8b | ||
|
|
ca177a0ceb | ||
|
|
c0e769e5f5 | ||
|
|
585dbc3171 | ||
|
|
b400491ef3 | ||
|
|
490baed566 | ||
|
|
811c4a304a | ||
|
|
c0fde76b79 | ||
|
|
16c7615b82 | ||
|
|
474364c862 | ||
|
|
1da5f7dc54 | ||
|
|
559c914e36 | ||
|
|
91cca4ae49 | ||
|
|
82a9db9738 | ||
|
|
3fd84d71b8 | ||
|
|
a17124f3c4 | ||
|
|
efc2cbf840 | ||
|
|
aa136aca4c | ||
|
|
a1ca89b058 | ||
|
|
dd70419d18 | ||
|
|
ef5ac023cf | ||
|
|
8bc5494ad5 | ||
|
|
d95a821d5b | ||
|
|
b7697fe3de | ||
|
|
16e05ab5f3 | ||
|
|
5cf7ce705a | ||
|
|
c8b8668212 | ||
|
|
2d450a5a36 | ||
|
|
e08412c345 | ||
|
|
c355f93d62 | ||
|
|
80206b5a53 | ||
|
|
e978fd4d61 | ||
|
|
6fc8492ecf | ||
|
|
95beb452a8 | ||
|
|
c10e9e2650 | ||
|
|
ac35bf4acb | ||
|
|
50b9855ace | ||
|
|
2ab26db197 | ||
|
|
5fcf5d0c8b | ||
|
|
0f0ad6b6d1 | ||
|
|
95f3109ddc | ||
|
|
6037c5d1e6 | ||
|
|
a70d9773dd | ||
|
|
bc50b48205 | ||
|
|
02e6a8608f | ||
|
|
82f4b51873 | ||
|
|
589e8fd5e1 | ||
|
|
58f74b96ef | ||
|
|
1489c080a7 | ||
|
|
6f845f61f0 | ||
|
|
c17f5ff3e8 | ||
|
|
ff21afb227 | ||
|
|
c1d6e5c3c2 | ||
|
|
377b5d4ccd |
@@ -189,6 +189,24 @@ stages:
|
||||
- test: 3.5
|
||||
|
||||
## Remote
|
||||
- stage: Remote_devel_extra_vms
|
||||
displayName: Remote devel extra VMs
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
testFormat: devel/{0}
|
||||
targets:
|
||||
- name: Alpine 3.17
|
||||
test: alpine/3.17
|
||||
# - name: Fedora 37
|
||||
# test: fedora/37
|
||||
# - name: Ubuntu 20.04
|
||||
# test: ubuntu/20.04
|
||||
- name: Ubuntu 22.04
|
||||
test: ubuntu/22.04
|
||||
groups:
|
||||
- vm
|
||||
- stage: Remote_devel
|
||||
displayName: Remote devel
|
||||
dependsOn: []
|
||||
@@ -201,12 +219,12 @@ stages:
|
||||
test: macos/12.0
|
||||
- name: RHEL 7.9
|
||||
test: rhel/7.9
|
||||
- name: RHEL 9.0
|
||||
test: rhel/9.0
|
||||
- name: FreeBSD 12.3
|
||||
test: freebsd/12.3
|
||||
- name: RHEL 9.1
|
||||
test: rhel/9.1
|
||||
- name: FreeBSD 13.1
|
||||
test: freebsd/13.1
|
||||
- name: FreeBSD 12.4
|
||||
test: freebsd/12.4
|
||||
groups:
|
||||
- 1
|
||||
- 2
|
||||
@@ -221,8 +239,8 @@ stages:
|
||||
targets:
|
||||
- name: RHEL 9.0
|
||||
test: rhel/9.0
|
||||
- name: FreeBSD 13.1
|
||||
test: freebsd/13.1
|
||||
- name: FreeBSD 12.3
|
||||
test: freebsd/12.3
|
||||
groups:
|
||||
- 1
|
||||
- 2
|
||||
@@ -289,8 +307,8 @@ stages:
|
||||
targets:
|
||||
- name: CentOS 7
|
||||
test: centos7
|
||||
- name: Fedora 36
|
||||
test: fedora36
|
||||
- name: Fedora 37
|
||||
test: fedora37
|
||||
- name: openSUSE 15
|
||||
test: opensuse15
|
||||
- name: Ubuntu 20.04
|
||||
@@ -311,8 +329,8 @@ stages:
|
||||
parameters:
|
||||
testFormat: 2.14/linux/{0}
|
||||
targets:
|
||||
- name: Ubuntu 20.04
|
||||
test: ubuntu2004
|
||||
- name: Fedora 36
|
||||
test: fedora36
|
||||
groups:
|
||||
- 1
|
||||
- 2
|
||||
@@ -386,7 +404,7 @@ stages:
|
||||
- name: ArchLinux
|
||||
test: archlinux/3.10
|
||||
- name: CentOS Stream 8
|
||||
test: centos-stream8/3.8
|
||||
test: centos-stream8/3.9
|
||||
groups:
|
||||
- 1
|
||||
- 2
|
||||
@@ -459,6 +477,7 @@ stages:
|
||||
- Units_2_12
|
||||
- Units_2_13
|
||||
- Units_2_14
|
||||
- Remote_devel_extra_vms
|
||||
- Remote_devel
|
||||
- Remote_2_11
|
||||
- Remote_2_12
|
||||
@@ -470,10 +489,11 @@ stages:
|
||||
- Docker_2_13
|
||||
- Docker_2_14
|
||||
- Docker_community_devel
|
||||
- Generic_devel
|
||||
- Generic_2_11
|
||||
- Generic_2_12
|
||||
- Generic_2_13
|
||||
- Generic_2_14
|
||||
# Right now all generic tests are disabled. Uncomment when at least one of them is re-enabled.
|
||||
# - Generic_devel
|
||||
# - Generic_2_11
|
||||
# - Generic_2_12
|
||||
# - Generic_2_13
|
||||
# - Generic_2_14
|
||||
jobs:
|
||||
- template: templates/coverage.yml
|
||||
|
||||
9
.github/BOTMETA.yml
vendored
9
.github/BOTMETA.yml
vendored
@@ -309,6 +309,9 @@ files:
|
||||
$module_utils/pipx.py:
|
||||
labels: pipx
|
||||
maintainers: russoz
|
||||
$module_utils/puppet.py:
|
||||
labels: puppet
|
||||
maintainers: russoz
|
||||
$module_utils/pure.py:
|
||||
labels: pure pure_storage
|
||||
maintainers: $team_purestorage
|
||||
@@ -320,6 +323,8 @@ files:
|
||||
$module_utils/scaleway.py:
|
||||
labels: cloud scaleway
|
||||
maintainers: $team_scaleway
|
||||
$module_utils/ssh.py:
|
||||
maintainers: russoz
|
||||
$module_utils/storage/hpe3par/hpe3par.py:
|
||||
maintainers: farhan7500 gautamphegde
|
||||
$module_utils/utm_utils.py:
|
||||
@@ -825,6 +830,10 @@ files:
|
||||
maintainers: shane-walker xcambar
|
||||
$modules/nsupdate.py:
|
||||
maintainers: nerzhul
|
||||
$modules/ocapi_command.py:
|
||||
maintainers: $team_wdc
|
||||
$modules/ocapi_info.py:
|
||||
maintainers: $team_wdc
|
||||
$modules/oci_vcn.py:
|
||||
maintainers: $team_oracle rohitChaware
|
||||
$modules/odbc.py:
|
||||
|
||||
132
CHANGELOG.rst
132
CHANGELOG.rst
@@ -6,6 +6,138 @@ Community General Release Notes
|
||||
|
||||
This changelog describes changes after version 5.0.0.
|
||||
|
||||
v6.3.0
|
||||
======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
Regular bugfix and feature release.
|
||||
|
||||
Minor Changes
|
||||
-------------
|
||||
|
||||
- apache2_module - add module argument ``warn_mpm_absent`` to control whether warning are raised in some edge cases (https://github.com/ansible-collections/community.general/pull/5793).
|
||||
- bitwarden lookup plugin - can now retrieve secrets from custom fields (https://github.com/ansible-collections/community.general/pull/5694).
|
||||
- bitwarden lookup plugin - implement filtering results by ``collection_id`` parameter (https://github.com/ansible-collections/community.general/issues/5849).
|
||||
- dig lookup plugin - support CAA record type (https://github.com/ansible-collections/community.general/pull/5913).
|
||||
- gitlab_project - add ``builds_access_level``, ``container_registry_access_level`` and ``forking_access_level`` options (https://github.com/ansible-collections/community.general/pull/5706).
|
||||
- gitlab_runner - add new boolean option ``access_level_on_creation``. It controls, whether the value of ``access_level`` is used for runner registration or not. The option ``access_level`` has been ignored on registration so far and was only used on updates (https://github.com/ansible-collections/community.general/issues/5907, https://github.com/ansible-collections/community.general/pull/5908).
|
||||
- ilo_redfish_utils module utils - change implementation of DNS Server IP and NTP Server IP update (https://github.com/ansible-collections/community.general/pull/5804).
|
||||
- ipa_group - allow to add and remove external users with the ``external_user`` option (https://github.com/ansible-collections/community.general/pull/5897).
|
||||
- iptables_state - minor refactoring within the module (https://github.com/ansible-collections/community.general/pull/5844).
|
||||
- one_vm - add a new ``updateconf`` option which implements the ``one.vm.updateconf`` API call (https://github.com/ansible-collections/community.general/pull/5812).
|
||||
- opkg - refactored module to use ``CmdRunner`` for executing ``opkg`` (https://github.com/ansible-collections/community.general/pull/5718).
|
||||
- redhat_subscription - adds ``token`` parameter for subscription-manager authentication using Red Hat API token (https://github.com/ansible-collections/community.general/pull/5725).
|
||||
- snap - minor refactor when executing module (https://github.com/ansible-collections/community.general/pull/5773).
|
||||
- snap_alias - refactored module to use ``CmdRunner`` to execute ``snap`` (https://github.com/ansible-collections/community.general/pull/5486).
|
||||
- sudoers - add ``setenv`` parameters to support passing environment variables via sudo. (https://github.com/ansible-collections/community.general/pull/5883)
|
||||
|
||||
Breaking Changes / Porting Guide
|
||||
--------------------------------
|
||||
|
||||
- ModuleHelper module utils - when the module sets output variables named ``msg``, ``exception``, ``output``, ``vars``, or ``changed``, the actual output will prefix those names with ``_`` (underscore symbol) only when they clash with output variables generated by ModuleHelper itself, which only occurs when handling exceptions. Please note that this breaking change does not require a new major release since before this release, it was not possible to add such variables to the output `due to a bug <https://github.com/ansible-collections/community.general/pull/5755>`__ (https://github.com/ansible-collections/community.general/pull/5765).
|
||||
|
||||
Deprecated Features
|
||||
-------------------
|
||||
|
||||
- consul - deprecate using parameters unused for ``state=absent`` (https://github.com/ansible-collections/community.general/pull/5772).
|
||||
- gitlab_runner - the default of the new option ``access_level_on_creation`` will change from ``false`` to ``true`` in community.general 7.0.0. This will cause ``access_level`` to be used during runner registration as well, and not only during updates (https://github.com/ansible-collections/community.general/pull/5908).
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- ModuleHelper - fix bug when adjusting the name of reserved output variables (https://github.com/ansible-collections/community.general/pull/5755).
|
||||
- alternatives - support subcommands on Fedora 37, which uses ``follower`` instead of ``slave`` (https://github.com/ansible-collections/community.general/pull/5794).
|
||||
- bitwarden lookup plugin - clarify what to do, if the bitwarden vault is not unlocked (https://github.com/ansible-collections/community.general/pull/5811).
|
||||
- dig lookup plugin - correctly handle DNSKEY record type's ``algorithm`` field (https://github.com/ansible-collections/community.general/pull/5914).
|
||||
- gem - fix force parameter not being passed to gem command when uninstalling (https://github.com/ansible-collections/community.general/pull/5822).
|
||||
- gem - fix hang due to interactive prompt for confirmation on specific version uninstall (https://github.com/ansible-collections/community.general/pull/5751).
|
||||
- gitlab_deploy_key - also update ``title`` and not just ``can_push`` (https://github.com/ansible-collections/community.general/pull/5888).
|
||||
- keycloak_user_federation - fixes federation creation issue. When a new federation was created and at the same time a default / standard mapper was also changed / updated the creation process failed as a bad None set variable led to a bad malformed url request (https://github.com/ansible-collections/community.general/pull/5750).
|
||||
- keycloak_user_federation - fixes idempotency detection issues. In some cases the module could fail to properly detect already existing user federations because of a buggy seemingly superflous extra query parameter (https://github.com/ansible-collections/community.general/pull/5732).
|
||||
- loganalytics callback plugin - adjust type of callback to ``notification``, it was incorrectly classified as ``aggregate`` before (https://github.com/ansible-collections/community.general/pull/5761).
|
||||
- logdna callback plugin - adjust type of callback to ``notification``, it was incorrectly classified as ``aggregate`` before (https://github.com/ansible-collections/community.general/pull/5761).
|
||||
- logstash callback plugin - adjust type of callback to ``notification``, it was incorrectly classified as ``aggregate`` before (https://github.com/ansible-collections/community.general/pull/5761).
|
||||
- nsupdate - fix zone lookup. The SOA record for an existing zone is returned as an answer RR and not as an authority RR (https://github.com/ansible-collections/community.general/issues/5817, https://github.com/ansible-collections/community.general/pull/5818).
|
||||
- proxmox_disk - fixed issue with read timeout on import action (https://github.com/ansible-collections/community.general/pull/5803).
|
||||
- redfish_utils - removed basic auth HTTP header when performing a GET on the service root resource and when performing a POST to the session collection (https://github.com/ansible-collections/community.general/issues/5886).
|
||||
- splunk callback plugin - adjust type of callback to ``notification``, it was incorrectly classified as ``aggregate`` before (https://github.com/ansible-collections/community.general/pull/5761).
|
||||
- sumologic callback plugin - adjust type of callback to ``notification``, it was incorrectly classified as ``aggregate`` before (https://github.com/ansible-collections/community.general/pull/5761).
|
||||
- syslog_json callback plugin - adjust type of callback to ``notification``, it was incorrectly classified as ``aggregate`` before (https://github.com/ansible-collections/community.general/pull/5761).
|
||||
- terraform - fix ``current`` workspace never getting appended to the ``all`` key in the ``workspace_ctf`` object (https://github.com/ansible-collections/community.general/pull/5735).
|
||||
- terraform - fix ``terraform init`` failure when there are multiple workspaces on the remote backend and when ``default`` workspace is missing by setting ``TF_WORKSPACE`` environmental variable to the value of ``workspace`` when used (https://github.com/ansible-collections/community.general/pull/5735).
|
||||
- terraform module - disable ANSI escape sequences during validation phase (https://github.com/ansible-collections/community.general/pull/5843).
|
||||
- xml - fixed a bug where empty ``children`` list would not be set (https://github.com/ansible-collections/community.general/pull/5808).
|
||||
|
||||
New Modules
|
||||
-----------
|
||||
|
||||
- ocapi_command - Manages Out-Of-Band controllers using Open Composable API (OCAPI)
|
||||
- ocapi_info - Manages Out-Of-Band controllers using Open Composable API (OCAPI)
|
||||
|
||||
v6.2.0
|
||||
======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
Regular bugfix and feature release.
|
||||
|
||||
Minor Changes
|
||||
-------------
|
||||
|
||||
- opkg - allow installing a package in a certain version (https://github.com/ansible-collections/community.general/pull/5688).
|
||||
- proxmox - added new module parameter ``tags`` for use with PVE 7+ (https://github.com/ansible-collections/community.general/pull/5714).
|
||||
- puppet - refactored module to use ``CmdRunner`` for executing ``puppet`` (https://github.com/ansible-collections/community.general/pull/5612).
|
||||
- redhat_subscription - add a ``server_proxy_scheme`` parameter to configure the scheme for the proxy server (https://github.com/ansible-collections/community.general/pull/5662).
|
||||
- ssh_config - refactor code to module util to fix sanity check (https://github.com/ansible-collections/community.general/pull/5720).
|
||||
- sudoers - adds ``host`` parameter for setting hostname restrictions in sudoers rules (https://github.com/ansible-collections/community.general/issues/5702).
|
||||
|
||||
Deprecated Features
|
||||
-------------------
|
||||
|
||||
- manageiq_policies - deprecate ``state=list`` in favour of using ``community.general.manageiq_policies_info`` (https://github.com/ansible-collections/community.general/pull/5721).
|
||||
- rax - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_cbs - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_cbs_attachments - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_cdb - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_cdb_database - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_cdb_user - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_clb - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_clb_nodes - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_clb_ssl - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_dns - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_dns_record - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_facts - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_files - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_files_objects - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_identity - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_keypair - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_meta - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_mon_alarm - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_mon_check - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_mon_entity - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_mon_notification - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_mon_notification_plan - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_network - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_queue - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_scaling_group - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_scaling_policy - module relies on deprecates library ``pyrax``. Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- ansible_galaxy_install - set default to raise exception if command's return code is different from zero (https://github.com/ansible-collections/community.general/pull/5680).
|
||||
- ansible_galaxy_install - try ``C.UTF-8`` and then fall back to ``en_US.UTF-8`` before failing (https://github.com/ansible-collections/community.general/pull/5680).
|
||||
- gitlab_group_variables - fix dropping variables accidentally when GitLab introduced new properties (https://github.com/ansible-collections/community.general/pull/5667).
|
||||
- gitlab_project_variables - fix dropping variables accidentally when GitLab introduced new properties (https://github.com/ansible-collections/community.general/pull/5667).
|
||||
- lxc_container - fix the arguments of the lxc command which broke the creation and cloning of containers (https://github.com/ansible-collections/community.general/issues/5578).
|
||||
- opkg - fix issue that ``force=reinstall`` would not reinstall an existing package (https://github.com/ansible-collections/community.general/pull/5705).
|
||||
- proxmox_disk - fixed possible issues with redundant ``vmid`` parameter (https://github.com/ansible-collections/community.general/issues/5492, https://github.com/ansible-collections/community.general/pull/5672).
|
||||
- proxmox_nic - fixed possible issues with redundant ``vmid`` parameter (https://github.com/ansible-collections/community.general/issues/5492, https://github.com/ansible-collections/community.general/pull/5672).
|
||||
- unixy callback plugin - fix typo introduced when updating to use Ansible's configuration manager for handling options (https://github.com/ansible-collections/community.general/issues/5600).
|
||||
|
||||
v6.1.0
|
||||
======
|
||||
|
||||
|
||||
@@ -754,3 +754,273 @@ releases:
|
||||
name: keycloak_clientsecret_regenerate
|
||||
namespace: ''
|
||||
release_date: '2022-12-06'
|
||||
6.2.0:
|
||||
changes:
|
||||
bugfixes:
|
||||
- ansible_galaxy_install - set default to raise exception if command's return
|
||||
code is different from zero (https://github.com/ansible-collections/community.general/pull/5680).
|
||||
- ansible_galaxy_install - try ``C.UTF-8`` and then fall back to ``en_US.UTF-8``
|
||||
before failing (https://github.com/ansible-collections/community.general/pull/5680).
|
||||
- gitlab_group_variables - fix dropping variables accidentally when GitLab introduced
|
||||
new properties (https://github.com/ansible-collections/community.general/pull/5667).
|
||||
- gitlab_project_variables - fix dropping variables accidentally when GitLab
|
||||
introduced new properties (https://github.com/ansible-collections/community.general/pull/5667).
|
||||
- lxc_container - fix the arguments of the lxc command which broke the creation
|
||||
and cloning of containers (https://github.com/ansible-collections/community.general/issues/5578).
|
||||
- opkg - fix issue that ``force=reinstall`` would not reinstall an existing
|
||||
package (https://github.com/ansible-collections/community.general/pull/5705).
|
||||
- proxmox_disk - fixed possible issues with redundant ``vmid`` parameter (https://github.com/ansible-collections/community.general/issues/5492,
|
||||
https://github.com/ansible-collections/community.general/pull/5672).
|
||||
- proxmox_nic - fixed possible issues with redundant ``vmid`` parameter (https://github.com/ansible-collections/community.general/issues/5492,
|
||||
https://github.com/ansible-collections/community.general/pull/5672).
|
||||
- unixy callback plugin - fix typo introduced when updating to use Ansible's
|
||||
configuration manager for handling options (https://github.com/ansible-collections/community.general/issues/5600).
|
||||
deprecated_features:
|
||||
- manageiq_policies - deprecate ``state=list`` in favour of using ``community.general.manageiq_policies_info``
|
||||
(https://github.com/ansible-collections/community.general/pull/5721).
|
||||
- rax - module relies on deprecates library ``pyrax``. Unless maintainers step
|
||||
up to work on the module, it will be marked as deprecated in community.general
|
||||
7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_cbs - module relies on deprecates library ``pyrax``. Unless maintainers
|
||||
step up to work on the module, it will be marked as deprecated in community.general
|
||||
7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_cbs_attachments - module relies on deprecates library ``pyrax``. Unless
|
||||
maintainers step up to work on the module, it will be marked as deprecated
|
||||
in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_cdb - module relies on deprecates library ``pyrax``. Unless maintainers
|
||||
step up to work on the module, it will be marked as deprecated in community.general
|
||||
7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_cdb_database - module relies on deprecates library ``pyrax``. Unless maintainers
|
||||
step up to work on the module, it will be marked as deprecated in community.general
|
||||
7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_cdb_user - module relies on deprecates library ``pyrax``. Unless maintainers
|
||||
step up to work on the module, it will be marked as deprecated in community.general
|
||||
7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_clb - module relies on deprecates library ``pyrax``. Unless maintainers
|
||||
step up to work on the module, it will be marked as deprecated in community.general
|
||||
7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_clb_nodes - module relies on deprecates library ``pyrax``. Unless maintainers
|
||||
step up to work on the module, it will be marked as deprecated in community.general
|
||||
7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_clb_ssl - module relies on deprecates library ``pyrax``. Unless maintainers
|
||||
step up to work on the module, it will be marked as deprecated in community.general
|
||||
7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_dns - module relies on deprecates library ``pyrax``. Unless maintainers
|
||||
step up to work on the module, it will be marked as deprecated in community.general
|
||||
7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_dns_record - module relies on deprecates library ``pyrax``. Unless maintainers
|
||||
step up to work on the module, it will be marked as deprecated in community.general
|
||||
7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_facts - module relies on deprecates library ``pyrax``. Unless maintainers
|
||||
step up to work on the module, it will be marked as deprecated in community.general
|
||||
7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_files - module relies on deprecates library ``pyrax``. Unless maintainers
|
||||
step up to work on the module, it will be marked as deprecated in community.general
|
||||
7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_files_objects - module relies on deprecates library ``pyrax``. Unless
|
||||
maintainers step up to work on the module, it will be marked as deprecated
|
||||
in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_identity - module relies on deprecates library ``pyrax``. Unless maintainers
|
||||
step up to work on the module, it will be marked as deprecated in community.general
|
||||
7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_keypair - module relies on deprecates library ``pyrax``. Unless maintainers
|
||||
step up to work on the module, it will be marked as deprecated in community.general
|
||||
7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_meta - module relies on deprecates library ``pyrax``. Unless maintainers
|
||||
step up to work on the module, it will be marked as deprecated in community.general
|
||||
7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_mon_alarm - module relies on deprecates library ``pyrax``. Unless maintainers
|
||||
step up to work on the module, it will be marked as deprecated in community.general
|
||||
7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_mon_check - module relies on deprecates library ``pyrax``. Unless maintainers
|
||||
step up to work on the module, it will be marked as deprecated in community.general
|
||||
7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_mon_entity - module relies on deprecates library ``pyrax``. Unless maintainers
|
||||
step up to work on the module, it will be marked as deprecated in community.general
|
||||
7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_mon_notification - module relies on deprecates library ``pyrax``. Unless
|
||||
maintainers step up to work on the module, it will be marked as deprecated
|
||||
in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_mon_notification_plan - module relies on deprecates library ``pyrax``.
|
||||
Unless maintainers step up to work on the module, it will be marked as deprecated
|
||||
in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_network - module relies on deprecates library ``pyrax``. Unless maintainers
|
||||
step up to work on the module, it will be marked as deprecated in community.general
|
||||
7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_queue - module relies on deprecates library ``pyrax``. Unless maintainers
|
||||
step up to work on the module, it will be marked as deprecated in community.general
|
||||
7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_scaling_group - module relies on deprecates library ``pyrax``. Unless
|
||||
maintainers step up to work on the module, it will be marked as deprecated
|
||||
in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
- rax_scaling_policy - module relies on deprecates library ``pyrax``. Unless
|
||||
maintainers step up to work on the module, it will be marked as deprecated
|
||||
in community.general 7.0.0 and removed in version 9.0.0 (https://github.com/ansible-collections/community.general/pull/5733).
|
||||
minor_changes:
|
||||
- opkg - allow installing a package in a certain version (https://github.com/ansible-collections/community.general/pull/5688).
|
||||
- proxmox - added new module parameter ``tags`` for use with PVE 7+ (https://github.com/ansible-collections/community.general/pull/5714).
|
||||
- puppet - refactored module to use ``CmdRunner`` for executing ``puppet`` (https://github.com/ansible-collections/community.general/pull/5612).
|
||||
- redhat_subscription - add a ``server_proxy_scheme`` parameter to configure
|
||||
the scheme for the proxy server (https://github.com/ansible-collections/community.general/pull/5662).
|
||||
- ssh_config - refactor code to module util to fix sanity check (https://github.com/ansible-collections/community.general/pull/5720).
|
||||
- sudoers - adds ``host`` parameter for setting hostname restrictions in sudoers
|
||||
rules (https://github.com/ansible-collections/community.general/issues/5702).
|
||||
release_summary: Regular bugfix and feature release.
|
||||
fragments:
|
||||
- 5612-puppet-cmd-runner.yml
|
||||
- 5659-fix-lxc_container-command.yml
|
||||
- 5662-redhat_subscription-server_proxy_scheme.yaml
|
||||
- 5666-gitlab-variables.yml
|
||||
- 5672-proxmox.yml
|
||||
- 5680-ansible_galaxy_install-fx-locale.yaml
|
||||
- 5688-opkg-module-install-certain-version.yml
|
||||
- 5703-sudoers-host-support.yml
|
||||
- 5705-opkg-fix-force-reinstall.yml
|
||||
- 5714-proxmox-lxc-tag-support.yml
|
||||
- 5720-ssh_config-plugin-sanity.yml
|
||||
- 5721-manageiq-policies-deprecate-list-state.yaml
|
||||
- 5733-rax-deprecation-notice.yml
|
||||
- 5744-unixy-callback-fix-config-manager-typo.yml
|
||||
- 6.2.0.yml
|
||||
release_date: '2023-01-04'
|
||||
6.3.0:
|
||||
changes:
|
||||
breaking_changes:
|
||||
- 'ModuleHelper module utils - when the module sets output variables named ``msg``,
|
||||
``exception``, ``output``, ``vars``, or ``changed``, the actual output will
|
||||
prefix those names with ``_`` (underscore symbol) only when they clash with
|
||||
output variables generated by ModuleHelper itself, which only occurs when
|
||||
handling exceptions. Please note that this breaking change does not require
|
||||
a new major release since before this release, it was not possible to add
|
||||
such variables to the output `due to a bug <https://github.com/ansible-collections/community.general/pull/5755>`__
|
||||
(https://github.com/ansible-collections/community.general/pull/5765).
|
||||
|
||||
'
|
||||
bugfixes:
|
||||
- ModuleHelper - fix bug when adjusting the name of reserved output variables
|
||||
(https://github.com/ansible-collections/community.general/pull/5755).
|
||||
- alternatives - support subcommands on Fedora 37, which uses ``follower`` instead
|
||||
of ``slave`` (https://github.com/ansible-collections/community.general/pull/5794).
|
||||
- bitwarden lookup plugin - clarify what to do, if the bitwarden vault is not
|
||||
unlocked (https://github.com/ansible-collections/community.general/pull/5811).
|
||||
- dig lookup plugin - correctly handle DNSKEY record type's ``algorithm`` field
|
||||
(https://github.com/ansible-collections/community.general/pull/5914).
|
||||
- gem - fix force parameter not being passed to gem command when uninstalling
|
||||
(https://github.com/ansible-collections/community.general/pull/5822).
|
||||
- gem - fix hang due to interactive prompt for confirmation on specific version
|
||||
uninstall (https://github.com/ansible-collections/community.general/pull/5751).
|
||||
- gitlab_deploy_key - also update ``title`` and not just ``can_push`` (https://github.com/ansible-collections/community.general/pull/5888).
|
||||
- keycloak_user_federation - fixes federation creation issue. When a new federation
|
||||
was created and at the same time a default / standard mapper was also changed
|
||||
/ updated the creation process failed as a bad None set variable led to a
|
||||
bad malformed url request (https://github.com/ansible-collections/community.general/pull/5750).
|
||||
- 'keycloak_user_federation - fixes idempotency detection issues. In some cases
|
||||
the module could fail to properly detect already existing user federations
|
||||
because of a buggy seemingly superflous extra query parameter (https://github.com/ansible-collections/community.general/pull/5732).
|
||||
|
||||
'
|
||||
- loganalytics callback plugin - adjust type of callback to ``notification``,
|
||||
it was incorrectly classified as ``aggregate`` before (https://github.com/ansible-collections/community.general/pull/5761).
|
||||
- logdna callback plugin - adjust type of callback to ``notification``, it was
|
||||
incorrectly classified as ``aggregate`` before (https://github.com/ansible-collections/community.general/pull/5761).
|
||||
- logstash callback plugin - adjust type of callback to ``notification``, it
|
||||
was incorrectly classified as ``aggregate`` before (https://github.com/ansible-collections/community.general/pull/5761).
|
||||
- nsupdate - fix zone lookup. The SOA record for an existing zone is returned
|
||||
as an answer RR and not as an authority RR (https://github.com/ansible-collections/community.general/issues/5817,
|
||||
https://github.com/ansible-collections/community.general/pull/5818).
|
||||
- proxmox_disk - fixed issue with read timeout on import action (https://github.com/ansible-collections/community.general/pull/5803).
|
||||
- redfish_utils - removed basic auth HTTP header when performing a GET on the
|
||||
service root resource and when performing a POST to the session collection
|
||||
(https://github.com/ansible-collections/community.general/issues/5886).
|
||||
- splunk callback plugin - adjust type of callback to ``notification``, it was
|
||||
incorrectly classified as ``aggregate`` before (https://github.com/ansible-collections/community.general/pull/5761).
|
||||
- sumologic callback plugin - adjust type of callback to ``notification``, it
|
||||
was incorrectly classified as ``aggregate`` before (https://github.com/ansible-collections/community.general/pull/5761).
|
||||
- syslog_json callback plugin - adjust type of callback to ``notification``,
|
||||
it was incorrectly classified as ``aggregate`` before (https://github.com/ansible-collections/community.general/pull/5761).
|
||||
- terraform - fix ``current`` workspace never getting appended to the ``all``
|
||||
key in the ``workspace_ctf`` object (https://github.com/ansible-collections/community.general/pull/5735).
|
||||
- terraform - fix ``terraform init`` failure when there are multiple workspaces
|
||||
on the remote backend and when ``default`` workspace is missing by setting
|
||||
``TF_WORKSPACE`` environmental variable to the value of ``workspace`` when
|
||||
used (https://github.com/ansible-collections/community.general/pull/5735).
|
||||
- terraform module - disable ANSI escape sequences during validation phase (https://github.com/ansible-collections/community.general/pull/5843).
|
||||
- xml - fixed a bug where empty ``children`` list would not be set (https://github.com/ansible-collections/community.general/pull/5808).
|
||||
deprecated_features:
|
||||
- consul - deprecate using parameters unused for ``state=absent`` (https://github.com/ansible-collections/community.general/pull/5772).
|
||||
- gitlab_runner - the default of the new option ``access_level_on_creation``
|
||||
will change from ``false`` to ``true`` in community.general 7.0.0. This will
|
||||
cause ``access_level`` to be used during runner registration as well, and
|
||||
not only during updates (https://github.com/ansible-collections/community.general/pull/5908).
|
||||
minor_changes:
|
||||
- apache2_module - add module argument ``warn_mpm_absent`` to control whether
|
||||
warning are raised in some edge cases (https://github.com/ansible-collections/community.general/pull/5793).
|
||||
- bitwarden lookup plugin - can now retrieve secrets from custom fields (https://github.com/ansible-collections/community.general/pull/5694).
|
||||
- bitwarden lookup plugin - implement filtering results by ``collection_id``
|
||||
parameter (https://github.com/ansible-collections/community.general/issues/5849).
|
||||
- dig lookup plugin - support CAA record type (https://github.com/ansible-collections/community.general/pull/5913).
|
||||
- gitlab_project - add ``builds_access_level``, ``container_registry_access_level``
|
||||
and ``forking_access_level`` options (https://github.com/ansible-collections/community.general/pull/5706).
|
||||
- gitlab_runner - add new boolean option ``access_level_on_creation``. It controls,
|
||||
whether the value of ``access_level`` is used for runner registration or not.
|
||||
The option ``access_level`` has been ignored on registration so far and was
|
||||
only used on updates (https://github.com/ansible-collections/community.general/issues/5907,
|
||||
https://github.com/ansible-collections/community.general/pull/5908).
|
||||
- ilo_redfish_utils module utils - change implementation of DNS Server IP and
|
||||
NTP Server IP update (https://github.com/ansible-collections/community.general/pull/5804).
|
||||
- ipa_group - allow to add and remove external users with the ``external_user``
|
||||
option (https://github.com/ansible-collections/community.general/pull/5897).
|
||||
- iptables_state - minor refactoring within the module (https://github.com/ansible-collections/community.general/pull/5844).
|
||||
- one_vm - add a new ``updateconf`` option which implements the ``one.vm.updateconf``
|
||||
API call (https://github.com/ansible-collections/community.general/pull/5812).
|
||||
- opkg - refactored module to use ``CmdRunner`` for executing ``opkg`` (https://github.com/ansible-collections/community.general/pull/5718).
|
||||
- redhat_subscription - adds ``token`` parameter for subscription-manager authentication
|
||||
using Red Hat API token (https://github.com/ansible-collections/community.general/pull/5725).
|
||||
- snap - minor refactor when executing module (https://github.com/ansible-collections/community.general/pull/5773).
|
||||
- snap_alias - refactored module to use ``CmdRunner`` to execute ``snap`` (https://github.com/ansible-collections/community.general/pull/5486).
|
||||
- sudoers - add ``setenv`` parameters to support passing environment variables
|
||||
via sudo. (https://github.com/ansible-collections/community.general/pull/5883)
|
||||
release_summary: Regular bugfix and feature release.
|
||||
fragments:
|
||||
- 5486-snap-alias-cmd-runner.yml
|
||||
- 5694-add-custom-fields-to-bitwarden.yml
|
||||
- 5706-add-builds-forks-container-registry.yml
|
||||
- 5718-opkg-refactor.yaml
|
||||
- 5725-redhat_subscription-add-red-hat-api-token.yml
|
||||
- 5732-bugfix-keycloak-userfed-idempotency.yml
|
||||
- 5735-terraform-init-fix-when-default-workspace-doesnt-exists.yaml
|
||||
- 5750-bugfixing-keycloak-usrfed-fail-when-update-default-mapper-simultaneously.yml
|
||||
- 5751-gem-fix-uninstall-hang.yml
|
||||
- 5755-mh-fix-output-conflict.yml
|
||||
- 5761-callback-types.yml
|
||||
- 5765-mh-lax-output-conflict.yml
|
||||
- 5772-consul-deprecate-params-when-absent.yml
|
||||
- 5773-snap-mh-execute.yml
|
||||
- 5793-apache2-module-npm-warnings.yml
|
||||
- 5794-alternatives-fedora37.yml
|
||||
- 5803-proxmox-read-timeout.yml
|
||||
- 5804-minor-changes-to-hpe-ilo-collection.yml
|
||||
- 5808-xml-children-parameter-does-not-exist.yml
|
||||
- 5811-clarify-bitwarden-error.yml
|
||||
- 5812-implement-updateconf-api-call.yml
|
||||
- 5818-nsupdate-fix-zone-lookup.yml
|
||||
- 5822-gem-uninstall-force.yml
|
||||
- 5843-terraform-validate-no-color.yml
|
||||
- 5844-iptables-state-refactor.yml
|
||||
- 5851-lookup-bitwarden-add-filter-by-collection-id-parameter.yml
|
||||
- 5883-sudoers-add-support-for-setenv-parameter.yml
|
||||
- 5886-redfish-correct-basic-auth-usage-on-session-creation.yml
|
||||
- 5888-update-key-title.yml
|
||||
- 5897-ipa_group-add-external-users.yml
|
||||
- 5907-fix-gitlab_runner-not-idempotent.yml
|
||||
- 5913-dig-caa.yml
|
||||
- 5914-dig-dnskey.yml
|
||||
- 6.3.0.yml
|
||||
modules:
|
||||
- description: Manages Out-Of-Band controllers using Open Composable API (OCAPI)
|
||||
name: ocapi_command
|
||||
namespace: ''
|
||||
- description: Manages Out-Of-Band controllers using Open Composable API (OCAPI)
|
||||
name: ocapi_info
|
||||
namespace: ''
|
||||
release_date: '2023-01-31'
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
namespace: community
|
||||
name: general
|
||||
version: 6.1.0
|
||||
version: 6.3.0
|
||||
readme: README.md
|
||||
authors:
|
||||
- Ansible (https://github.com/ansible)
|
||||
|
||||
@@ -16,15 +16,15 @@ DOCUMENTATION = '''
|
||||
- cgroups
|
||||
short_description: Profiles maximum memory usage of tasks and full execution using cgroups
|
||||
description:
|
||||
- This is an ansible callback plugin that profiles maximum memory usage of ansible and individual tasks, and displays a recap at the end using cgroups
|
||||
- This is an ansible callback plugin that profiles maximum memory usage of ansible and individual tasks, and displays a recap at the end using cgroups.
|
||||
notes:
|
||||
- Requires ansible to be run from within a cgroup, such as with C(cgexec -g memory:ansible_profile ansible-playbook ...)
|
||||
- This cgroup should only be used by ansible to get accurate results
|
||||
- To create the cgroup, first use a command such as C(sudo cgcreate -a ec2-user:ec2-user -t ec2-user:ec2-user -g memory:ansible_profile)
|
||||
- Requires ansible to be run from within a cgroup, such as with C(cgexec -g memory:ansible_profile ansible-playbook ...).
|
||||
- This cgroup should only be used by ansible to get accurate results.
|
||||
- To create the cgroup, first use a command such as C(sudo cgcreate -a ec2-user:ec2-user -t ec2-user:ec2-user -g memory:ansible_profile).
|
||||
options:
|
||||
max_mem_file:
|
||||
required: true
|
||||
description: Path to cgroups C(memory.max_usage_in_bytes) file. Example C(/sys/fs/cgroup/memory/ansible_profile/memory.max_usage_in_bytes)
|
||||
description: Path to cgroups C(memory.max_usage_in_bytes) file. Example C(/sys/fs/cgroup/memory/ansible_profile/memory.max_usage_in_bytes).
|
||||
env:
|
||||
- name: CGROUP_MAX_MEM_FILE
|
||||
ini:
|
||||
@@ -32,7 +32,7 @@ DOCUMENTATION = '''
|
||||
key: max_mem_file
|
||||
cur_mem_file:
|
||||
required: true
|
||||
description: Path to C(memory.usage_in_bytes) file. Example C(/sys/fs/cgroup/memory/ansible_profile/memory.usage_in_bytes)
|
||||
description: Path to C(memory.usage_in_bytes) file. Example C(/sys/fs/cgroup/memory/ansible_profile/memory.usage_in_bytes).
|
||||
env:
|
||||
- name: CGROUP_CUR_MEM_FILE
|
||||
ini:
|
||||
|
||||
@@ -13,8 +13,8 @@ DOCUMENTATION = '''
|
||||
type: aggregate
|
||||
short_description: demo callback that adds play/task context
|
||||
description:
|
||||
- Displays some play and task context along with normal output
|
||||
- This is mostly for demo purposes
|
||||
- Displays some play and task context along with normal output.
|
||||
- This is mostly for demo purposes.
|
||||
requirements:
|
||||
- whitelist in configuration
|
||||
'''
|
||||
|
||||
@@ -21,7 +21,7 @@ DOCUMENTATION = '''
|
||||
extends_documentation_fragment:
|
||||
- default_callback
|
||||
requirements:
|
||||
- set as stdout callback in ansible.cfg (stdout_callback = counter_enabled)
|
||||
- set as stdout callback in C(ansible.cfg) (C(stdout_callback = counter_enabled))
|
||||
'''
|
||||
|
||||
from ansible import constants as C
|
||||
|
||||
@@ -14,7 +14,7 @@ short_description: minimal stdout output
|
||||
extends_documentation_fragment:
|
||||
- default_callback
|
||||
description:
|
||||
- When in verbose mode it will act the same as the default callback
|
||||
- When in verbose mode it will act the same as the default callback.
|
||||
author:
|
||||
- Dag Wieers (@dagwieers)
|
||||
requirements:
|
||||
|
||||
@@ -13,10 +13,10 @@ DOCUMENTATION = '''
|
||||
type: notification
|
||||
short_description: post task events to a jabber server
|
||||
description:
|
||||
- The chatty part of ChatOps with a Hipchat server as a target
|
||||
- The chatty part of ChatOps with a Hipchat server as a target.
|
||||
- This callback plugin sends status updates to a HipChat channel during playbook execution.
|
||||
requirements:
|
||||
- xmpp (python lib https://github.com/ArchipelProject/xmpppy)
|
||||
- xmpp (Python library U(https://github.com/ArchipelProject/xmpppy))
|
||||
options:
|
||||
server:
|
||||
description: connection info to jabber server
|
||||
|
||||
@@ -13,10 +13,10 @@ DOCUMENTATION = '''
|
||||
type: notification
|
||||
short_description: write playbook output to log file
|
||||
description:
|
||||
- This callback writes playbook output to a file per host in the C(/var/log/ansible/hosts) directory
|
||||
- This callback writes playbook output to a file per host in the C(/var/log/ansible/hosts) directory.
|
||||
requirements:
|
||||
- Whitelist in configuration
|
||||
- A writeable /var/log/ansible/hosts directory by the user executing Ansible on the controller
|
||||
- A writeable C(/var/log/ansible/hosts) directory by the user executing Ansible on the controller
|
||||
options:
|
||||
log_folder:
|
||||
default: /var/log/ansible/hosts
|
||||
|
||||
@@ -8,7 +8,7 @@ __metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
name: loganalytics
|
||||
type: aggregate
|
||||
type: notification
|
||||
short_description: Posts task results to Azure Log Analytics
|
||||
author: "Cyrus Li (@zhcli) <cyrus1006@gmail.com>"
|
||||
description:
|
||||
@@ -155,7 +155,7 @@ class AzureLogAnalyticsSource(object):
|
||||
|
||||
class CallbackModule(CallbackBase):
|
||||
CALLBACK_VERSION = 2.0
|
||||
CALLBACK_TYPE = 'aggregate'
|
||||
CALLBACK_TYPE = 'notification'
|
||||
CALLBACK_NAME = 'loganalytics'
|
||||
CALLBACK_NEEDS_WHITELIST = True
|
||||
|
||||
|
||||
@@ -9,17 +9,17 @@ __metaclass__ = type
|
||||
DOCUMENTATION = '''
|
||||
author: Unknown (!UNKNOWN)
|
||||
name: logdna
|
||||
type: aggregate
|
||||
type: notification
|
||||
short_description: Sends playbook logs to LogDNA
|
||||
description:
|
||||
- This callback will report logs from playbook actions, tasks, and events to LogDNA (https://app.logdna.com)
|
||||
- This callback will report logs from playbook actions, tasks, and events to LogDNA (U(https://app.logdna.com)).
|
||||
requirements:
|
||||
- LogDNA Python Library (https://github.com/logdna/python)
|
||||
- LogDNA Python Library (U(https://github.com/logdna/python))
|
||||
- whitelisting in configuration
|
||||
options:
|
||||
conf_key:
|
||||
required: true
|
||||
description: LogDNA Ingestion Key
|
||||
description: LogDNA Ingestion Key.
|
||||
type: string
|
||||
env:
|
||||
- name: LOGDNA_INGESTION_KEY
|
||||
@@ -28,7 +28,7 @@ DOCUMENTATION = '''
|
||||
key: conf_key
|
||||
plugin_ignore_errors:
|
||||
required: false
|
||||
description: Whether to ignore errors on failing or not
|
||||
description: Whether to ignore errors on failing or not.
|
||||
type: boolean
|
||||
env:
|
||||
- name: ANSIBLE_IGNORE_ERRORS
|
||||
@@ -38,7 +38,7 @@ DOCUMENTATION = '''
|
||||
default: false
|
||||
conf_hostname:
|
||||
required: false
|
||||
description: Alternative Host Name; the current host name by default
|
||||
description: Alternative Host Name; the current host name by default.
|
||||
type: string
|
||||
env:
|
||||
- name: LOGDNA_HOSTNAME
|
||||
@@ -47,7 +47,7 @@ DOCUMENTATION = '''
|
||||
key: conf_hostname
|
||||
conf_tags:
|
||||
required: false
|
||||
description: Tags
|
||||
description: Tags.
|
||||
type: string
|
||||
env:
|
||||
- name: LOGDNA_TAGS
|
||||
@@ -111,7 +111,7 @@ def isJSONable(obj):
|
||||
class CallbackModule(CallbackBase):
|
||||
|
||||
CALLBACK_VERSION = 0.1
|
||||
CALLBACK_TYPE = 'aggregate'
|
||||
CALLBACK_TYPE = 'notification'
|
||||
CALLBACK_NAME = 'community.general.logdna'
|
||||
CALLBACK_NEEDS_WHITELIST = True
|
||||
|
||||
|
||||
@@ -13,15 +13,15 @@ DOCUMENTATION = '''
|
||||
short_description: Sends events to Logentries
|
||||
description:
|
||||
- This callback plugin will generate JSON objects and send them to Logentries via TCP for auditing/debugging purposes.
|
||||
- Before 2.4, if you wanted to use an ini configuration, the file must be placed in the same directory as this plugin and named logentries.ini
|
||||
- Before 2.4, if you wanted to use an ini configuration, the file must be placed in the same directory as this plugin and named C(logentries.ini).
|
||||
- In 2.4 and above you can just put it in the main Ansible configuration file.
|
||||
requirements:
|
||||
- whitelisting in configuration
|
||||
- certifi (python library)
|
||||
- flatdict (python library), if you want to use the 'flatten' option
|
||||
- certifi (Python library)
|
||||
- flatdict (Python library), if you want to use the 'flatten' option
|
||||
options:
|
||||
api:
|
||||
description: URI to the Logentries API
|
||||
description: URI to the Logentries API.
|
||||
env:
|
||||
- name: LOGENTRIES_API
|
||||
default: data.logentries.com
|
||||
@@ -29,7 +29,7 @@ DOCUMENTATION = '''
|
||||
- section: callback_logentries
|
||||
key: api
|
||||
port:
|
||||
description: HTTP port to use when connecting to the API
|
||||
description: HTTP port to use when connecting to the API.
|
||||
env:
|
||||
- name: LOGENTRIES_PORT
|
||||
default: 80
|
||||
@@ -37,7 +37,7 @@ DOCUMENTATION = '''
|
||||
- section: callback_logentries
|
||||
key: port
|
||||
tls_port:
|
||||
description: Port to use when connecting to the API when TLS is enabled
|
||||
description: Port to use when connecting to the API when TLS is enabled.
|
||||
env:
|
||||
- name: LOGENTRIES_TLS_PORT
|
||||
default: 443
|
||||
@@ -45,7 +45,7 @@ DOCUMENTATION = '''
|
||||
- section: callback_logentries
|
||||
key: tls_port
|
||||
token:
|
||||
description: The logentries "TCP token"
|
||||
description: The logentries C(TCP token).
|
||||
env:
|
||||
- name: LOGENTRIES_ANSIBLE_TOKEN
|
||||
required: true
|
||||
@@ -54,7 +54,7 @@ DOCUMENTATION = '''
|
||||
key: token
|
||||
use_tls:
|
||||
description:
|
||||
- Toggle to decide whether to use TLS to encrypt the communications with the API server
|
||||
- Toggle to decide whether to use TLS to encrypt the communications with the API server.
|
||||
env:
|
||||
- name: LOGENTRIES_USE_TLS
|
||||
default: false
|
||||
@@ -63,7 +63,7 @@ DOCUMENTATION = '''
|
||||
- section: callback_logentries
|
||||
key: use_tls
|
||||
flatten:
|
||||
description: flatten complex data structures into a single dictionary with complex keys
|
||||
description: Flatten complex data structures into a single dictionary with complex keys.
|
||||
type: boolean
|
||||
default: false
|
||||
env:
|
||||
|
||||
@@ -13,13 +13,13 @@ DOCUMENTATION = r'''
|
||||
type: notification
|
||||
short_description: Sends events to Logstash
|
||||
description:
|
||||
- This callback will report facts and task events to Logstash https://www.elastic.co/products/logstash
|
||||
- This callback will report facts and task events to Logstash U(https://www.elastic.co/products/logstash).
|
||||
requirements:
|
||||
- whitelisting in configuration
|
||||
- logstash (python library)
|
||||
- logstash (Python library)
|
||||
options:
|
||||
server:
|
||||
description: Address of the Logstash server
|
||||
description: Address of the Logstash server.
|
||||
env:
|
||||
- name: LOGSTASH_SERVER
|
||||
ini:
|
||||
@@ -28,7 +28,7 @@ DOCUMENTATION = r'''
|
||||
version_added: 1.0.0
|
||||
default: localhost
|
||||
port:
|
||||
description: Port on which logstash is listening
|
||||
description: Port on which logstash is listening.
|
||||
env:
|
||||
- name: LOGSTASH_PORT
|
||||
ini:
|
||||
@@ -37,7 +37,7 @@ DOCUMENTATION = r'''
|
||||
version_added: 1.0.0
|
||||
default: 5000
|
||||
type:
|
||||
description: Message type
|
||||
description: Message type.
|
||||
env:
|
||||
- name: LOGSTASH_TYPE
|
||||
ini:
|
||||
@@ -54,7 +54,7 @@ DOCUMENTATION = r'''
|
||||
env:
|
||||
- name: LOGSTASH_PRE_COMMAND
|
||||
format_version:
|
||||
description: Logging format
|
||||
description: Logging format.
|
||||
type: str
|
||||
version_added: 2.0.0
|
||||
ini:
|
||||
@@ -113,7 +113,7 @@ from ansible.plugins.callback import CallbackBase
|
||||
class CallbackModule(CallbackBase):
|
||||
|
||||
CALLBACK_VERSION = 2.0
|
||||
CALLBACK_TYPE = 'aggregate'
|
||||
CALLBACK_TYPE = 'notification'
|
||||
CALLBACK_NAME = 'community.general.logstash'
|
||||
CALLBACK_NEEDS_WHITELIST = True
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ DOCUMENTATION = '''
|
||||
- set as main display callback
|
||||
short_description: Don't display stuff to screen
|
||||
description:
|
||||
- This callback prevents outputing events to screen
|
||||
- This callback prevents outputing events to screen.
|
||||
'''
|
||||
|
||||
from ansible.plugins.callback import CallbackBase
|
||||
|
||||
@@ -14,12 +14,12 @@ DOCUMENTATION = '''
|
||||
type: notification
|
||||
requirements:
|
||||
- whitelisting in configuration
|
||||
- the '/usr/bin/say' command line program (standard on macOS) or 'espeak' command line program
|
||||
- the C(/usr/bin/say) command line program (standard on macOS) or C(espeak) command line program
|
||||
short_description: notify using software speech synthesizer
|
||||
description:
|
||||
- This plugin will use the 'say' or 'espeak' program to "speak" about play events.
|
||||
- This plugin will use the C(say) or C(espeak) program to "speak" about play events.
|
||||
notes:
|
||||
- In 2.8, this callback has been renamed from C(osx_say) into M(community.general.say).
|
||||
- In Ansible 2.8, this callback has been renamed from C(osx_say) into M(community.general.say).
|
||||
'''
|
||||
|
||||
import platform
|
||||
|
||||
@@ -22,7 +22,7 @@ DOCUMENTATION = '''
|
||||
options:
|
||||
nocolor:
|
||||
default: false
|
||||
description: This setting allows suppressing colorizing output
|
||||
description: This setting allows suppressing colorizing output.
|
||||
env:
|
||||
- name: ANSIBLE_NOCOLOR
|
||||
- name: ANSIBLE_SELECTIVE_DONT_COLORIZE
|
||||
|
||||
@@ -18,11 +18,11 @@ DOCUMENTATION = '''
|
||||
short_description: Sends play events to a Slack channel
|
||||
description:
|
||||
- This is an ansible callback plugin that sends status updates to a Slack channel during playbook execution.
|
||||
- Before 2.4 only environment variables were available for configuring this plugin
|
||||
- Before Ansible 2.4 only environment variables were available for configuring this plugin.
|
||||
options:
|
||||
webhook_url:
|
||||
required: true
|
||||
description: Slack Webhook URL
|
||||
description: Slack Webhook URL.
|
||||
env:
|
||||
- name: SLACK_WEBHOOK_URL
|
||||
ini:
|
||||
@@ -45,7 +45,7 @@ DOCUMENTATION = '''
|
||||
- section: callback_slack
|
||||
key: username
|
||||
validate_certs:
|
||||
description: validate the SSL certificate of the Slack server. (For HTTPS URLs)
|
||||
description: Validate the SSL certificate of the Slack server for HTTPS URLs.
|
||||
env:
|
||||
- name: SLACK_VALIDATE_CERTS
|
||||
ini:
|
||||
|
||||
@@ -8,27 +8,27 @@ __metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
name: splunk
|
||||
type: aggregate
|
||||
type: notification
|
||||
short_description: Sends task result events to Splunk HTTP Event Collector
|
||||
author: "Stuart Hirst (!UNKNOWN) <support@convergingdata.com>"
|
||||
description:
|
||||
- This callback plugin will send task results as JSON formatted events to a Splunk HTTP collector.
|
||||
- The companion Splunk Monitoring & Diagnostics App is available here "https://splunkbase.splunk.com/app/4023/"
|
||||
- The companion Splunk Monitoring & Diagnostics App is available here U(https://splunkbase.splunk.com/app/4023/).
|
||||
- Credit to "Ryan Currah (@ryancurrah)" for original source upon which this is based.
|
||||
requirements:
|
||||
- Whitelisting this callback plugin
|
||||
- 'Create a HTTP Event Collector in Splunk'
|
||||
- 'Define the url and token in ansible.cfg'
|
||||
- 'Define the URL and token in C(ansible.cfg)'
|
||||
options:
|
||||
url:
|
||||
description: URL to the Splunk HTTP collector source
|
||||
description: URL to the Splunk HTTP collector source.
|
||||
env:
|
||||
- name: SPLUNK_URL
|
||||
ini:
|
||||
- section: callback_splunk
|
||||
key: url
|
||||
authtoken:
|
||||
description: Token to authenticate the connection to the Splunk HTTP collector
|
||||
description: Token to authenticate the connection to the Splunk HTTP collector.
|
||||
env:
|
||||
- name: SPLUNK_AUTHTOKEN
|
||||
ini:
|
||||
@@ -48,7 +48,7 @@ DOCUMENTATION = '''
|
||||
version_added: '1.0.0'
|
||||
include_milliseconds:
|
||||
description: Whether to include milliseconds as part of the generated timestamp field in the event
|
||||
sent to the Splunk HTTP collector
|
||||
sent to the Splunk HTTP collector.
|
||||
env:
|
||||
- name: SPLUNK_INCLUDE_MILLISECONDS
|
||||
ini:
|
||||
@@ -165,7 +165,7 @@ class SplunkHTTPCollectorSource(object):
|
||||
|
||||
class CallbackModule(CallbackBase):
|
||||
CALLBACK_VERSION = 2.0
|
||||
CALLBACK_TYPE = 'aggregate'
|
||||
CALLBACK_TYPE = 'notification'
|
||||
CALLBACK_NAME = 'community.general.splunk'
|
||||
CALLBACK_NEEDS_WHITELIST = True
|
||||
|
||||
|
||||
@@ -8,18 +8,18 @@ __metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
name: sumologic
|
||||
type: aggregate
|
||||
type: notification
|
||||
short_description: Sends task result events to Sumologic
|
||||
author: "Ryan Currah (@ryancurrah)"
|
||||
description:
|
||||
- This callback plugin will send task results as JSON formatted events to a Sumologic HTTP collector source
|
||||
- This callback plugin will send task results as JSON formatted events to a Sumologic HTTP collector source.
|
||||
requirements:
|
||||
- Whitelisting this callback plugin
|
||||
- 'Create a HTTP collector source in Sumologic and specify a custom timestamp format of C(yyyy-MM-dd HH:mm:ss ZZZZ) and a custom timestamp locator
|
||||
of C("timestamp": "(.*)")'
|
||||
options:
|
||||
url:
|
||||
description: URL to the Sumologic HTTP collector source
|
||||
description: URL to the Sumologic HTTP collector source.
|
||||
env:
|
||||
- name: SUMOLOGIC_URL
|
||||
ini:
|
||||
@@ -28,7 +28,7 @@ options:
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
examples: >
|
||||
examples: |
|
||||
To enable, add this to your ansible.cfg file in the defaults block
|
||||
[defaults]
|
||||
callback_whitelist = community.general.sumologic
|
||||
@@ -111,7 +111,7 @@ class SumologicHTTPCollectorSource(object):
|
||||
|
||||
class CallbackModule(CallbackBase):
|
||||
CALLBACK_VERSION = 2.0
|
||||
CALLBACK_TYPE = 'aggregate'
|
||||
CALLBACK_TYPE = 'notification'
|
||||
CALLBACK_NAME = 'community.general.sumologic'
|
||||
CALLBACK_NEEDS_WHITELIST = True
|
||||
|
||||
|
||||
@@ -15,11 +15,11 @@ DOCUMENTATION = '''
|
||||
- whitelist in configuration
|
||||
short_description: sends JSON events to syslog
|
||||
description:
|
||||
- This plugin logs ansible-playbook and ansible runs to a syslog server in JSON format
|
||||
- Before Ansible 2.9 only environment variables were available for configuration
|
||||
- This plugin logs ansible-playbook and ansible runs to a syslog server in JSON format.
|
||||
- Before Ansible 2.9 only environment variables were available for configuration.
|
||||
options:
|
||||
server:
|
||||
description: syslog server that will receive the event
|
||||
description: Syslog server that will receive the event.
|
||||
env:
|
||||
- name: SYSLOG_SERVER
|
||||
default: localhost
|
||||
@@ -27,7 +27,7 @@ DOCUMENTATION = '''
|
||||
- section: callback_syslog_json
|
||||
key: syslog_server
|
||||
port:
|
||||
description: port on which the syslog server is listening
|
||||
description: Port on which the syslog server is listening.
|
||||
env:
|
||||
- name: SYSLOG_PORT
|
||||
default: 514
|
||||
@@ -35,7 +35,7 @@ DOCUMENTATION = '''
|
||||
- section: callback_syslog_json
|
||||
key: syslog_port
|
||||
facility:
|
||||
description: syslog facility to log as
|
||||
description: Syslog facility to log as.
|
||||
env:
|
||||
- name: SYSLOG_FACILITY
|
||||
default: user
|
||||
@@ -71,7 +71,7 @@ class CallbackModule(CallbackBase):
|
||||
"""
|
||||
|
||||
CALLBACK_VERSION = 2.0
|
||||
CALLBACK_TYPE = 'aggregate'
|
||||
CALLBACK_TYPE = 'notification'
|
||||
CALLBACK_NAME = 'community.general.syslog_json'
|
||||
CALLBACK_NEEDS_WHITELIST = True
|
||||
|
||||
|
||||
@@ -142,7 +142,7 @@ class CallbackModule(CallbackModule_default):
|
||||
display_color = C.COLOR_CHANGED
|
||||
task_result = self._process_result_output(result, msg)
|
||||
self._display.display(" " + task_result, display_color)
|
||||
elif self.get('display_ok_hosts'):
|
||||
elif self.get_option('display_ok_hosts'):
|
||||
task_result = self._process_result_output(result, msg)
|
||||
self._display.display(" " + task_result, display_color)
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ DOCUMENTATION = '''
|
||||
author: Unknown (!UNKNOWN)
|
||||
name: yaml
|
||||
type: stdout
|
||||
short_description: yaml-ized Ansible screen output
|
||||
short_description: YAML-ized Ansible screen output
|
||||
description:
|
||||
- Ansible output that can be quite a bit easier to read than the
|
||||
default JSON formatting.
|
||||
|
||||
@@ -20,9 +20,13 @@ attributes:
|
||||
description: Will return details on what has changed (or possibly needs changing in C(check_mode)), when in diff mode.
|
||||
'''
|
||||
|
||||
# platform:
|
||||
# description: Target OS/families that can be operated against.
|
||||
# support: N/A
|
||||
PLATFORM = r'''
|
||||
options: {}
|
||||
attributes:
|
||||
platform:
|
||||
description: Target OS/families that can be operated against.
|
||||
support: N/A
|
||||
'''
|
||||
|
||||
# Should be used together with the standard fragment
|
||||
INFO_MODULE = r'''
|
||||
|
||||
@@ -60,7 +60,7 @@ options:
|
||||
sasl_class:
|
||||
description:
|
||||
- The class to use for SASL authentication.
|
||||
- possible choices are C(external), C(gssapi).
|
||||
- Possible choices are C(external), C(gssapi).
|
||||
type: str
|
||||
choices: ['external', 'gssapi']
|
||||
default: external
|
||||
|
||||
@@ -55,6 +55,11 @@ DOCUMENTATION = r'''
|
||||
type: str
|
||||
default: none
|
||||
choices: [ 'STOPPED', 'STARTING', 'RUNNING', 'none' ]
|
||||
project:
|
||||
description: Filter the instance according to the given project.
|
||||
type: str
|
||||
default: default
|
||||
version_added: 6.2.0
|
||||
type_filter:
|
||||
description:
|
||||
- Filter the instances by type C(virtual-machine), C(container) or C(both).
|
||||
@@ -140,6 +145,9 @@ groupby:
|
||||
vlan666:
|
||||
type: vlanid
|
||||
attribute: 666
|
||||
projectInternals:
|
||||
type: project
|
||||
attribute: internals
|
||||
'''
|
||||
|
||||
import binascii
|
||||
@@ -153,6 +161,7 @@ from ansible.module_utils.common.text.converters import to_native, to_text
|
||||
from ansible.module_utils.common.dict_transformations import dict_merge
|
||||
from ansible.module_utils.six import raise_from
|
||||
from ansible.errors import AnsibleError, AnsibleParserError
|
||||
from ansible.module_utils.six.moves.urllib.parse import urlencode
|
||||
from ansible_collections.community.general.plugins.module_utils.lxd import LXDClient, LXDClientException
|
||||
|
||||
try:
|
||||
@@ -330,7 +339,15 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
# "status_code": 200,
|
||||
# "type": "sync"
|
||||
# }
|
||||
instances = self.socket.do('GET', '/1.0/instances')
|
||||
url = '/1.0/instances'
|
||||
if self.project:
|
||||
url = url + '?{0}'.format(urlencode(dict(project=self.project)))
|
||||
|
||||
instances = self.socket.do('GET', url)
|
||||
|
||||
if self.project:
|
||||
return [m.split('/')[3].split('?')[0] for m in instances['metadata']]
|
||||
|
||||
return [m.split('/')[3] for m in instances['metadata']]
|
||||
|
||||
def _get_config(self, branch, name):
|
||||
@@ -351,9 +368,11 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
dict(config): Config of the instance"""
|
||||
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])))}
|
||||
config[name] = {branch[1]: self.socket.do(
|
||||
'GET', '/1.0/{0}/{1}/{2}?{3}'.format(to_native(branch[0]), to_native(name), to_native(branch[1]), urlencode(dict(project=self.project))))}
|
||||
else:
|
||||
config[name] = {branch: self.socket.do('GET', '/1.0/{0}/{1}'.format(to_native(branch), to_native(name)))}
|
||||
config[name] = {branch: self.socket.do(
|
||||
'GET', '/1.0/{0}/{1}?{2}'.format(to_native(branch), to_native(name), urlencode(dict(project=self.project))))}
|
||||
return config
|
||||
|
||||
def get_instance_data(self, names):
|
||||
@@ -583,6 +602,8 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
self._set_data_entry(instance_name, 'network_interfaces', self.extract_network_information_from_instance_config(instance_name))
|
||||
self._set_data_entry(instance_name, 'preferred_interface', self.get_prefered_instance_network_interface(instance_name))
|
||||
self._set_data_entry(instance_name, 'vlan_ids', self.get_instance_vlans(instance_name))
|
||||
self._set_data_entry(instance_name, 'project', self._get_data_entry(
|
||||
'instances/{0}/instances/metadata/project'.format(instance_name)))
|
||||
|
||||
def build_inventory_network(self, instance_name):
|
||||
"""Add the network interfaces of the instance to the inventory
|
||||
@@ -686,6 +707,8 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
# add VLAN_ID information
|
||||
if self._get_data_entry('inventory/{0}/vlan_ids'.format(instance_name)):
|
||||
self.inventory.set_variable(instance_name, 'ansible_lxd_vlan_ids', self._get_data_entry('inventory/{0}/vlan_ids'.format(instance_name)))
|
||||
# add project
|
||||
self.inventory.set_variable(instance_name, 'ansible_lxd_project', self._get_data_entry('inventory/{0}/project'.format(instance_name)))
|
||||
|
||||
def build_inventory_groups_location(self, group_name):
|
||||
"""create group by attribute: location
|
||||
@@ -761,6 +784,28 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
# Ignore invalid IP addresses returned by lxd
|
||||
pass
|
||||
|
||||
def build_inventory_groups_project(self, group_name):
|
||||
"""create group by attribute: project
|
||||
|
||||
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_instances = [
|
||||
instance_name for instance_name in self.inventory.hosts
|
||||
if 'ansible_lxd_project' in self.inventory.get_host(instance_name).get_vars()]
|
||||
for instance_name in gen_instances:
|
||||
if self.groupby[group_name].get('attribute').lower() == self.inventory.get_host(instance_name).get_vars().get('ansible_lxd_project'):
|
||||
self.inventory.add_child(group_name, instance_name)
|
||||
|
||||
def build_inventory_groups_os(self, group_name):
|
||||
"""create group by attribute: os
|
||||
|
||||
@@ -899,6 +944,7 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
* 'profile'
|
||||
* 'vlanid'
|
||||
* 'type'
|
||||
* 'project'
|
||||
|
||||
Args:
|
||||
str(group_name): Group name
|
||||
@@ -926,6 +972,8 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
self.build_inventory_groups_vlanid(group_name)
|
||||
elif self.groupby[group_name].get('type') == 'type':
|
||||
self.build_inventory_groups_type(group_name)
|
||||
elif self.groupby[group_name].get('type') == 'project':
|
||||
self.build_inventory_groups_project(group_name)
|
||||
else:
|
||||
raise AnsibleParserError('Unknown group type: {0}'.format(to_native(group_name)))
|
||||
|
||||
@@ -1032,6 +1080,7 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
try:
|
||||
self.client_key = self.get_option('client_key')
|
||||
self.client_cert = self.get_option('client_cert')
|
||||
self.project = self.get_option('project')
|
||||
self.debug = self.DEBUG
|
||||
self.data = {} # store for inventory-data
|
||||
self.groupby = self.get_option('groupby')
|
||||
|
||||
@@ -28,8 +28,12 @@ DOCUMENTATION = """
|
||||
default: name
|
||||
version_added: 5.7.0
|
||||
field:
|
||||
description: Field to fetch; leave unset to fetch whole response.
|
||||
description: Field to fetch. Leave unset to fetch whole response.
|
||||
type: str
|
||||
collection_id:
|
||||
description: Collection ID to filter results by collection. Leave unset to skip filtering.
|
||||
type: str
|
||||
version_added: 6.3.0
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
@@ -43,10 +47,20 @@ EXAMPLES = """
|
||||
msg: >-
|
||||
{{ lookup('community.general.bitwarden', 'bafba515-af11-47e6-abe3-af1200cd18b2', search='id', field='password') }}
|
||||
|
||||
- name: "Get 'password' from Bitwarden record named 'a_test' from collection"
|
||||
ansible.builtin.debug:
|
||||
msg: >-
|
||||
{{ lookup('community.general.bitwarden', 'a_test', field='password', collection_id='bafba515-af11-47e6-abe3-af1200cd18b2') }}
|
||||
|
||||
- name: "Get full Bitwarden record named 'a_test'"
|
||||
ansible.builtin.debug:
|
||||
msg: >-
|
||||
{{ lookup('community.general.bitwarden', 'a_test') }}
|
||||
|
||||
- name: "Get custom field 'api_key' from Bitwarden record named 'a_test'"
|
||||
ansible.builtin.debug:
|
||||
msg: >-
|
||||
{{ lookup('community.general.bitwarden', 'a_test', field='api_key') }}
|
||||
"""
|
||||
|
||||
RETURN = """
|
||||
@@ -78,7 +92,7 @@ class Bitwarden(object):
|
||||
return self._cli_path
|
||||
|
||||
@property
|
||||
def logged_in(self):
|
||||
def unlocked(self):
|
||||
out, err = self._run(['status'], stdin="")
|
||||
decoded = AnsibleJSONDecoder().raw_decode(out)[0]
|
||||
return decoded['status'] == 'unlocked'
|
||||
@@ -91,10 +105,17 @@ class Bitwarden(object):
|
||||
raise BitwardenException(err)
|
||||
return to_text(out, errors='surrogate_or_strict'), to_text(err, errors='surrogate_or_strict')
|
||||
|
||||
def _get_matches(self, search_value, search_field):
|
||||
def _get_matches(self, search_value, search_field, collection_id):
|
||||
"""Return matching records whose search_field is equal to key.
|
||||
"""
|
||||
out, err = self._run(['list', 'items', '--search', search_value])
|
||||
|
||||
# Prepare set of params for Bitwarden CLI
|
||||
params = ['list', 'items', '--search', search_value]
|
||||
|
||||
if collection_id:
|
||||
params.extend(['--collectionid', collection_id])
|
||||
|
||||
out, err = self._run(params)
|
||||
|
||||
# This includes things that matched in different fields.
|
||||
initial_matches = AnsibleJSONDecoder().raw_decode(out)[0]
|
||||
@@ -102,17 +123,27 @@ class Bitwarden(object):
|
||||
# Filter to only include results from the right field.
|
||||
return [item for item in initial_matches if item[search_field] == search_value]
|
||||
|
||||
def get_field(self, field, search_value, search_field="name"):
|
||||
"""Return a list of the specified field for records whose search_field match search_value.
|
||||
def get_field(self, field, search_value, search_field="name", collection_id=None):
|
||||
"""Return a list of the specified field for records whose search_field match search_value
|
||||
and filtered by collection if collection has been provided.
|
||||
|
||||
If field is None, return the whole record for each match.
|
||||
"""
|
||||
matches = self._get_matches(search_value, search_field)
|
||||
matches = self._get_matches(search_value, search_field, collection_id)
|
||||
|
||||
if field:
|
||||
if field in ['autofillOnPageLoad', 'password', 'passwordRevisionDate', 'totp', 'uris', 'username']:
|
||||
return [match['login'][field] for match in matches]
|
||||
|
||||
return matches
|
||||
elif not field:
|
||||
return matches
|
||||
else:
|
||||
custom_field_matches = []
|
||||
for match in matches:
|
||||
for custom_field in match['fields']:
|
||||
if custom_field['name'] == field:
|
||||
custom_field_matches.append(custom_field['value'])
|
||||
if matches and not custom_field_matches:
|
||||
raise AnsibleError("Custom field {field} does not exist in {search_value}".format(field=field, search_value=search_value))
|
||||
return custom_field_matches
|
||||
|
||||
|
||||
class LookupModule(LookupBase):
|
||||
@@ -121,10 +152,11 @@ class LookupModule(LookupBase):
|
||||
self.set_options(var_options=variables, direct=kwargs)
|
||||
field = self.get_option('field')
|
||||
search_field = self.get_option('search')
|
||||
if not _bitwarden.logged_in:
|
||||
raise AnsibleError("Not logged into Bitwarden. Run 'bw login'.")
|
||||
collection_id = self.get_option('collection_id')
|
||||
if not _bitwarden.unlocked:
|
||||
raise AnsibleError("Bitwarden Vault locked. Run 'bw unlock'.")
|
||||
|
||||
return [_bitwarden.get_field(field, term, search_field) for term in terms]
|
||||
return [_bitwarden.get_field(field, term, search_field, collection_id) for term in terms]
|
||||
|
||||
|
||||
_bitwarden = Bitwarden()
|
||||
|
||||
@@ -35,9 +35,10 @@ DOCUMENTATION = '''
|
||||
description:
|
||||
- Record type to query.
|
||||
- C(DLV) has been removed in community.general 6.0.0.
|
||||
- C(CAA) has been added in community.general 6.3.0.
|
||||
type: str
|
||||
default: 'A'
|
||||
choices: [A, ALL, AAAA, CNAME, DNAME, DNSKEY, DS, HINFO, LOC, MX, NAPTR, NS, NSEC3PARAM, PTR, RP, RRSIG, SOA, SPF, SRV, SSHFP, TLSA, TXT]
|
||||
choices: [A, ALL, AAAA, CAA, CNAME, DNAME, DNSKEY, DS, HINFO, LOC, MX, NAPTR, NS, NSEC3PARAM, PTR, RP, RRSIG, SOA, SPF, SRV, SSHFP, TLSA, TXT]
|
||||
flat:
|
||||
description: If 0 each record is returned as a dictionary, otherwise a string.
|
||||
type: int
|
||||
@@ -129,6 +130,12 @@ RETURN = """
|
||||
AAAA:
|
||||
description:
|
||||
- address
|
||||
CAA:
|
||||
description:
|
||||
- flags
|
||||
- tag
|
||||
- value
|
||||
version_added: 6.3.0
|
||||
CNAME:
|
||||
description:
|
||||
- target
|
||||
@@ -198,7 +205,7 @@ try:
|
||||
import dns.resolver
|
||||
import dns.reversename
|
||||
import dns.rdataclass
|
||||
from dns.rdatatype import (A, AAAA, CNAME, DNAME, DNSKEY, DS, HINFO, LOC,
|
||||
from dns.rdatatype import (A, AAAA, CAA, CNAME, DNAME, DNSKEY, DS, HINFO, LOC,
|
||||
MX, NAPTR, NS, NSEC3PARAM, PTR, RP, SOA, SPF, SRV, SSHFP, TLSA, TXT)
|
||||
HAVE_DNS = True
|
||||
except ImportError:
|
||||
@@ -218,6 +225,7 @@ def make_rdata_dict(rdata):
|
||||
supported_types = {
|
||||
A: ['address'],
|
||||
AAAA: ['address'],
|
||||
CAA: ['flags', 'tag', 'value'],
|
||||
CNAME: ['target'],
|
||||
DNAME: ['target'],
|
||||
DNSKEY: ['flags', 'algorithm', 'protocol', 'key'],
|
||||
@@ -230,7 +238,7 @@ def make_rdata_dict(rdata):
|
||||
NSEC3PARAM: ['algorithm', 'flags', 'iterations', 'salt'],
|
||||
PTR: ['target'],
|
||||
RP: ['mbox', 'txt'],
|
||||
# RRSIG: ['algorithm', 'labels', 'original_ttl', 'expiration', 'inception', 'signature'],
|
||||
# RRSIG: ['type_covered', 'algorithm', 'labels', 'original_ttl', 'expiration', 'inception', 'key_tag', 'signer', 'signature'],
|
||||
SOA: ['mname', 'rname', 'serial', 'refresh', 'retry', 'expire', 'minimum'],
|
||||
SPF: ['strings'],
|
||||
SRV: ['priority', 'weight', 'port', 'target'],
|
||||
@@ -251,6 +259,8 @@ def make_rdata_dict(rdata):
|
||||
|
||||
if rdata.rdtype == DS and f == 'digest':
|
||||
val = dns.rdata._hexify(rdata.digest).replace(' ', '')
|
||||
if rdata.rdtype == DNSKEY and f == 'algorithm':
|
||||
val = int(val)
|
||||
if rdata.rdtype == DNSKEY and f == 'key':
|
||||
val = dns.rdata._base64ify(rdata.key).replace(' ', '')
|
||||
if rdata.rdtype == NSEC3PARAM and f == 'salt':
|
||||
|
||||
@@ -110,3 +110,14 @@ def gitlab_authentication(module):
|
||||
GitLab remove Session API now that private tokens are removed from user API endpoints since version 10.2." % to_native(e))
|
||||
|
||||
return gitlab_instance
|
||||
|
||||
|
||||
def filter_returned_variables(gitlab_variables):
|
||||
# pop properties we don't know
|
||||
existing_variables = [dict(x.attributes) for x in gitlab_variables]
|
||||
KNOWN = ['key', 'value', 'masked', 'protected', 'variable_type', 'environment_scope']
|
||||
for item in existing_variables:
|
||||
for key in list(item.keys()):
|
||||
if key not in KNOWN:
|
||||
item.pop(key)
|
||||
return existing_variables
|
||||
|
||||
@@ -85,17 +85,16 @@ class iLORedfishUtils(RedfishUtils):
|
||||
|
||||
datetime_uri = self.manager_uri + "DateTime"
|
||||
|
||||
response = self.get_request(self.root_uri + datetime_uri)
|
||||
if not response['ret']:
|
||||
return response
|
||||
listofips = mgr_attributes['mgr_attr_value'].split(" ")
|
||||
if len(listofips) > 2:
|
||||
return {'ret': False, 'changed': False, 'msg': "More than 2 NTP Servers mentioned"}
|
||||
|
||||
data = response['data']
|
||||
ntp_list = []
|
||||
for ips in listofips:
|
||||
ntp_list.append(ips)
|
||||
|
||||
ntp_list = data[setkey]
|
||||
if len(ntp_list) == 2:
|
||||
ntp_list.pop(0)
|
||||
|
||||
ntp_list.append(mgr_attributes['mgr_attr_value'])
|
||||
while len(ntp_list) < 2:
|
||||
ntp_list.append("0.0.0.0")
|
||||
|
||||
payload = {setkey: ntp_list}
|
||||
|
||||
@@ -137,18 +136,16 @@ class iLORedfishUtils(RedfishUtils):
|
||||
nic_info = self.get_manager_ethernet_uri()
|
||||
uri = nic_info["nic_addr"]
|
||||
|
||||
response = self.get_request(self.root_uri + uri)
|
||||
if not response['ret']:
|
||||
return response
|
||||
listofips = attr['mgr_attr_value'].split(" ")
|
||||
if len(listofips) > 3:
|
||||
return {'ret': False, 'changed': False, 'msg': "More than 3 DNS Servers mentioned"}
|
||||
|
||||
data = response['data']
|
||||
dns_list = []
|
||||
for ips in listofips:
|
||||
dns_list.append(ips)
|
||||
|
||||
dns_list = data["Oem"]["Hpe"]["IPv4"][key]
|
||||
|
||||
if len(dns_list) == 3:
|
||||
dns_list.pop(0)
|
||||
|
||||
dns_list.append(attr['mgr_attr_value'])
|
||||
while len(dns_list) < 3:
|
||||
dns_list.append("0.0.0.0")
|
||||
|
||||
payload = {
|
||||
"Oem": {
|
||||
|
||||
@@ -37,8 +37,17 @@ def cause_changes(on_success=None, on_failure=None):
|
||||
|
||||
|
||||
def module_fails_on_exception(func):
|
||||
conflict_list = ('msg', 'exception', 'output', 'vars', 'changed')
|
||||
|
||||
@wraps(func)
|
||||
def wrapper(self, *args, **kwargs):
|
||||
def fix_var_conflicts(output):
|
||||
result = dict([
|
||||
(k if k not in conflict_list else "_" + k, v)
|
||||
for k, v in output.items()
|
||||
])
|
||||
return result
|
||||
|
||||
try:
|
||||
func(self, *args, **kwargs)
|
||||
except SystemExit:
|
||||
@@ -46,12 +55,16 @@ def module_fails_on_exception(func):
|
||||
except ModuleHelperException as e:
|
||||
if e.update_output:
|
||||
self.update_output(e.update_output)
|
||||
# patchy solution to resolve conflict with output variables
|
||||
output = fix_var_conflicts(self.output)
|
||||
self.module.fail_json(msg=e.msg, exception=traceback.format_exc(),
|
||||
output=self.output, vars=self.vars.output(), **self.output)
|
||||
output=self.output, vars=self.vars.output(), **output)
|
||||
except Exception as e:
|
||||
# patchy solution to resolve conflict with output variables
|
||||
output = fix_var_conflicts(self.output)
|
||||
msg = "Module failed with exception: {0}".format(str(e).strip())
|
||||
self.module.fail_json(msg=msg, exception=traceback.format_exc(),
|
||||
output=self.output, vars=self.vars.output(), **self.output)
|
||||
output=self.output, vars=self.vars.output(), **output)
|
||||
return wrapper
|
||||
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ from ansible_collections.community.general.plugins.module_utils.mh.mixins.deprec
|
||||
|
||||
|
||||
class ModuleHelper(DeprecateAttrsMixin, VarsMixin, DependencyMixin, ModuleHelperBase):
|
||||
_output_conflict_list = ('msg', 'exception', 'output', 'vars', 'changed')
|
||||
facts_name = None
|
||||
output_params = ()
|
||||
diff_params = ()
|
||||
@@ -60,10 +59,6 @@ class ModuleHelper(DeprecateAttrsMixin, VarsMixin, DependencyMixin, ModuleHelper
|
||||
vars_diff = self.vars.diff() or {}
|
||||
result['diff'] = dict_merge(dict(diff), vars_diff)
|
||||
|
||||
for varname in result:
|
||||
if varname in self._output_conflict_list:
|
||||
result["_" + varname] = result[varname]
|
||||
del result[varname]
|
||||
return result
|
||||
|
||||
|
||||
|
||||
502
plugins/module_utils/ocapi_utils.py
Normal file
502
plugins/module_utils/ocapi_utils.py
Normal file
@@ -0,0 +1,502 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2022 Western Digital Corporation
|
||||
# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
import json
|
||||
import os
|
||||
import uuid
|
||||
|
||||
from ansible.module_utils.urls import open_url
|
||||
from ansible.module_utils.common.text.converters import to_native
|
||||
from ansible.module_utils.common.text.converters import to_text
|
||||
from ansible.module_utils.six.moves.urllib.error import URLError, HTTPError
|
||||
from ansible.module_utils.six.moves.urllib.parse import urlparse
|
||||
|
||||
|
||||
GET_HEADERS = {'accept': 'application/json'}
|
||||
PUT_HEADERS = {'content-type': 'application/json', 'accept': 'application/json'}
|
||||
POST_HEADERS = {'content-type': 'application/json', 'accept': 'application/json'}
|
||||
DELETE_HEADERS = {'accept': 'application/json'}
|
||||
|
||||
HEALTH_OK = 5
|
||||
|
||||
|
||||
class OcapiUtils(object):
|
||||
|
||||
def __init__(self, creds, base_uri, proxy_slot_number, timeout, module):
|
||||
self.root_uri = base_uri
|
||||
self.proxy_slot_number = proxy_slot_number
|
||||
self.creds = creds
|
||||
self.timeout = timeout
|
||||
self.module = module
|
||||
|
||||
def _auth_params(self):
|
||||
"""
|
||||
Return tuple of required authentication params based on the username and password.
|
||||
|
||||
:return: tuple of username, password
|
||||
"""
|
||||
username = self.creds['user']
|
||||
password = self.creds['pswd']
|
||||
force_basic_auth = True
|
||||
return username, password, force_basic_auth
|
||||
|
||||
def get_request(self, uri):
|
||||
req_headers = dict(GET_HEADERS)
|
||||
username, password, basic_auth = self._auth_params()
|
||||
try:
|
||||
resp = open_url(uri, method="GET", headers=req_headers,
|
||||
url_username=username, url_password=password,
|
||||
force_basic_auth=basic_auth, validate_certs=False,
|
||||
follow_redirects='all',
|
||||
use_proxy=True, timeout=self.timeout)
|
||||
data = json.loads(to_native(resp.read()))
|
||||
headers = dict((k.lower(), v) for (k, v) in resp.info().items())
|
||||
except HTTPError as e:
|
||||
return {'ret': False,
|
||||
'msg': "HTTP Error %s on GET request to '%s'"
|
||||
% (e.code, uri),
|
||||
'status': e.code}
|
||||
except URLError as e:
|
||||
return {'ret': False, 'msg': "URL Error on GET request to '%s': '%s'"
|
||||
% (uri, e.reason)}
|
||||
# Almost all errors should be caught above, but just in case
|
||||
except Exception as e:
|
||||
return {'ret': False,
|
||||
'msg': "Failed GET request to '%s': '%s'" % (uri, to_text(e))}
|
||||
return {'ret': True, 'data': data, 'headers': headers}
|
||||
|
||||
def delete_request(self, uri, etag=None):
|
||||
req_headers = dict(DELETE_HEADERS)
|
||||
if etag is not None:
|
||||
req_headers['If-Match'] = etag
|
||||
username, password, basic_auth = self._auth_params()
|
||||
try:
|
||||
resp = open_url(uri, method="DELETE", headers=req_headers,
|
||||
url_username=username, url_password=password,
|
||||
force_basic_auth=basic_auth, validate_certs=False,
|
||||
follow_redirects='all',
|
||||
use_proxy=True, timeout=self.timeout)
|
||||
if resp.status != 204:
|
||||
data = json.loads(to_native(resp.read()))
|
||||
else:
|
||||
data = ""
|
||||
headers = dict((k.lower(), v) for (k, v) in resp.info().items())
|
||||
except HTTPError as e:
|
||||
return {'ret': False,
|
||||
'msg': "HTTP Error %s on DELETE request to '%s'"
|
||||
% (e.code, uri),
|
||||
'status': e.code}
|
||||
except URLError as e:
|
||||
return {'ret': False, 'msg': "URL Error on DELETE request to '%s': '%s'"
|
||||
% (uri, e.reason)}
|
||||
# Almost all errors should be caught above, but just in case
|
||||
except Exception as e:
|
||||
return {'ret': False,
|
||||
'msg': "Failed DELETE request to '%s': '%s'" % (uri, to_text(e))}
|
||||
return {'ret': True, 'data': data, 'headers': headers}
|
||||
|
||||
def put_request(self, uri, payload, etag=None):
|
||||
req_headers = dict(PUT_HEADERS)
|
||||
if etag is not None:
|
||||
req_headers['If-Match'] = etag
|
||||
username, password, basic_auth = self._auth_params()
|
||||
try:
|
||||
resp = open_url(uri, data=json.dumps(payload),
|
||||
headers=req_headers, method="PUT",
|
||||
url_username=username, url_password=password,
|
||||
force_basic_auth=basic_auth, validate_certs=False,
|
||||
follow_redirects='all',
|
||||
use_proxy=True, timeout=self.timeout)
|
||||
headers = dict((k.lower(), v) for (k, v) in resp.info().items())
|
||||
except HTTPError as e:
|
||||
return {'ret': False,
|
||||
'msg': "HTTP Error %s on PUT request to '%s'"
|
||||
% (e.code, uri),
|
||||
'status': e.code}
|
||||
except URLError as e:
|
||||
return {'ret': False, 'msg': "URL Error on PUT request to '%s': '%s'"
|
||||
% (uri, e.reason)}
|
||||
# Almost all errors should be caught above, but just in case
|
||||
except Exception as e:
|
||||
return {'ret': False,
|
||||
'msg': "Failed PUT request to '%s': '%s'" % (uri, to_text(e))}
|
||||
return {'ret': True, 'headers': headers, 'resp': resp}
|
||||
|
||||
def post_request(self, uri, payload, content_type="application/json", timeout=None):
|
||||
req_headers = dict(POST_HEADERS)
|
||||
if content_type != "application/json":
|
||||
req_headers["content-type"] = content_type
|
||||
username, password, basic_auth = self._auth_params()
|
||||
if content_type == "application/json":
|
||||
request_data = json.dumps(payload)
|
||||
else:
|
||||
request_data = payload
|
||||
try:
|
||||
resp = open_url(uri, data=request_data,
|
||||
headers=req_headers, method="POST",
|
||||
url_username=username, url_password=password,
|
||||
force_basic_auth=basic_auth, validate_certs=False,
|
||||
follow_redirects='all',
|
||||
use_proxy=True, timeout=self.timeout if timeout is None else timeout)
|
||||
headers = dict((k.lower(), v) for (k, v) in resp.info().items())
|
||||
except HTTPError as e:
|
||||
return {'ret': False,
|
||||
'msg': "HTTP Error %s on POST request to '%s'"
|
||||
% (e.code, uri),
|
||||
'status': e.code}
|
||||
except URLError as e:
|
||||
return {'ret': False, 'msg': "URL Error on POST request to '%s': '%s'"
|
||||
% (uri, e.reason)}
|
||||
# Almost all errors should be caught above, but just in case
|
||||
except Exception as e:
|
||||
return {'ret': False,
|
||||
'msg': "Failed POST request to '%s': '%s'" % (uri, to_text(e))}
|
||||
return {'ret': True, 'headers': headers, 'resp': resp}
|
||||
|
||||
def get_uri_with_slot_number_query_param(self, uri):
|
||||
"""Return the URI with proxy slot number added as a query param, if there is one.
|
||||
|
||||
If a proxy slot number is provided, to access it, we must append it as a query parameter.
|
||||
This method returns the given URI with the slotnumber query param added, if there is one.
|
||||
If there is not a proxy slot number, it just returns the URI as it was passed in.
|
||||
"""
|
||||
if self.proxy_slot_number is not None:
|
||||
parsed_url = urlparse(uri)
|
||||
return parsed_url._replace(query="slotnumber=" + str(self.proxy_slot_number)).geturl()
|
||||
else:
|
||||
return uri
|
||||
|
||||
def manage_system_power(self, command):
|
||||
"""Process a command to manage the system power.
|
||||
|
||||
:param str command: The Ansible command being processed.
|
||||
"""
|
||||
if command == "PowerGracefulRestart":
|
||||
resource_uri = self.root_uri
|
||||
resource_uri = self.get_uri_with_slot_number_query_param(resource_uri)
|
||||
|
||||
# Get the resource so that we have the Etag
|
||||
response = self.get_request(resource_uri)
|
||||
if 'etag' not in response['headers']:
|
||||
return {'ret': False, 'msg': 'Etag not found in response.'}
|
||||
etag = response['headers']['etag']
|
||||
if response['ret'] is False:
|
||||
return response
|
||||
|
||||
# Issue the PUT to do the reboot (unless we are in check mode)
|
||||
if self.module.check_mode:
|
||||
return {
|
||||
'ret': True,
|
||||
'changed': True,
|
||||
'msg': 'Update not performed in check mode.'
|
||||
}
|
||||
payload = {'Reboot': True}
|
||||
response = self.put_request(resource_uri, payload, etag)
|
||||
if response['ret'] is False:
|
||||
return response
|
||||
elif command.startswith("PowerMode"):
|
||||
return self.manage_power_mode(command)
|
||||
else:
|
||||
return {'ret': False, 'msg': 'Invalid command: ' + command}
|
||||
|
||||
return {'ret': True}
|
||||
|
||||
def manage_chassis_indicator_led(self, command):
|
||||
"""Process a command to manage the chassis indicator LED.
|
||||
|
||||
:param string command: The Ansible command being processed.
|
||||
"""
|
||||
return self.manage_indicator_led(command, self.root_uri)
|
||||
|
||||
def manage_indicator_led(self, command, resource_uri=None):
|
||||
"""Process a command to manage an indicator LED.
|
||||
|
||||
:param string command: The Ansible command being processed.
|
||||
:param string resource_uri: URI of the resource whose indicator LED is being managed.
|
||||
"""
|
||||
key = "IndicatorLED"
|
||||
if resource_uri is None:
|
||||
resource_uri = self.root_uri
|
||||
resource_uri = self.get_uri_with_slot_number_query_param(resource_uri)
|
||||
|
||||
payloads = {
|
||||
'IndicatorLedOn': {
|
||||
'ID': 2
|
||||
},
|
||||
'IndicatorLedOff': {
|
||||
'ID': 4
|
||||
}
|
||||
}
|
||||
|
||||
response = self.get_request(resource_uri)
|
||||
if 'etag' not in response['headers']:
|
||||
return {'ret': False, 'msg': 'Etag not found in response.'}
|
||||
etag = response['headers']['etag']
|
||||
if response['ret'] is False:
|
||||
return response
|
||||
data = response['data']
|
||||
if key not in data:
|
||||
return {'ret': False, 'msg': "Key %s not found" % key}
|
||||
if 'ID' not in data[key]:
|
||||
return {'ret': False, 'msg': 'IndicatorLED for resource has no ID.'}
|
||||
|
||||
if command in payloads.keys():
|
||||
# See if the LED is already set as requested.
|
||||
current_led_status = data[key]['ID']
|
||||
if current_led_status == payloads[command]['ID']:
|
||||
return {'ret': True, 'changed': False}
|
||||
|
||||
# Set the LED (unless we are in check mode)
|
||||
if self.module.check_mode:
|
||||
return {
|
||||
'ret': True,
|
||||
'changed': True,
|
||||
'msg': 'Update not performed in check mode.'
|
||||
}
|
||||
payload = {'IndicatorLED': payloads[command]}
|
||||
response = self.put_request(resource_uri, payload, etag)
|
||||
if response['ret'] is False:
|
||||
return response
|
||||
else:
|
||||
return {'ret': False, 'msg': 'Invalid command'}
|
||||
|
||||
return {'ret': True}
|
||||
|
||||
def manage_power_mode(self, command):
|
||||
key = "PowerState"
|
||||
resource_uri = self.get_uri_with_slot_number_query_param(self.root_uri)
|
||||
|
||||
payloads = {
|
||||
"PowerModeNormal": 2,
|
||||
"PowerModeLow": 4
|
||||
}
|
||||
|
||||
response = self.get_request(resource_uri)
|
||||
if 'etag' not in response['headers']:
|
||||
return {'ret': False, 'msg': 'Etag not found in response.'}
|
||||
etag = response['headers']['etag']
|
||||
if response['ret'] is False:
|
||||
return response
|
||||
data = response['data']
|
||||
if key not in data:
|
||||
return {'ret': False, 'msg': "Key %s not found" % key}
|
||||
if 'ID' not in data[key]:
|
||||
return {'ret': False, 'msg': 'PowerState for resource has no ID.'}
|
||||
|
||||
if command in payloads.keys():
|
||||
# See if the PowerState is already set as requested.
|
||||
current_power_state = data[key]['ID']
|
||||
if current_power_state == payloads[command]:
|
||||
return {'ret': True, 'changed': False}
|
||||
|
||||
# Set the Power State (unless we are in check mode)
|
||||
if self.module.check_mode:
|
||||
return {
|
||||
'ret': True,
|
||||
'changed': True,
|
||||
'msg': 'Update not performed in check mode.'
|
||||
}
|
||||
payload = {'PowerState': {"ID": payloads[command]}}
|
||||
response = self.put_request(resource_uri, payload, etag)
|
||||
if response['ret'] is False:
|
||||
return response
|
||||
else:
|
||||
return {'ret': False, 'msg': 'Invalid command: ' + command}
|
||||
|
||||
return {'ret': True}
|
||||
|
||||
def prepare_multipart_firmware_upload(self, filename):
|
||||
"""Prepare a multipart/form-data body for OCAPI firmware upload.
|
||||
|
||||
:arg filename: The name of the file to upload.
|
||||
:returns: tuple of (content_type, body) where ``content_type`` is
|
||||
the ``multipart/form-data`` ``Content-Type`` header including
|
||||
``boundary`` and ``body`` is the prepared bytestring body
|
||||
|
||||
Prepares the body to include "FirmwareFile" field with the contents of the file.
|
||||
Because some OCAPI targets do not support Base-64 encoding for multipart/form-data,
|
||||
this method sends the file as binary.
|
||||
"""
|
||||
boundary = str(uuid.uuid4()) # Generate a random boundary
|
||||
body = "--" + boundary + '\r\n'
|
||||
body += 'Content-Disposition: form-data; name="FirmwareFile"; filename="%s"\r\n' % to_native(os.path.basename(filename))
|
||||
body += 'Content-Type: application/octet-stream\r\n\r\n'
|
||||
body_bytes = bytearray(body, 'utf-8')
|
||||
with open(filename, 'rb') as f:
|
||||
body_bytes += f.read()
|
||||
body_bytes += bytearray("\r\n--%s--" % boundary, 'utf-8')
|
||||
return ("multipart/form-data; boundary=%s" % boundary,
|
||||
body_bytes)
|
||||
|
||||
def upload_firmware_image(self, update_image_path):
|
||||
"""Perform Firmware Upload to the OCAPI storage device.
|
||||
|
||||
:param str update_image_path: The path/filename of the firmware image, on the local filesystem.
|
||||
"""
|
||||
if not (os.path.exists(update_image_path) and os.path.isfile(update_image_path)):
|
||||
return {'ret': False, 'msg': 'File does not exist.'}
|
||||
url = self.root_uri + "OperatingSystem"
|
||||
url = self.get_uri_with_slot_number_query_param(url)
|
||||
content_type, b_form_data = self.prepare_multipart_firmware_upload(update_image_path)
|
||||
|
||||
# Post the firmware (unless we are in check mode)
|
||||
if self.module.check_mode:
|
||||
return {
|
||||
'ret': True,
|
||||
'changed': True,
|
||||
'msg': 'Update not performed in check mode.'
|
||||
}
|
||||
result = self.post_request(url, b_form_data, content_type=content_type, timeout=300)
|
||||
if result['ret'] is False:
|
||||
return result
|
||||
return {'ret': True}
|
||||
|
||||
def update_firmware_image(self):
|
||||
"""Perform a Firmware Update on the OCAPI storage device."""
|
||||
resource_uri = self.root_uri
|
||||
resource_uri = self.get_uri_with_slot_number_query_param(resource_uri)
|
||||
# We have to do a GET to obtain the Etag. It's required on the PUT.
|
||||
response = self.get_request(resource_uri)
|
||||
if response['ret'] is False:
|
||||
return response
|
||||
if 'etag' not in response['headers']:
|
||||
return {'ret': False, 'msg': 'Etag not found in response.'}
|
||||
etag = response['headers']['etag']
|
||||
|
||||
# Issue the PUT (unless we are in check mode)
|
||||
if self.module.check_mode:
|
||||
return {
|
||||
'ret': True,
|
||||
'changed': True,
|
||||
'msg': 'Update not performed in check mode.'
|
||||
}
|
||||
payload = {'FirmwareUpdate': True}
|
||||
response = self.put_request(resource_uri, payload, etag)
|
||||
if response['ret'] is False:
|
||||
return response
|
||||
|
||||
return {'ret': True, 'jobUri': response["headers"]["location"]}
|
||||
|
||||
def activate_firmware_image(self):
|
||||
"""Perform a Firmware Activate on the OCAPI storage device."""
|
||||
resource_uri = self.root_uri
|
||||
resource_uri = self.get_uri_with_slot_number_query_param(resource_uri)
|
||||
# We have to do a GET to obtain the Etag. It's required on the PUT.
|
||||
response = self.get_request(resource_uri)
|
||||
if 'etag' not in response['headers']:
|
||||
return {'ret': False, 'msg': 'Etag not found in response.'}
|
||||
etag = response['headers']['etag']
|
||||
if response['ret'] is False:
|
||||
return response
|
||||
|
||||
# Issue the PUT (unless we are in check mode)
|
||||
if self.module.check_mode:
|
||||
return {
|
||||
'ret': True,
|
||||
'changed': True,
|
||||
'msg': 'Update not performed in check mode.'
|
||||
}
|
||||
payload = {'FirmwareActivate': True}
|
||||
response = self.put_request(resource_uri, payload, etag)
|
||||
if response['ret'] is False:
|
||||
return response
|
||||
|
||||
return {'ret': True, 'jobUri': response["headers"]["location"]}
|
||||
|
||||
def get_job_status(self, job_uri):
|
||||
"""Get the status of a job.
|
||||
|
||||
:param str job_uri: The URI of the job's status monitor.
|
||||
"""
|
||||
job_uri = self.get_uri_with_slot_number_query_param(job_uri)
|
||||
response = self.get_request(job_uri)
|
||||
if response['ret'] is False:
|
||||
if response.get('status') == 404:
|
||||
# Job not found -- assume 0%
|
||||
return {
|
||||
"ret": True,
|
||||
"percentComplete": 0,
|
||||
"operationStatus": "Not Available",
|
||||
"operationStatusId": 1,
|
||||
"operationHealth": None,
|
||||
"operationHealthId": None,
|
||||
"details": "Job does not exist.",
|
||||
"jobExists": False
|
||||
}
|
||||
else:
|
||||
return response
|
||||
details = response["data"]["Status"].get("Details")
|
||||
if type(details) is str:
|
||||
details = [details]
|
||||
health_list = response["data"]["Status"]["Health"]
|
||||
return_value = {
|
||||
"ret": True,
|
||||
"percentComplete": response["data"]["PercentComplete"],
|
||||
"operationStatus": response["data"]["Status"]["State"]["Name"],
|
||||
"operationStatusId": response["data"]["Status"]["State"]["ID"],
|
||||
"operationHealth": health_list[0]["Name"] if len(health_list) > 0 else None,
|
||||
"operationHealthId": health_list[0]["ID"] if len(health_list) > 0 else None,
|
||||
"details": details,
|
||||
"jobExists": True
|
||||
}
|
||||
return return_value
|
||||
|
||||
def delete_job(self, job_uri):
|
||||
"""Delete the OCAPI job referenced by the specified job_uri."""
|
||||
job_uri = self.get_uri_with_slot_number_query_param(job_uri)
|
||||
# We have to do a GET to obtain the Etag. It's required on the DELETE.
|
||||
response = self.get_request(job_uri)
|
||||
|
||||
if response['ret'] is True:
|
||||
if 'etag' not in response['headers']:
|
||||
return {'ret': False, 'msg': 'Etag not found in response.'}
|
||||
else:
|
||||
etag = response['headers']['etag']
|
||||
|
||||
if response['data']['PercentComplete'] != 100:
|
||||
return {
|
||||
'ret': False,
|
||||
'changed': False,
|
||||
'msg': 'Cannot delete job because it is in progress.'
|
||||
}
|
||||
|
||||
if response['ret'] is False:
|
||||
if response['status'] == 404:
|
||||
return {
|
||||
'ret': True,
|
||||
'changed': False,
|
||||
'msg': 'Job already deleted.'
|
||||
}
|
||||
return response
|
||||
if self.module.check_mode:
|
||||
return {
|
||||
'ret': True,
|
||||
'changed': True,
|
||||
'msg': 'Update not performed in check mode.'
|
||||
}
|
||||
|
||||
# Do the DELETE (unless we are in check mode)
|
||||
response = self.delete_request(job_uri, etag)
|
||||
if response['ret'] is False:
|
||||
if response['status'] == 404:
|
||||
return {
|
||||
'ret': True,
|
||||
'changed': False
|
||||
}
|
||||
elif response['status'] == 409:
|
||||
return {
|
||||
'ret': False,
|
||||
'changed': False,
|
||||
'msg': 'Cannot delete job because it is in progress.'
|
||||
}
|
||||
return response
|
||||
return {
|
||||
'ret': True,
|
||||
'changed': True
|
||||
}
|
||||
@@ -26,6 +26,36 @@ except ImportError:
|
||||
HAS_PYONE = False
|
||||
|
||||
|
||||
# A helper function to mitigate https://github.com/OpenNebula/one/issues/6064.
|
||||
# It allows for easily handling lists like "NIC" or "DISK" in the JSON-like template representation.
|
||||
# There are either lists of dictionaries (length > 1) or just dictionaries.
|
||||
def flatten(to_flatten, extract=False):
|
||||
"""Flattens nested lists (with optional value extraction)."""
|
||||
def recurse(to_flatten):
|
||||
return sum(map(recurse, to_flatten), []) if isinstance(to_flatten, list) else [to_flatten]
|
||||
value = recurse(to_flatten)
|
||||
if extract and len(value) == 1:
|
||||
return value[0]
|
||||
return value
|
||||
|
||||
|
||||
# A helper function to mitigate https://github.com/OpenNebula/one/issues/6064.
|
||||
# It renders JSON-like template representation into OpenNebula's template syntax (string).
|
||||
def render(to_render):
|
||||
"""Converts dictionary to OpenNebula template."""
|
||||
def recurse(to_render):
|
||||
for key, value in sorted(to_render.items()):
|
||||
if isinstance(value, dict):
|
||||
yield '{0:}=[{1:}]'.format(key, ','.join(recurse(value)))
|
||||
continue
|
||||
if isinstance(value, list):
|
||||
for item in value:
|
||||
yield '{0:}=[{1:}]'.format(key, ','.join(recurse(item)))
|
||||
continue
|
||||
yield '{0:}="{1:}"'.format(key, value)
|
||||
return '\n'.join(recurse(to_render))
|
||||
|
||||
|
||||
class OpenNebulaModule:
|
||||
"""
|
||||
Base class for all OpenNebula Ansible Modules.
|
||||
|
||||
114
plugins/module_utils/puppet.py
Normal file
114
plugins/module_utils/puppet.py
Normal file
@@ -0,0 +1,114 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2022, Alexei Znamensky <russoz@gmail.com>
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
import os
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.cmd_runner import CmdRunner, cmd_runner_fmt
|
||||
|
||||
|
||||
_PUPPET_PATH_PREFIX = ["/opt/puppetlabs/bin"]
|
||||
|
||||
|
||||
def get_facter_dir():
|
||||
if os.getuid() == 0:
|
||||
return '/etc/facter/facts.d'
|
||||
else:
|
||||
return os.path.expanduser('~/.facter/facts.d')
|
||||
|
||||
|
||||
def _puppet_cmd(module):
|
||||
return module.get_bin_path("puppet", False, _PUPPET_PATH_PREFIX)
|
||||
|
||||
|
||||
# If the `timeout` CLI command feature is removed,
|
||||
# Then we could add this as a fixed param to `puppet_runner`
|
||||
def ensure_agent_enabled(module):
|
||||
runner = CmdRunner(
|
||||
module,
|
||||
command="puppet",
|
||||
path_prefix=_PUPPET_PATH_PREFIX,
|
||||
arg_formats=dict(
|
||||
_agent_disabled=cmd_runner_fmt.as_fixed(['config', 'print', 'agent_disabled_lockfile']),
|
||||
),
|
||||
check_rc=False,
|
||||
)
|
||||
|
||||
rc, stdout, stderr = runner("_agent_disabled").run()
|
||||
if os.path.exists(stdout.strip()):
|
||||
module.fail_json(
|
||||
msg="Puppet agent is administratively disabled.",
|
||||
disabled=True)
|
||||
elif rc != 0:
|
||||
module.fail_json(
|
||||
msg="Puppet agent state could not be determined.")
|
||||
|
||||
|
||||
def puppet_runner(module):
|
||||
|
||||
# Keeping backward compatibility, allow for running with the `timeout` CLI command.
|
||||
# If this can be replaced with ansible `timeout` parameter in playbook,
|
||||
# then this function could be removed.
|
||||
def _prepare_base_cmd():
|
||||
_tout_cmd = module.get_bin_path("timeout", False)
|
||||
if _tout_cmd:
|
||||
cmd = ["timeout", "-s", "9", module.params["timeout"], _puppet_cmd(module)]
|
||||
else:
|
||||
cmd = ["puppet"]
|
||||
return cmd
|
||||
|
||||
def noop_func(v):
|
||||
_noop = cmd_runner_fmt.as_map({
|
||||
True: "--noop",
|
||||
False: "--no-noop",
|
||||
})
|
||||
return _noop(module.check_mode or v)
|
||||
|
||||
_logdest_map = {
|
||||
"syslog": ["--logdest", "syslog"],
|
||||
"all": ["--logdest", "syslog", "--logdest", "console"],
|
||||
}
|
||||
|
||||
@cmd_runner_fmt.unpack_args
|
||||
def execute_func(execute, manifest):
|
||||
if execute:
|
||||
return ["--execute", execute]
|
||||
else:
|
||||
return [manifest]
|
||||
|
||||
runner = CmdRunner(
|
||||
module,
|
||||
command=_prepare_base_cmd(),
|
||||
path_prefix=_PUPPET_PATH_PREFIX,
|
||||
arg_formats=dict(
|
||||
_agent_fixed=cmd_runner_fmt.as_fixed([
|
||||
"agent", "--onetime", "--no-daemonize", "--no-usecacheonfailure",
|
||||
"--no-splay", "--detailed-exitcodes", "--verbose", "--color", "0",
|
||||
]),
|
||||
_apply_fixed=cmd_runner_fmt.as_fixed(["apply", "--detailed-exitcodes"]),
|
||||
puppetmaster=cmd_runner_fmt.as_opt_val("--server"),
|
||||
show_diff=cmd_runner_fmt.as_bool("--show-diff"),
|
||||
confdir=cmd_runner_fmt.as_opt_val("--confdir"),
|
||||
environment=cmd_runner_fmt.as_opt_val("--environment"),
|
||||
tags=cmd_runner_fmt.as_func(lambda v: ["--tags", ",".join(v)]),
|
||||
certname=cmd_runner_fmt.as_opt_eq_val("--certname"),
|
||||
noop=cmd_runner_fmt.as_func(noop_func),
|
||||
use_srv_records=cmd_runner_fmt.as_map({
|
||||
True: "--usr_srv_records",
|
||||
False: "--no-usr_srv_records",
|
||||
}),
|
||||
logdest=cmd_runner_fmt.as_map(_logdest_map, default=[]),
|
||||
modulepath=cmd_runner_fmt.as_opt_eq_val("--modulepath"),
|
||||
_execute=cmd_runner_fmt.as_func(execute_func),
|
||||
summarize=cmd_runner_fmt.as_bool("--summarize"),
|
||||
debug=cmd_runner_fmt.as_bool("--debug"),
|
||||
verbose=cmd_runner_fmt.as_bool("--verbose"),
|
||||
),
|
||||
check_rc=False,
|
||||
)
|
||||
return runner
|
||||
@@ -38,6 +38,8 @@ class RedfishUtils(object):
|
||||
self.timeout = timeout
|
||||
self.module = module
|
||||
self.service_root = '/redfish/v1/'
|
||||
self.session_service_uri = '/redfish/v1/SessionService'
|
||||
self.sessions_uri = '/redfish/v1/SessionService/Sessions'
|
||||
self.resource_id = resource_id
|
||||
self.data_modification = data_modification
|
||||
self.strip_etag_quotes = strip_etag_quotes
|
||||
@@ -125,6 +127,10 @@ class RedfishUtils(object):
|
||||
req_headers = dict(GET_HEADERS)
|
||||
username, password, basic_auth = self._auth_params(req_headers)
|
||||
try:
|
||||
# Service root is an unauthenticated resource; remove credentials
|
||||
# in case the caller will be using sessions later.
|
||||
if uri == (self.root_uri + self.service_root):
|
||||
basic_auth = False
|
||||
resp = open_url(uri, method="GET", headers=req_headers,
|
||||
url_username=username, url_password=password,
|
||||
force_basic_auth=basic_auth, validate_certs=False,
|
||||
@@ -151,6 +157,11 @@ class RedfishUtils(object):
|
||||
req_headers = dict(POST_HEADERS)
|
||||
username, password, basic_auth = self._auth_params(req_headers)
|
||||
try:
|
||||
# When performing a POST to the session collection, credentials are
|
||||
# provided in the request body. Do not provide the basic auth
|
||||
# header since this can cause conflicts with some services
|
||||
if self.sessions_uri is not None and uri == (self.root_uri + self.sessions_uri):
|
||||
basic_auth = False
|
||||
resp = open_url(uri, data=json.dumps(pyld),
|
||||
headers=req_headers, method="POST",
|
||||
url_username=username, url_password=password,
|
||||
@@ -363,23 +374,23 @@ class RedfishUtils(object):
|
||||
return {'ret': True}
|
||||
|
||||
def _find_sessionservice_resource(self):
|
||||
# Get the service root
|
||||
response = self.get_request(self.root_uri + self.service_root)
|
||||
if response['ret'] is False:
|
||||
return response
|
||||
data = response['data']
|
||||
if 'SessionService' not in data:
|
||||
|
||||
# Check for the session service and session collection. Well-known
|
||||
# defaults are provided in the constructor, but services that predate
|
||||
# Redfish 1.6.0 might contain different values.
|
||||
self.session_service_uri = data.get('SessionService', {}).get('@odata.id')
|
||||
self.sessions_uri = data.get('Links', {}).get('Sessions', {}).get('@odata.id')
|
||||
|
||||
# If one isn't found, return an error
|
||||
if self.session_service_uri is None:
|
||||
return {'ret': False, 'msg': "SessionService resource not found"}
|
||||
else:
|
||||
session_service = data["SessionService"]["@odata.id"]
|
||||
self.session_service_uri = session_service
|
||||
response = self.get_request(self.root_uri + session_service)
|
||||
if response['ret'] is False:
|
||||
return response
|
||||
data = response['data']
|
||||
sessions = data['Sessions']['@odata.id']
|
||||
if sessions[-1:] == '/':
|
||||
sessions = sessions[:-1]
|
||||
self.sessions_uri = sessions
|
||||
if self.sessions_uri is None:
|
||||
return {'ret': False, 'msg': "SessionCollection resource not found"}
|
||||
return {'ret': True}
|
||||
|
||||
def _get_resource_uri_by_id(self, uris, id_prop):
|
||||
|
||||
@@ -84,6 +84,10 @@ def parse_pagination_link(header):
|
||||
|
||||
|
||||
def filter_sensitive_attributes(container, attributes):
|
||||
'''
|
||||
WARNING: This function is effectively private, **do not use it**!
|
||||
It will be removed or renamed once changing its name no longer triggers a pylint bug.
|
||||
'''
|
||||
for attr in attributes:
|
||||
container[attr] = "SENSITIVE_VALUE"
|
||||
|
||||
|
||||
21
plugins/module_utils/ssh.py
Normal file
21
plugins/module_utils/ssh.py
Normal file
@@ -0,0 +1,21 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2015, Björn Andersson
|
||||
# Copyright (c) 2021, Ansible Project
|
||||
# Copyright (c) 2021, Abhijeet Kasurde <akasurde@redhat.com>
|
||||
# Copyright (c) 2022, Alexei Znamensky <russoz@gmail.com>
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
import os
|
||||
|
||||
|
||||
def determine_config_file(user, config_file):
|
||||
if user:
|
||||
config_file = os.path.join(os.path.expanduser('~%s' % user), '.ssh', 'config')
|
||||
elif config_file is None:
|
||||
config_file = '/etc/ssh/ssh_config'
|
||||
return config_file
|
||||
@@ -60,6 +60,8 @@ options:
|
||||
description:
|
||||
- A list of subcommands.
|
||||
- Each subcommand needs a name, a link and a path parameter.
|
||||
- Subcommands are also named 'slaves' or 'followers', depending on the version
|
||||
of alternatives.
|
||||
type: list
|
||||
elements: dict
|
||||
aliases: ['slaves']
|
||||
@@ -310,10 +312,10 @@ class AlternativesModule(object):
|
||||
current_mode_regex = re.compile(r'\s-\s(?:status\sis\s)?(\w*)(?:\smode|.)$', re.MULTILINE)
|
||||
current_path_regex = re.compile(r'^\s*link currently points to (.*)$', re.MULTILINE)
|
||||
current_link_regex = re.compile(r'^\s*link \w+ is (.*)$', re.MULTILINE)
|
||||
subcmd_path_link_regex = re.compile(r'^\s*slave (\S+) is (.*)$', re.MULTILINE)
|
||||
subcmd_path_link_regex = re.compile(r'^\s*(?:slave|follower) (\S+) is (.*)$', re.MULTILINE)
|
||||
|
||||
alternative_regex = re.compile(r'^(\/.*)\s-\s(?:family\s\S+\s)?priority\s(\d+)((?:\s+slave.*)*)', re.MULTILINE)
|
||||
subcmd_regex = re.compile(r'^\s+slave (.*): (.*)$', re.MULTILINE)
|
||||
alternative_regex = re.compile(r'^(\/.*)\s-\s(?:family\s\S+\s)?priority\s(\d+)((?:\s+(?:slave|follower).*)*)', re.MULTILINE)
|
||||
subcmd_regex = re.compile(r'^\s+(?:slave|follower) (.*): (.*)$', re.MULTILINE)
|
||||
|
||||
match = current_mode_regex.search(display_output)
|
||||
if not match:
|
||||
|
||||
@@ -20,6 +20,10 @@ notes:
|
||||
- >
|
||||
B(Ansible 2.9/2.10): The C(ansible-galaxy) command changed significantly between Ansible 2.9 and
|
||||
ansible-base 2.10 (later ansible-core 2.11). See comments in the parameters.
|
||||
- >
|
||||
The module will try and run using the C(C.UTF-8) locale.
|
||||
If that fails, it will try C(en_US.UTF-8).
|
||||
If that one also fails, the module will fail.
|
||||
requirements:
|
||||
- Ansible 2.9, ansible-base 2.10, or ansible-core 2.11 or newer
|
||||
options:
|
||||
@@ -185,7 +189,7 @@ RETURN = """
|
||||
import re
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.cmd_runner import CmdRunner, cmd_runner_fmt as fmt
|
||||
from ansible_collections.community.general.plugins.module_utils.module_helper import ModuleHelper
|
||||
from ansible_collections.community.general.plugins.module_utils.module_helper import ModuleHelper, ModuleHelperException
|
||||
|
||||
|
||||
class AnsibleGalaxyInstall(ModuleHelper):
|
||||
@@ -226,11 +230,17 @@ class AnsibleGalaxyInstall(ModuleHelper):
|
||||
version=fmt.as_bool("--version"),
|
||||
name=fmt.as_list(),
|
||||
)
|
||||
force_lang = "en_US.UTF-8"
|
||||
check_rc = True
|
||||
|
||||
def _make_runner(self, lang):
|
||||
return CmdRunner(self.module, command=self.command, arg_formats=self.command_args_formats, force_lang=lang, check_rc=True)
|
||||
|
||||
def _get_ansible_galaxy_version(self):
|
||||
class UnsupportedLocale(ModuleHelperException):
|
||||
pass
|
||||
|
||||
def process(rc, out, err):
|
||||
if (rc != 0 and "unsupported locale setting" in err) or (rc == 0 and "cannot change locale" in err):
|
||||
raise UnsupportedLocale(msg=err)
|
||||
line = out.splitlines()[0]
|
||||
match = self._RE_GALAXY_VERSION.match(line)
|
||||
if not match:
|
||||
@@ -239,12 +249,18 @@ class AnsibleGalaxyInstall(ModuleHelper):
|
||||
version = tuple(int(x) for x in version.split('.')[:3])
|
||||
return version
|
||||
|
||||
with self.runner("version", check_rc=True, output_process=process) as ctx:
|
||||
return ctx.run(version=True)
|
||||
try:
|
||||
runner = self._make_runner("C.UTF-8")
|
||||
with runner("version", check_rc=False, output_process=process) as ctx:
|
||||
return runner, ctx.run(version=True)
|
||||
except UnsupportedLocale as e:
|
||||
runner = self._make_runner("en_US.UTF-8")
|
||||
with runner("version", check_rc=True, output_process=process) as ctx:
|
||||
return runner, ctx.run(version=True)
|
||||
|
||||
def __init_module__(self):
|
||||
self.runner = CmdRunner(self.module, command=self.command, arg_formats=self.command_args_formats, force_lang=self.force_lang)
|
||||
self.ansible_version = self._get_ansible_galaxy_version()
|
||||
# self.runner = CmdRunner(self.module, command=self.command, arg_formats=self.command_args_formats, force_lang=self.force_lang)
|
||||
self.runner, self.ansible_version = self._get_ansible_galaxy_version()
|
||||
if self.ansible_version < (2, 11) and not self.vars.ack_min_ansiblecore211:
|
||||
self.module.deprecate(
|
||||
"Support for Ansible 2.9 and ansible-base 2.10 is being deprecated. "
|
||||
@@ -339,11 +355,12 @@ class AnsibleGalaxyInstall(ModuleHelper):
|
||||
self._setup210plus()
|
||||
with self.runner("type galaxy_cmd force no_deps dest requirements_file name", output_process=process) as ctx:
|
||||
ctx.run(galaxy_cmd="install")
|
||||
if self.verbosity > 2:
|
||||
self.vars.set("run_info", ctx.run_info)
|
||||
|
||||
|
||||
def main():
|
||||
galaxy = AnsibleGalaxyInstall()
|
||||
galaxy.run()
|
||||
AnsibleGalaxyInstall.execute()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -49,6 +49,12 @@ options:
|
||||
- Ignore configuration checks about inconsistent module configuration. Especially for mpm_* modules.
|
||||
type: bool
|
||||
default: false
|
||||
warn_mpm_absent:
|
||||
description:
|
||||
- Control the behavior of the warning process for MPM modules.
|
||||
type: bool
|
||||
default: true
|
||||
version_added: 6.3.0
|
||||
requirements: ["a2enmod","a2dismod"]
|
||||
notes:
|
||||
- This does not work on RedHat-based distributions. It does work on Debian- and SuSE-based distributions.
|
||||
@@ -78,6 +84,18 @@ EXAMPLES = '''
|
||||
name: mpm_worker
|
||||
ignore_configcheck: true
|
||||
|
||||
- name: Disable mpm_event, enable mpm_prefork and ignore warnings about missing mpm module
|
||||
community.general.apache2_module:
|
||||
name: "{{ item.module }}"
|
||||
state: "{{ item.state }}"
|
||||
warn_mpm_absent: false
|
||||
ignore_configcheck: true
|
||||
loop:
|
||||
- module: mpm_event
|
||||
state: absent
|
||||
- module: mpm_prefork
|
||||
state: present
|
||||
|
||||
- name: Enable dump_io module, which is identified as dumpio_module inside apache2
|
||||
community.general.apache2_module:
|
||||
state: present
|
||||
@@ -140,10 +158,11 @@ def _module_is_enabled(module):
|
||||
error_msg = "Error executing %s: %s" % (control_binary, stderr)
|
||||
if module.params['ignore_configcheck']:
|
||||
if 'AH00534' in stderr and 'mpm_' in module.params['name']:
|
||||
module.warnings.append(
|
||||
"No MPM module loaded! apache2 reload AND other module actions"
|
||||
" will fail if no MPM module is loaded immediately."
|
||||
)
|
||||
if module.params['warn_mpm_absent']:
|
||||
module.warnings.append(
|
||||
"No MPM module loaded! apache2 reload AND other module actions"
|
||||
" will fail if no MPM module is loaded immediately."
|
||||
)
|
||||
else:
|
||||
module.warnings.append(error_msg)
|
||||
return False
|
||||
@@ -249,6 +268,7 @@ def main():
|
||||
force=dict(type='bool', default=False),
|
||||
state=dict(default='present', choices=['absent', 'present']),
|
||||
ignore_configcheck=dict(type='bool', default=False),
|
||||
warn_mpm_absent=dict(type='bool', default=True),
|
||||
),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
@@ -23,7 +23,7 @@ description:
|
||||
by Consul from the Service name and id respectively by appending 'service:'
|
||||
Node level checks require a I(check_name) and optionally a I(check_id)."
|
||||
- Currently, there is no complete way to retrieve the script, interval or ttl
|
||||
metadata for a registered check. Without this metadata it is not possible to
|
||||
metadata for a registered check. Without this metadata it is not possible to
|
||||
tell if the data supplied with ansible represents a change to a check. As a
|
||||
result this does not attempt to determine changes and will always report a
|
||||
changed occurred. An API method is planned to supply this metadata so at that
|
||||
@@ -37,7 +37,7 @@ options:
|
||||
state:
|
||||
type: str
|
||||
description:
|
||||
- register or deregister the consul service, defaults to present
|
||||
- Register or deregister the consul service, defaults to present.
|
||||
default: present
|
||||
choices: ['present', 'absent']
|
||||
service_name:
|
||||
@@ -45,30 +45,30 @@ options:
|
||||
description:
|
||||
- Unique name for the service on a node, must be unique per node,
|
||||
required if registering a service. May be omitted if registering
|
||||
a node level check
|
||||
a node level check.
|
||||
service_id:
|
||||
type: str
|
||||
description:
|
||||
- the ID for the service, must be unique per node. If I(state=absent),
|
||||
- The ID for the service, must be unique per node. If I(state=absent),
|
||||
defaults to the service name if supplied.
|
||||
host:
|
||||
type: str
|
||||
description:
|
||||
- host of the consul agent defaults to localhost
|
||||
- Host of the consul agent defaults to localhost.
|
||||
default: localhost
|
||||
port:
|
||||
type: int
|
||||
description:
|
||||
- the port on which the consul agent is running
|
||||
- The port on which the consul agent is running.
|
||||
default: 8500
|
||||
scheme:
|
||||
type: str
|
||||
description:
|
||||
- the protocol scheme on which the consul agent is running
|
||||
- The protocol scheme on which the consul agent is running.
|
||||
default: http
|
||||
validate_certs:
|
||||
description:
|
||||
- whether to verify the TLS certificate of the consul agent
|
||||
- Whether to verify the TLS certificate of the consul agent.
|
||||
type: bool
|
||||
default: true
|
||||
notes:
|
||||
@@ -78,12 +78,12 @@ options:
|
||||
service_port:
|
||||
type: int
|
||||
description:
|
||||
- the port on which the service is listening. Can optionally be supplied for
|
||||
registration of a service, i.e. if I(service_name) or I(service_id) is set
|
||||
- The port on which the service is listening. Can optionally be supplied for
|
||||
registration of a service, i.e. if I(service_name) or I(service_id) is set.
|
||||
service_address:
|
||||
type: str
|
||||
description:
|
||||
- the address to advertise that the service will be listening on.
|
||||
- The address to advertise that the service will be listening on.
|
||||
This value will be passed as the I(address) parameter to Consul's
|
||||
C(/v1/agent/service/register) API method, so refer to the Consul API
|
||||
documentation for further details.
|
||||
@@ -91,63 +91,68 @@ options:
|
||||
type: list
|
||||
elements: str
|
||||
description:
|
||||
- tags that will be attached to the service registration.
|
||||
- Tags that will be attached to the service registration.
|
||||
script:
|
||||
type: str
|
||||
description:
|
||||
- the script/command that will be run periodically to check the health
|
||||
of the service. Scripts require I(interval) and vice versa.
|
||||
- The script/command that will be run periodically to check the health of the service.
|
||||
- Requires I(interval) to be provided.
|
||||
interval:
|
||||
type: str
|
||||
description:
|
||||
- the interval at which the service check will be run. This is a number
|
||||
with a s or m suffix to signify the units of seconds or minutes e.g
|
||||
C(15s) or C(1m). If no suffix is supplied, m will be used by default e.g.
|
||||
C(1) will be C(1m). Required if the I(script) parameter is specified.
|
||||
- The interval at which the service check will be run.
|
||||
This is a number with a C(s) or C(m) suffix to signify the units of seconds or minutes e.g C(15s) or C(1m).
|
||||
If no suffix is supplied C(s) will be used by default, e.g. C(10) will be C(10s).
|
||||
- Required if one of the parameters I(script), I(http), or I(tcp) is specified.
|
||||
check_id:
|
||||
type: str
|
||||
description:
|
||||
- an ID for the service check. If I(state=absent), defaults to
|
||||
- An ID for the service check. If I(state=absent), defaults to
|
||||
I(check_name). Ignored if part of a service definition.
|
||||
check_name:
|
||||
type: str
|
||||
description:
|
||||
- a name for the service check. Required if standalone, ignored if
|
||||
- Name for the service check. Required if standalone, ignored if
|
||||
part of service definition.
|
||||
ttl:
|
||||
type: str
|
||||
description:
|
||||
- checks can be registered with a ttl instead of a I(script) and I(interval)
|
||||
- Checks can be registered with a ttl instead of a I(script) and I(interval)
|
||||
this means that the service will check in with the agent before the
|
||||
ttl expires. If it doesn't the check will be considered failed.
|
||||
Required if registering a check and the script an interval are missing
|
||||
Similar to the interval this is a number with a s or m suffix to
|
||||
signify the units of seconds or minutes e.g C(15s) or C(1m). If no suffix
|
||||
is supplied, C(m) will be used by default e.g. C(1) will be C(1m)
|
||||
Similar to the interval this is a number with a C(s) or C(m) suffix to
|
||||
signify the units of seconds or minutes e.g C(15s) or C(1m).
|
||||
If no suffix is supplied C(s) will be used by default, e.g. C(10) will be C(10s).
|
||||
tcp:
|
||||
type: str
|
||||
description:
|
||||
- Checks can be registered with a TCP port. This means that consul
|
||||
will check if the connection attempt to that port is successful (that is, the port is currently accepting connections).
|
||||
The format is C(host:port), for example C(localhost:80).
|
||||
I(interval) must also be provided with this option.
|
||||
- Requires I(interval) to be provided.
|
||||
version_added: '1.3.0'
|
||||
http:
|
||||
type: str
|
||||
description:
|
||||
- checks can be registered with an HTTP endpoint. This means that consul
|
||||
- Checks can be registered with an HTTP endpoint. This means that consul
|
||||
will check that the http endpoint returns a successful HTTP status.
|
||||
I(interval) must also be provided with this option.
|
||||
- Requires I(interval) to be provided.
|
||||
timeout:
|
||||
type: str
|
||||
description:
|
||||
- A custom HTTP check timeout. The consul default is 10 seconds.
|
||||
Similar to the interval this is a number with a C(s) or C(m) suffix to
|
||||
signify the units of seconds or minutes, e.g. C(15s) or C(1m).
|
||||
If no suffix is supplied C(s) will be used by default, e.g. C(10) will be C(10s).
|
||||
token:
|
||||
type: str
|
||||
description:
|
||||
- the token key identifying an ACL rule set. May be required to register services.
|
||||
- The token key identifying an ACL rule set. May be required to register services.
|
||||
ack_params_state_absent:
|
||||
type: bool
|
||||
description:
|
||||
- Disable deprecation warning when using parameters incompatible with I(state=absent).
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
@@ -583,7 +588,8 @@ def main():
|
||||
http=dict(type='str'),
|
||||
timeout=dict(type='str'),
|
||||
tags=dict(type='list', elements='str'),
|
||||
token=dict(no_log=True)
|
||||
token=dict(no_log=True),
|
||||
ack_params_state_absent=dict(type='bool'),
|
||||
),
|
||||
required_if=[
|
||||
('state', 'present', ['service_name']),
|
||||
@@ -591,14 +597,29 @@ def main():
|
||||
],
|
||||
supports_check_mode=False,
|
||||
)
|
||||
p = module.params
|
||||
|
||||
test_dependencies(module)
|
||||
if p['state'] == 'absent' and any(p[x] for x in ['script', 'ttl', 'tcp', 'http', 'interval']) and not p['ack_params_state_absent']:
|
||||
module.deprecate(
|
||||
"The use of parameters 'script', 'ttl', 'tcp', 'http', 'interval' along with 'state=absent' is deprecated. "
|
||||
"In community.general 8.0.0 their use will become an error. "
|
||||
"To suppress this deprecation notice, set parameter ack_params_state_absent=true.",
|
||||
version="8.0.0",
|
||||
collection_name="community.general",
|
||||
)
|
||||
# When reaching c.g 8.0.0:
|
||||
# - Replace the deprecation with a fail_json(), remove the "ack_params_state_absent" condition from the "if"
|
||||
# - Add mutually_exclusive for ('script', 'ttl', 'tcp', 'http'), then remove that validation from parse_check()
|
||||
# - Add required_by {'script': 'interval', 'http': 'interval', 'tcp': 'interval'}, then remove checks for 'interval' in ConsulCheck.__init__()
|
||||
# - Deprecate the parameter ack_params_state_absent
|
||||
|
||||
try:
|
||||
register_with_consul(module)
|
||||
except SystemExit:
|
||||
raise
|
||||
except ConnectionError as e:
|
||||
module.fail_json(msg='Could not connect to consul agent at %s:%s, error was %s' % (
|
||||
module.params['host'], module.params['port'], str(e)))
|
||||
module.fail_json(msg='Could not connect to consul agent at %s:%s, error was %s' % (p['host'], p['port'], str(e)))
|
||||
except Exception as e:
|
||||
module.fail_json(msg=str(e))
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ options:
|
||||
required: false
|
||||
force:
|
||||
description:
|
||||
- Force gem to install, bypassing dependency checks.
|
||||
- Force gem to (un-)install, bypassing dependency checks.
|
||||
required: false
|
||||
default: false
|
||||
type: bool
|
||||
@@ -234,7 +234,9 @@ def uninstall(module):
|
||||
cmd.extend(['--version', module.params['version']])
|
||||
else:
|
||||
cmd.append('--all')
|
||||
cmd.append('--executable')
|
||||
cmd.append('--executable')
|
||||
if module.params['force']:
|
||||
cmd.append('--force')
|
||||
cmd.append(module.params['name'])
|
||||
module.run_command(cmd, environ_update=environ, check_rc=True)
|
||||
|
||||
|
||||
@@ -108,17 +108,8 @@ EXAMPLES = '''
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
create_release:
|
||||
description:
|
||||
- Version of the created release
|
||||
- "For Ansible version 2.5 and later, if specified release version already exists, then State is unchanged"
|
||||
- "For Ansible versions prior to 2.5, if specified release version already exists, then State is skipped"
|
||||
type: str
|
||||
returned: success
|
||||
sample: 1.1.0
|
||||
|
||||
latest_release:
|
||||
description: Version of the latest release
|
||||
tag:
|
||||
description: Version of the created/latest release.
|
||||
type: str
|
||||
returned: success
|
||||
sample: 1.1.0
|
||||
|
||||
@@ -151,6 +151,7 @@ class GitLabDeployKey(object):
|
||||
changed = True
|
||||
else:
|
||||
changed, deploy_key = self.update_deploy_key(self.deploy_key_object, {
|
||||
'title': key_title,
|
||||
'can_push': options['can_push']})
|
||||
|
||||
self.deploy_key_object = deploy_key
|
||||
|
||||
@@ -165,7 +165,7 @@ from ansible.module_utils.six import string_types
|
||||
from ansible.module_utils.six import integer_types
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import (
|
||||
auth_argument_spec, gitlab_authentication, ensure_gitlab_package
|
||||
auth_argument_spec, gitlab_authentication, ensure_gitlab_package, filter_returned_variables
|
||||
)
|
||||
|
||||
|
||||
@@ -296,11 +296,7 @@ def native_python_main(this_gitlab, purge, requested_variables, state, module):
|
||||
before = [x.attributes for x in gitlab_keys]
|
||||
|
||||
gitlab_keys = this_gitlab.list_all_group_variables()
|
||||
existing_variables = [x.attributes for x in gitlab_keys]
|
||||
|
||||
# preprocessing:filter out and enrich before compare
|
||||
for item in existing_variables:
|
||||
item.pop('group_id')
|
||||
existing_variables = filter_returned_variables(gitlab_keys)
|
||||
|
||||
for item in requested_variables:
|
||||
item['key'] = item.pop('name')
|
||||
@@ -331,9 +327,7 @@ def native_python_main(this_gitlab, purge, requested_variables, state, module):
|
||||
if purge:
|
||||
# refetch and filter
|
||||
gitlab_keys = this_gitlab.list_all_group_variables()
|
||||
existing_variables = [x.attributes for x in gitlab_keys]
|
||||
for item in existing_variables:
|
||||
item.pop('group_id')
|
||||
existing_variables = filter_returned_variables(gitlab_keys)
|
||||
|
||||
remove = [x for x in existing_variables if x not in requested_variables]
|
||||
for item in remove:
|
||||
|
||||
@@ -172,6 +172,30 @@ options:
|
||||
- This option is only used on creation, not for updates. This is also only used if I(initialize_with_readme=true).
|
||||
type: str
|
||||
version_added: "4.2.0"
|
||||
builds_access_level:
|
||||
description:
|
||||
- C(private) means that repository CI/CD is allowed only to project members.
|
||||
- C(disabled) means that repository CI/CD is disabled.
|
||||
- C(enabled) means that repository CI/CD is enabled.
|
||||
type: str
|
||||
choices: ["private", "disabled", "enabled"]
|
||||
version_added: "6.2.0"
|
||||
forking_access_level:
|
||||
description:
|
||||
- C(private) means that repository forks is allowed only to project members.
|
||||
- C(disabled) means that repository forks are disabled.
|
||||
- C(enabled) means that repository forks are enabled.
|
||||
type: str
|
||||
choices: ["private", "disabled", "enabled"]
|
||||
version_added: "6.2.0"
|
||||
container_registry_access_level:
|
||||
description:
|
||||
- C(private) means that container registry is allowed only to project members.
|
||||
- C(disabled) means that container registry is disabled.
|
||||
- C(enabled) means that container registry is enabled.
|
||||
type: str
|
||||
choices: ["private", "disabled", "enabled"]
|
||||
version_added: "6.2.0"
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
@@ -287,6 +311,9 @@ class GitLabProject(object):
|
||||
'squash_option': options['squash_option'],
|
||||
'ci_config_path': options['ci_config_path'],
|
||||
'shared_runners_enabled': options['shared_runners_enabled'],
|
||||
'builds_access_level': options['builds_access_level'],
|
||||
'forking_access_level': options['forking_access_level'],
|
||||
'container_registry_access_level': options['container_registry_access_level'],
|
||||
}
|
||||
# Because we have already call userExists in main()
|
||||
if self.project_object is None:
|
||||
@@ -417,6 +444,9 @@ def main():
|
||||
ci_config_path=dict(type='str'),
|
||||
shared_runners_enabled=dict(type='bool'),
|
||||
avatar_path=dict(type='path'),
|
||||
builds_access_level=dict(type='str', choices=['private', 'disabled', 'enabled']),
|
||||
forking_access_level=dict(type='str', choices=['private', 'disabled', 'enabled']),
|
||||
container_registry_access_level=dict(type='str', choices=['private', 'disabled', 'enabled']),
|
||||
))
|
||||
|
||||
module = AnsibleModule(
|
||||
@@ -464,6 +494,9 @@ def main():
|
||||
shared_runners_enabled = module.params['shared_runners_enabled']
|
||||
avatar_path = module.params['avatar_path']
|
||||
default_branch = module.params['default_branch']
|
||||
builds_access_level = module.params['builds_access_level']
|
||||
forking_access_level = module.params['forking_access_level']
|
||||
container_registry_access_level = module.params['container_registry_access_level']
|
||||
|
||||
if default_branch and not initialize_with_readme:
|
||||
module.fail_json(msg="Param default_branch need param initialize_with_readme set to true")
|
||||
@@ -533,6 +566,9 @@ def main():
|
||||
"ci_config_path": ci_config_path,
|
||||
"shared_runners_enabled": shared_runners_enabled,
|
||||
"avatar_path": avatar_path,
|
||||
"builds_access_level": builds_access_level,
|
||||
"forking_access_level": forking_access_level,
|
||||
"container_registry_access_level": container_registry_access_level,
|
||||
}):
|
||||
|
||||
module.exit_json(changed=True, msg="Successfully created or updated the project %s" % project_name, project=gitlab_project.project_object._attrs)
|
||||
|
||||
@@ -189,7 +189,7 @@ except Exception:
|
||||
HAS_GITLAB_PACKAGE = False
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import (
|
||||
auth_argument_spec, gitlab_authentication, ensure_gitlab_package
|
||||
auth_argument_spec, gitlab_authentication, ensure_gitlab_package, filter_returned_variables
|
||||
)
|
||||
|
||||
|
||||
@@ -255,9 +255,11 @@ class GitlabProjectVariables(object):
|
||||
return True
|
||||
|
||||
var = {
|
||||
"key": var_obj.get('key'), "value": var_obj.get('value'),
|
||||
"masked": var_obj.get('masked'), "protected": var_obj.get('protected'),
|
||||
"variable_type": var_obj.get('variable_type')
|
||||
"key": var_obj.get('key'),
|
||||
"value": var_obj.get('value'),
|
||||
"masked": var_obj.get('masked'),
|
||||
"protected": var_obj.get('protected'),
|
||||
"variable_type": var_obj.get('variable_type'),
|
||||
}
|
||||
|
||||
if var_obj.get('environment_scope') is not None:
|
||||
@@ -319,12 +321,9 @@ def native_python_main(this_gitlab, purge, requested_variables, state, module):
|
||||
before = [x.attributes for x in gitlab_keys]
|
||||
|
||||
gitlab_keys = this_gitlab.list_all_project_variables()
|
||||
existing_variables = [x.attributes for x in gitlab_keys]
|
||||
|
||||
# preprocessing:filter out and enrich before compare
|
||||
for item in existing_variables:
|
||||
item.pop('project_id')
|
||||
existing_variables = filter_returned_variables(gitlab_keys)
|
||||
|
||||
# filter out and enrich before compare
|
||||
for item in requested_variables:
|
||||
item['key'] = item.pop('name')
|
||||
item['value'] = str(item.get('value'))
|
||||
@@ -354,9 +353,7 @@ def native_python_main(this_gitlab, purge, requested_variables, state, module):
|
||||
if purge:
|
||||
# refetch and filter
|
||||
gitlab_keys = this_gitlab.list_all_project_variables()
|
||||
existing_variables = [x.attributes for x in gitlab_keys]
|
||||
for item in existing_variables:
|
||||
item.pop('project_id')
|
||||
existing_variables = filter_returned_variables(gitlab_keys)
|
||||
|
||||
remove = [x for x in existing_variables if x not in requested_variables]
|
||||
for item in remove:
|
||||
@@ -409,7 +406,7 @@ def main():
|
||||
masked=dict(type='bool', default=False),
|
||||
protected=dict(type='bool', default=False),
|
||||
environment_scope=dict(type='str', default='*'),
|
||||
variable_type=dict(type='str', default='env_var', choices=["env_var", "file"])
|
||||
variable_type=dict(type='str', default='env_var', choices=["env_var", "file"]),
|
||||
)),
|
||||
state=dict(type='str', default="present", choices=["absent", "present"]),
|
||||
)
|
||||
|
||||
@@ -84,12 +84,23 @@ options:
|
||||
access_level:
|
||||
description:
|
||||
- Determines if a runner can pick up jobs only from protected branches.
|
||||
- If I(access_level_on_creation) is not explicitly set to C(true), this option is ignored on registration and
|
||||
is only applied on updates.
|
||||
- If set to C(ref_protected), runner can pick up jobs only from protected branches.
|
||||
- If set to C(not_protected), runner can pick up jobs from both protected and unprotected branches.
|
||||
required: false
|
||||
default: ref_protected
|
||||
choices: ["ref_protected", "not_protected"]
|
||||
type: str
|
||||
access_level_on_creation:
|
||||
description:
|
||||
- Whether the runner should be registered with an access level or not.
|
||||
- If set to C(true), the value of I(access_level) is used for runner registration.
|
||||
- If set to C(false), GitLab registers the runner with the default access level.
|
||||
- The current default of this option is C(false). This default is deprecated and will change to C(true) in commuinty.general 7.0.0.
|
||||
required: false
|
||||
type: bool
|
||||
version_added: 6.3.0
|
||||
maximum_timeout:
|
||||
description:
|
||||
- The maximum time that a runner has to complete a specific job.
|
||||
@@ -207,27 +218,34 @@ class GitLabRunner(object):
|
||||
def create_or_update_runner(self, description, options):
|
||||
changed = False
|
||||
|
||||
arguments = {
|
||||
'active': options['active'],
|
||||
'locked': options['locked'],
|
||||
'run_untagged': options['run_untagged'],
|
||||
'maximum_timeout': options['maximum_timeout'],
|
||||
'tag_list': options['tag_list'],
|
||||
}
|
||||
# Because we have already call userExists in main()
|
||||
if self.runner_object is None:
|
||||
runner = self.create_runner({
|
||||
'description': description,
|
||||
'active': options['active'],
|
||||
'token': options['registration_token'],
|
||||
'locked': options['locked'],
|
||||
'run_untagged': options['run_untagged'],
|
||||
'maximum_timeout': options['maximum_timeout'],
|
||||
'tag_list': options['tag_list'],
|
||||
})
|
||||
arguments['description'] = description
|
||||
arguments['token'] = options['registration_token']
|
||||
|
||||
access_level_on_creation = self._module.params['access_level_on_creation']
|
||||
if access_level_on_creation is None:
|
||||
message = "The option 'access_level_on_creation' is unspecified, so 'false' is assumed. "\
|
||||
"That means any value of 'access_level' is ignored and GitLab registers the runner with its default value. "\
|
||||
"The option 'access_level_on_creation' will switch to 'true' in community.general 7.0.0"
|
||||
self._module.deprecate(message, version='7.0.0', collection_name='community.general')
|
||||
access_level_on_creation = False
|
||||
|
||||
if access_level_on_creation:
|
||||
arguments['access_level'] = options['access_level']
|
||||
|
||||
runner = self.create_runner(arguments)
|
||||
changed = True
|
||||
else:
|
||||
changed, runner = self.update_runner(self.runner_object, {
|
||||
'active': options['active'],
|
||||
'locked': options['locked'],
|
||||
'run_untagged': options['run_untagged'],
|
||||
'maximum_timeout': options['maximum_timeout'],
|
||||
'access_level': options['access_level'],
|
||||
'tag_list': options['tag_list'],
|
||||
})
|
||||
arguments['access_level'] = options['access_level']
|
||||
changed, runner = self.update_runner(self.runner_object, arguments)
|
||||
|
||||
self.runner_object = runner
|
||||
if changed:
|
||||
@@ -328,6 +346,7 @@ def main():
|
||||
run_untagged=dict(type='bool', default=True),
|
||||
locked=dict(type='bool', default=False),
|
||||
access_level=dict(type='str', default='ref_protected', choices=["not_protected", "ref_protected"]),
|
||||
access_level_on_creation=dict(type='bool'),
|
||||
maximum_timeout=dict(type='int', default=3600),
|
||||
registration_token=dict(type='str', no_log=True),
|
||||
project=dict(type='str'),
|
||||
|
||||
@@ -41,9 +41,12 @@ options:
|
||||
description:
|
||||
- Encryption scheme to be used. As well as the four choices listed
|
||||
here, you can also use any other hash supported by passlib, such as
|
||||
md5_crypt and sha256_crypt, which are linux passwd hashes. If you
|
||||
do so the password file will not be compatible with Apache or Nginx
|
||||
- 'Some of the available choices might be: C(apr_md5_crypt), C(des_crypt), C(ldap_sha1), C(plaintext)'
|
||||
C(portable_apache22) and C(host_apache24); or C(md5_crypt) and C(sha256_crypt),
|
||||
which are Linux passwd hashes. Only some schemes in addition to
|
||||
the four choices below will be compatible with Apache or Nginx, and
|
||||
supported schemes depend on passlib version and its dependencies.
|
||||
- See U(https://passlib.readthedocs.io/en/stable/lib/passlib.apache.html#passlib.apache.HtpasswdFile) parameter C(default_scheme).
|
||||
- 'Some of the available choices might be: C(apr_md5_crypt), C(des_crypt), C(ldap_sha1), C(plaintext).'
|
||||
state:
|
||||
type: str
|
||||
required: false
|
||||
|
||||
@@ -125,7 +125,7 @@ def main():
|
||||
password=dict(no_log=True),
|
||||
auth_token=dict(no_log=True),
|
||||
attribute_name=dict(required=True),
|
||||
attribute_value=dict(),
|
||||
attribute_value=dict(type='str'),
|
||||
timeout=dict(type='int', default=10)
|
||||
),
|
||||
required_together=[
|
||||
|
||||
@@ -64,6 +64,17 @@ options:
|
||||
- If option is omitted assigned users will not be checked or changed.
|
||||
type: list
|
||||
elements: str
|
||||
external_user:
|
||||
description:
|
||||
- List of external users assigned to this group.
|
||||
- Behaves identically to I(user) with respect to I(append) attribute.
|
||||
- List entries can be in C(DOMAIN\\username) or SID format.
|
||||
- Unless SIDs are provided, the module will always attempt to make changes even if the group already has all the users.
|
||||
This is because only SIDs are returned by IPA query.
|
||||
- I(external=true) is needed for this option to work.
|
||||
type: list
|
||||
elements: str
|
||||
version_added: 6.3.0
|
||||
state:
|
||||
description:
|
||||
- State to ensure
|
||||
@@ -116,6 +127,28 @@ EXAMPLES = r'''
|
||||
ipa_user: admin
|
||||
ipa_pass: topsecret
|
||||
|
||||
- name: Add external user to a group
|
||||
community.general.ipa_group:
|
||||
name: developers
|
||||
external: true
|
||||
append: true
|
||||
external_user:
|
||||
- S-1-5-21-123-1234-12345-63421
|
||||
ipa_host: ipa.example.com
|
||||
ipa_user: admin
|
||||
ipa_pass: topsecret
|
||||
|
||||
- name: Add a user from MYDOMAIN
|
||||
community.general.ipa_group:
|
||||
name: developers
|
||||
external: true
|
||||
append: true
|
||||
external_user:
|
||||
- MYDOMAIN\\john
|
||||
ipa_host: ipa.example.com
|
||||
ipa_user: admin
|
||||
ipa_pass: topsecret
|
||||
|
||||
- name: Ensure group is absent
|
||||
community.general.ipa_group:
|
||||
name: sysops
|
||||
@@ -164,6 +197,9 @@ class GroupIPAClient(IPAClient):
|
||||
def group_add_member_user(self, name, item):
|
||||
return self.group_add_member(name=name, item={'user': item})
|
||||
|
||||
def group_add_member_externaluser(self, name, item):
|
||||
return self.group_add_member(name=name, item={'ipaexternalmember': item})
|
||||
|
||||
def group_remove_member(self, name, item):
|
||||
return self._post_json(method='group_remove_member', name=name, item=item)
|
||||
|
||||
@@ -173,6 +209,9 @@ class GroupIPAClient(IPAClient):
|
||||
def group_remove_member_user(self, name, item):
|
||||
return self.group_remove_member(name=name, item={'user': item})
|
||||
|
||||
def group_remove_member_externaluser(self, name, item):
|
||||
return self.group_remove_member(name=name, item={'ipaexternalmember': item})
|
||||
|
||||
|
||||
def get_group_dict(description=None, external=None, gid=None, nonposix=None):
|
||||
group = {}
|
||||
@@ -208,12 +247,19 @@ def ensure(module, client):
|
||||
name = module.params['cn']
|
||||
group = module.params['group']
|
||||
user = module.params['user']
|
||||
external = module.params['external']
|
||||
external_user = module.params['external_user']
|
||||
append = module.params['append']
|
||||
|
||||
module_group = get_group_dict(description=module.params['description'], external=module.params['external'],
|
||||
gid=module.params['gidnumber'], nonposix=module.params['nonposix'])
|
||||
module_group = get_group_dict(description=module.params['description'],
|
||||
external=external,
|
||||
gid=module.params['gidnumber'],
|
||||
nonposix=module.params['nonposix'])
|
||||
ipa_group = client.group_find(name=name)
|
||||
|
||||
if (not (external or external_user is None)):
|
||||
module.fail_json("external_user can only be set if external = True")
|
||||
|
||||
changed = False
|
||||
if state == 'present':
|
||||
if not ipa_group:
|
||||
@@ -242,6 +288,11 @@ def ensure(module, client):
|
||||
client.group_remove_member_user,
|
||||
append=append) or changed
|
||||
|
||||
if external_user is not None:
|
||||
changed = client.modify_if_diff(name, ipa_group.get('ipaexternalmember', []), external_user,
|
||||
client.group_add_member_externaluser,
|
||||
client.group_remove_member_externaluser,
|
||||
append=append) or changed
|
||||
else:
|
||||
if ipa_group:
|
||||
changed = True
|
||||
@@ -256,6 +307,7 @@ def main():
|
||||
argument_spec.update(cn=dict(type='str', required=True, aliases=['name']),
|
||||
description=dict(type='str'),
|
||||
external=dict(type='bool'),
|
||||
external_user=dict(type='list', elements='str'),
|
||||
gidnumber=dict(type='str', aliases=['gid']),
|
||||
group=dict(type='list', elements='str'),
|
||||
nonposix=dict(type='bool'),
|
||||
|
||||
@@ -260,10 +260,7 @@ def read_state(b_path):
|
||||
'''
|
||||
with open(b_path, 'r') as f:
|
||||
text = f.read()
|
||||
lines = text.splitlines()
|
||||
while '' in lines:
|
||||
lines.remove('')
|
||||
return lines
|
||||
return [t for t in text.splitlines() if t != '']
|
||||
|
||||
|
||||
def write_state(b_path, lines, changed):
|
||||
@@ -273,8 +270,7 @@ def write_state(b_path, lines, changed):
|
||||
# Populate a temporary file
|
||||
tmpfd, tmpfile = tempfile.mkstemp()
|
||||
with os.fdopen(tmpfd, 'w') as f:
|
||||
for line in lines:
|
||||
f.write('%s\n' % line)
|
||||
f.write("{0}\n".format("\n".join(lines)))
|
||||
|
||||
# Prepare to copy temporary file to the final destination
|
||||
if not os.path.exists(b_path):
|
||||
@@ -335,9 +331,7 @@ def filter_and_format_state(string):
|
||||
string = re.sub(r'((^|\n)# (Generated|Completed)[^\n]*) on [^\n]*', r'\1', string)
|
||||
if not module.params['counters']:
|
||||
string = re.sub(r'\[[0-9]+:[0-9]+\]', r'[0:0]', string)
|
||||
lines = string.splitlines()
|
||||
while '' in lines:
|
||||
lines.remove('')
|
||||
lines = [line for line in string.splitlines() if line != '']
|
||||
return lines
|
||||
|
||||
|
||||
@@ -354,10 +348,7 @@ def per_table_state(command, state):
|
||||
dummy, out, dummy = module.run_command(COMMAND, check_rc=True)
|
||||
out = re.sub(r'(^|\n)(# Generated|# Completed|[*]%s|COMMIT)[^\n]*' % t, r'', out)
|
||||
out = re.sub(r' *\[[0-9]+:[0-9]+\] *', r'', out)
|
||||
table = out.splitlines()
|
||||
while '' in table:
|
||||
table.remove('')
|
||||
tables[t] = table
|
||||
tables[t] = [tt for tt in out.splitlines() if tt != '']
|
||||
return tables
|
||||
|
||||
|
||||
@@ -548,8 +539,7 @@ def main():
|
||||
if module.check_mode:
|
||||
tmpfd, tmpfile = tempfile.mkstemp()
|
||||
with os.fdopen(tmpfd, 'w') as f:
|
||||
for line in initial_state:
|
||||
f.write('%s\n' % line)
|
||||
f.write("{0}\n".format("\n".join(initial_state)))
|
||||
|
||||
if filecmp.cmp(tmpfile, b_path):
|
||||
restored_state = initial_state
|
||||
|
||||
@@ -24,7 +24,7 @@ description:
|
||||
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/15.0/rest-api/index.html).
|
||||
Keycloak API and its documentation at U(https://www.keycloak.org/docs-api/20.0.2/rest-api/index.html).
|
||||
|
||||
|
||||
options:
|
||||
@@ -835,7 +835,7 @@ def main():
|
||||
|
||||
# See if it already exists in Keycloak
|
||||
if cid is None:
|
||||
found = kc.get_components(urlencode(dict(type='org.keycloak.storage.UserStorageProvider', parent=realm, name=name)), realm)
|
||||
found = kc.get_components(urlencode(dict(type='org.keycloak.storage.UserStorageProvider', name=name)), realm)
|
||||
if len(found) > 1:
|
||||
module.fail_json(msg='No ID given and found multiple user federations with name `{name}`. Cannot continue.'.format(name=name))
|
||||
before_comp = next(iter(found), None)
|
||||
@@ -923,6 +923,8 @@ def main():
|
||||
updated_mappers = desired_comp.pop('mappers', [])
|
||||
after_comp = kc.create_component(desired_comp, realm)
|
||||
|
||||
cid = after_comp['id']
|
||||
|
||||
for mapper in updated_mappers:
|
||||
found = kc.get_components(urlencode(dict(parent=cid, name=mapper['name'])), realm)
|
||||
if len(found) > 1:
|
||||
|
||||
@@ -677,7 +677,7 @@ class LxcContainerManagement(object):
|
||||
|
||||
false_values = BOOLEANS_FALSE.union([None, ''])
|
||||
result = dict(
|
||||
(k, v)
|
||||
(v, self.module.params[k])
|
||||
for k, v in variables.items()
|
||||
if self.module.params[k] not in false_values
|
||||
)
|
||||
|
||||
@@ -27,7 +27,10 @@ options:
|
||||
description:
|
||||
- C(absent) - policy_profiles should not exist,
|
||||
- C(present) - policy_profiles should exist,
|
||||
- C(list) - list current policy_profiles and policies.
|
||||
- >
|
||||
C(list) - list current policy_profiles and policies.
|
||||
This state is deprecated and will be removed 8.0.0.
|
||||
Please use the module M(community.general.manageiq_policies_info) instead.
|
||||
choices: ['absent', 'present', 'list']
|
||||
default: 'present'
|
||||
policy_profiles:
|
||||
@@ -163,6 +166,13 @@ def main():
|
||||
resource_name = module.params['resource_name']
|
||||
state = module.params['state']
|
||||
|
||||
if state == "list":
|
||||
module.deprecate(
|
||||
'The value "list" for "state" is deprecated. Please use community.general.manageiq_policies_info instead.',
|
||||
version='8.0.0',
|
||||
collection_name='community.general'
|
||||
)
|
||||
|
||||
# get the action and resource type
|
||||
action = actions[state]
|
||||
resource_type = manageiq_entities()[resource_type_key]
|
||||
|
||||
@@ -269,12 +269,16 @@ class RecordManager(object):
|
||||
if lookup.rcode() in [dns.rcode.SERVFAIL, dns.rcode.REFUSED]:
|
||||
self.module.fail_json(msg='Zone lookup failure: \'%s\' will not respond to queries regarding \'%s\'.' % (
|
||||
self.module.params['server'], self.module.params['record']))
|
||||
try:
|
||||
zone = lookup.authority[0].name
|
||||
if zone == name:
|
||||
return zone.to_text()
|
||||
except IndexError:
|
||||
pass
|
||||
# If the response contains an Answer SOA RR whose name matches the queried name,
|
||||
# this is the name of the zone in which the record needs to be inserted.
|
||||
for rr in lookup.answer:
|
||||
if rr.rdtype == dns.rdatatype.SOA and rr.name == name:
|
||||
return rr.name.to_text()
|
||||
# If the response contains an Authority SOA RR whose name is a subdomain of the queried name,
|
||||
# this SOA name is the zone in which the record needs to be inserted.
|
||||
for rr in lookup.authority:
|
||||
if rr.rdtype == dns.rdatatype.SOA and name.fullcompare(rr.name)[0] == dns.name.NAMERELN_SUBDOMAIN:
|
||||
return rr.name.to_text()
|
||||
try:
|
||||
name = name.parent()
|
||||
except dns.name.NoParent:
|
||||
|
||||
267
plugins/modules/ocapi_command.py
Normal file
267
plugins/modules/ocapi_command.py
Normal file
@@ -0,0 +1,267 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2022 Western Digital Corporation
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: ocapi_command
|
||||
version_added: 6.3.0
|
||||
short_description: Manages Out-Of-Band controllers using Open Composable API (OCAPI)
|
||||
description:
|
||||
- Builds OCAPI URIs locally and sends them to remote OOB controllers to
|
||||
perform an action.
|
||||
- Manages OOB controller such as Indicator LED, Reboot, Power Mode, Firmware Update.
|
||||
options:
|
||||
category:
|
||||
required: true
|
||||
description:
|
||||
- Category to execute on OOB controller.
|
||||
type: str
|
||||
command:
|
||||
required: true
|
||||
description:
|
||||
- Command to execute on OOB controller.
|
||||
type: str
|
||||
baseuri:
|
||||
required: true
|
||||
description:
|
||||
- Base URI of OOB controller.
|
||||
type: str
|
||||
proxy_slot_number:
|
||||
description: For proxied inband requests, the slot number of the IOM. Only applies if I(baseuri) is a proxy server.
|
||||
type: int
|
||||
update_image_path:
|
||||
required: false
|
||||
description:
|
||||
- For C(FWUpload), the path on the local filesystem of the firmware update image.
|
||||
type: str
|
||||
job_name:
|
||||
required: false
|
||||
description:
|
||||
- For C(DeleteJob) command, the name of the job to delete.
|
||||
type: str
|
||||
username:
|
||||
required: true
|
||||
description:
|
||||
- Username for authenticating to OOB controller.
|
||||
type: str
|
||||
password:
|
||||
required: true
|
||||
description:
|
||||
- Password for authenticating to OOB controller.
|
||||
type: str
|
||||
timeout:
|
||||
description:
|
||||
- Timeout in seconds for URL requests to OOB controller.
|
||||
default: 10
|
||||
type: int
|
||||
|
||||
author: "Mike Moerk (@mikemoerk)"
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Set the power state to low
|
||||
community.general.ocapi_command:
|
||||
category: Chassis
|
||||
command: PowerModeLow
|
||||
baseuri: "{{ baseuri }}"
|
||||
username: "{{ username }}"
|
||||
password: "{{ password }}"
|
||||
|
||||
- name: Set the power state to normal
|
||||
community.general.ocapi_command:
|
||||
category: Chassis
|
||||
command: PowerModeNormal
|
||||
baseuri: "{{ baseuri }}"
|
||||
username: "{{ username }}"
|
||||
password: "{{ password }}"
|
||||
- name: Set chassis indicator LED to on
|
||||
community.general.ocapi_command:
|
||||
category: Chassis
|
||||
command: IndicatorLedOn
|
||||
baseuri: "{{ baseuri }}"
|
||||
proxy_slot_number: 2
|
||||
username: "{{ username }}"
|
||||
password: "{{ password }}"
|
||||
- name: Set chassis indicator LED to off
|
||||
community.general.ocapi_command:
|
||||
category: Chassis
|
||||
command: IndicatorLedOff
|
||||
baseuri: "{{ baseuri }}"
|
||||
proxy_slot_number: 2
|
||||
username: "{{ username }}"
|
||||
password: "{{ password }}"
|
||||
- name: Reset Enclosure
|
||||
community.general.ocapi_command:
|
||||
category: Systems
|
||||
command: PowerGracefulRestart
|
||||
baseuri: "{{ baseuri }}"
|
||||
proxy_slot_number: 2
|
||||
username: "{{ username }}"
|
||||
password: "{{ password }}"
|
||||
- name: Firmware Upload
|
||||
community.general.ocapi_command:
|
||||
category: Update
|
||||
command: FWUpload
|
||||
baseuri: "iom1.wdc.com"
|
||||
proxy_slot_number: 2
|
||||
username: "{{ username }}"
|
||||
password: "{{ password }}"
|
||||
update_image_path: "/path/to/firmware.tar.gz"
|
||||
- name: Firmware Update
|
||||
community.general.ocapi_command:
|
||||
category: Update
|
||||
command: FWUpdate
|
||||
baseuri: "iom1.wdc.com"
|
||||
proxy_slot_number: 2
|
||||
username: "{{ username }}"
|
||||
password: "{{ password }}"
|
||||
- name: Firmware Activate
|
||||
community.general.ocapi_command:
|
||||
category: Update
|
||||
command: FWActivate
|
||||
baseuri: "iom1.wdc.com"
|
||||
proxy_slot_number: 2
|
||||
username: "{{ username }}"
|
||||
password: "{{ password }}"
|
||||
- name: Delete Job
|
||||
community.general.ocapi_command:
|
||||
category: Jobs
|
||||
command: DeleteJob
|
||||
job_name: FirmwareUpdate
|
||||
baseuri: "{{ baseuri }}"
|
||||
proxy_slot_number: 2
|
||||
username: "{{ username }}"
|
||||
password: "{{ password }}"
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
msg:
|
||||
description: Message with action result or error description.
|
||||
returned: always
|
||||
type: str
|
||||
sample: "Action was successful"
|
||||
|
||||
jobUri:
|
||||
description: URI to use to monitor status of the operation. Returned for async commands such as Firmware Update, Firmware Activate.
|
||||
returned: when supported
|
||||
type: str
|
||||
sample: "https://ioma.wdc.com/Storage/Devices/openflex-data24-usalp03020qb0003/Jobs/FirmwareUpdate/"
|
||||
|
||||
operationStatusId:
|
||||
description: OCAPI State ID (see OCAPI documentation for possible values).
|
||||
returned: when supported
|
||||
type: int
|
||||
sample: 2
|
||||
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.general.plugins.module_utils.ocapi_utils import OcapiUtils
|
||||
from ansible.module_utils.common.text.converters import to_native
|
||||
from ansible.module_utils.six.moves.urllib.parse import quote_plus, urljoin
|
||||
|
||||
# More will be added as module features are expanded
|
||||
CATEGORY_COMMANDS_ALL = {
|
||||
"Chassis": ["IndicatorLedOn", "IndicatorLedOff", "PowerModeLow", "PowerModeNormal"],
|
||||
"Systems": ["PowerGracefulRestart"],
|
||||
"Update": ["FWUpload", "FWUpdate", "FWActivate"],
|
||||
"Jobs": ["DeleteJob"]
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
result = {}
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
category=dict(required=True),
|
||||
command=dict(required=True, type='str'),
|
||||
job_name=dict(type='str'),
|
||||
baseuri=dict(required=True, type='str'),
|
||||
proxy_slot_number=dict(type='int'),
|
||||
update_image_path=dict(type='str'),
|
||||
username=dict(required=True),
|
||||
password=dict(required=True, no_log=True),
|
||||
timeout=dict(type='int', default=10)
|
||||
),
|
||||
supports_check_mode=True
|
||||
)
|
||||
|
||||
category = module.params['category']
|
||||
command = module.params['command']
|
||||
|
||||
# admin credentials used for authentication
|
||||
creds = {
|
||||
'user': module.params['username'],
|
||||
'pswd': module.params['password']
|
||||
}
|
||||
|
||||
# timeout
|
||||
timeout = module.params['timeout']
|
||||
|
||||
base_uri = "https://" + module.params["baseuri"]
|
||||
proxy_slot_number = module.params.get("proxy_slot_number")
|
||||
ocapi_utils = OcapiUtils(creds, base_uri, proxy_slot_number, timeout, module)
|
||||
|
||||
# Check that Category is valid
|
||||
if category not in CATEGORY_COMMANDS_ALL:
|
||||
module.fail_json(msg=to_native("Invalid Category '%s'. Valid Categories = %s" % (category, list(CATEGORY_COMMANDS_ALL.keys()))))
|
||||
|
||||
# Check that the command is valid
|
||||
if command not in CATEGORY_COMMANDS_ALL[category]:
|
||||
module.fail_json(msg=to_native("Invalid Command '%s'. Valid Commands = %s" % (command, CATEGORY_COMMANDS_ALL[category])))
|
||||
|
||||
# Organize by Categories / Commands
|
||||
if category == "Chassis":
|
||||
if command.startswith("IndicatorLed"):
|
||||
result = ocapi_utils.manage_chassis_indicator_led(command)
|
||||
elif command.startswith("PowerMode"):
|
||||
result = ocapi_utils.manage_system_power(command)
|
||||
elif category == "Systems":
|
||||
if command.startswith("Power"):
|
||||
result = ocapi_utils.manage_system_power(command)
|
||||
elif category == "Update":
|
||||
if command == "FWUpload":
|
||||
update_image_path = module.params.get("update_image_path")
|
||||
if update_image_path is None:
|
||||
module.fail_json(msg=to_native("Missing update_image_path."))
|
||||
result = ocapi_utils.upload_firmware_image(update_image_path)
|
||||
elif command == "FWUpdate":
|
||||
result = ocapi_utils.update_firmware_image()
|
||||
elif command == "FWActivate":
|
||||
result = ocapi_utils.activate_firmware_image()
|
||||
elif category == "Jobs":
|
||||
if command == "DeleteJob":
|
||||
job_name = module.params.get("job_name")
|
||||
if job_name is None:
|
||||
module.fail_json("Missing job_name")
|
||||
job_uri = urljoin(base_uri, "Jobs/" + job_name)
|
||||
result = ocapi_utils.delete_job(job_uri)
|
||||
|
||||
if result['ret'] is False:
|
||||
module.fail_json(msg=to_native(result['msg']))
|
||||
else:
|
||||
del result['ret']
|
||||
changed = result.get('changed', True)
|
||||
session = result.get('session', dict())
|
||||
kwargs = {
|
||||
"changed": changed,
|
||||
"session": session,
|
||||
"msg": "Action was successful." if not module.check_mode else result.get(
|
||||
"msg", "No action performed in check mode."
|
||||
)
|
||||
}
|
||||
result_keys = [result_key for result_key in result if result_key not in kwargs]
|
||||
for result_key in result_keys:
|
||||
kwargs[result_key] = result[result_key]
|
||||
module.exit_json(**kwargs)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
221
plugins/modules/ocapi_info.py
Normal file
221
plugins/modules/ocapi_info.py
Normal file
@@ -0,0 +1,221 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2022 Western Digital Corporation
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: ocapi_info
|
||||
version_added: 6.3.0
|
||||
short_description: Manages Out-Of-Band controllers using Open Composable API (OCAPI)
|
||||
description:
|
||||
- Builds OCAPI URIs locally and sends them to remote OOB controllers to
|
||||
get information back.
|
||||
options:
|
||||
category:
|
||||
required: true
|
||||
description:
|
||||
- Category to execute on OOB controller.
|
||||
type: str
|
||||
command:
|
||||
required: true
|
||||
description:
|
||||
- Command to execute on OOB controller.
|
||||
type: str
|
||||
baseuri:
|
||||
required: true
|
||||
description:
|
||||
- Base URI of OOB controller.
|
||||
type: str
|
||||
proxy_slot_number:
|
||||
description: For proxied inband requests, the slot number of the IOM. Only applies if I(baseuri) is a proxy server.
|
||||
type: int
|
||||
username:
|
||||
required: true
|
||||
description:
|
||||
- Username for authenticating to OOB controller.
|
||||
type: str
|
||||
password:
|
||||
required: true
|
||||
description:
|
||||
- Password for authenticating to OOB controller.
|
||||
type: str
|
||||
timeout:
|
||||
description:
|
||||
- Timeout in seconds for URL requests to OOB controller.
|
||||
default: 10
|
||||
type: int
|
||||
job_name:
|
||||
description:
|
||||
- Name of job for fetching status.
|
||||
type: str
|
||||
|
||||
|
||||
author: "Mike Moerk (@mikemoerk)"
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Get job status
|
||||
community.general.ocapi_info:
|
||||
category: Status
|
||||
command: JobStatus
|
||||
baseuri: "http://iom1.wdc.com"
|
||||
jobName: FirmwareUpdate
|
||||
username: "{{ username }}"
|
||||
password: "{{ password }}"
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
msg:
|
||||
description: Message with action result or error description.
|
||||
returned: always
|
||||
type: str
|
||||
sample: "Action was successful"
|
||||
|
||||
percentComplete:
|
||||
description: Percent complete of the relevant operation. Applies to C(JobStatus) command.
|
||||
returned: when supported
|
||||
type: int
|
||||
sample: 99
|
||||
|
||||
operationStatus:
|
||||
description: Status of the relevant operation. Applies to C(JobStatus) command. See OCAPI documentation for details.
|
||||
returned: when supported
|
||||
type: str
|
||||
sample: "Activate needed"
|
||||
|
||||
operationStatusId:
|
||||
description: Integer value of status (corresponds to operationStatus). Applies to C(JobStatus) command. See OCAPI documentation for details.
|
||||
returned: when supported
|
||||
type: int
|
||||
sample: 65540
|
||||
|
||||
operationHealth:
|
||||
description: Health of the operation. Applies to C(JobStatus) command. See OCAPI documentation for details.
|
||||
returned: when supported
|
||||
type: str
|
||||
sample: "OK"
|
||||
|
||||
operationHealthId:
|
||||
description: >
|
||||
Integer value for health of the operation (corresponds to C(operationHealth)). Applies to C(JobStatus) command.
|
||||
See OCAPI documentation for details.
|
||||
returned: when supported
|
||||
type: str
|
||||
sample: "OK"
|
||||
|
||||
details:
|
||||
description: Details of the relevant operation. Applies to C(JobStatus) command.
|
||||
returned: when supported
|
||||
type: list
|
||||
elements: str
|
||||
|
||||
status:
|
||||
description: Dict containing status information. See OCAPI documentation for details.
|
||||
returned: when supported
|
||||
type: dict
|
||||
sample: {
|
||||
"Details": [
|
||||
"None"
|
||||
],
|
||||
"Health": [
|
||||
{
|
||||
"ID": 5,
|
||||
"Name": "OK"
|
||||
}
|
||||
],
|
||||
"State": {
|
||||
"ID": 16,
|
||||
"Name": "In service"
|
||||
}
|
||||
}
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.general.plugins.module_utils.ocapi_utils import OcapiUtils
|
||||
from ansible.module_utils.common.text.converters import to_native
|
||||
from ansible.module_utils.six.moves.urllib.parse import quote_plus, urljoin
|
||||
|
||||
# More will be added as module features are expanded
|
||||
CATEGORY_COMMANDS_ALL = {
|
||||
"Jobs": ["JobStatus"]
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
result = {}
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
category=dict(required=True),
|
||||
command=dict(required=True, type='str'),
|
||||
job_name=dict(type='str'),
|
||||
baseuri=dict(required=True, type='str'),
|
||||
proxy_slot_number=dict(type='int'),
|
||||
username=dict(required=True),
|
||||
password=dict(required=True, no_log=True),
|
||||
timeout=dict(type='int', default=10)
|
||||
),
|
||||
supports_check_mode=True
|
||||
)
|
||||
|
||||
category = module.params['category']
|
||||
command = module.params['command']
|
||||
|
||||
# admin credentials used for authentication
|
||||
creds = {
|
||||
'user': module.params['username'],
|
||||
'pswd': module.params['password']
|
||||
}
|
||||
|
||||
# timeout
|
||||
timeout = module.params['timeout']
|
||||
|
||||
base_uri = "https://" + module.params["baseuri"]
|
||||
proxy_slot_number = module.params.get("proxy_slot_number")
|
||||
ocapi_utils = OcapiUtils(creds, base_uri, proxy_slot_number, timeout, module)
|
||||
|
||||
# Check that Category is valid
|
||||
if category not in CATEGORY_COMMANDS_ALL:
|
||||
module.fail_json(msg=to_native("Invalid Category '%s'. Valid Categories = %s" % (category, list(CATEGORY_COMMANDS_ALL.keys()))))
|
||||
|
||||
# Check that the command is valid
|
||||
if command not in CATEGORY_COMMANDS_ALL[category]:
|
||||
module.fail_json(msg=to_native("Invalid Command '%s'. Valid Commands = %s" % (command, CATEGORY_COMMANDS_ALL[category])))
|
||||
|
||||
# Organize by Categories / Commands
|
||||
if category == "Jobs":
|
||||
if command == "JobStatus":
|
||||
if module.params.get("job_name") is None:
|
||||
module.fail_json(msg=to_native(
|
||||
"job_name required for JobStatus command."))
|
||||
job_uri = urljoin(base_uri, 'Jobs/' + module.params["job_name"])
|
||||
result = ocapi_utils.get_job_status(job_uri)
|
||||
|
||||
if result['ret'] is False:
|
||||
module.fail_json(msg=to_native(result['msg']))
|
||||
else:
|
||||
del result['ret']
|
||||
changed = False
|
||||
session = result.get('session', dict())
|
||||
kwargs = {
|
||||
"changed": changed,
|
||||
"session": session,
|
||||
"msg": "Action was successful." if not module.check_mode else result.get(
|
||||
"msg", "No action performed in check mode."
|
||||
)
|
||||
}
|
||||
result_keys = [result_key for result_key in result if result_key not in kwargs]
|
||||
for result_key in result_keys:
|
||||
kwargs[result_key] = result[result_key]
|
||||
module.exit_json(**kwargs)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -196,6 +196,13 @@ options:
|
||||
- Name of Datastore to use to create a new instace
|
||||
version_added: '0.2.0'
|
||||
type: str
|
||||
updateconf:
|
||||
description:
|
||||
- When I(instance_ids) is provided, updates running VMs with the C(updateconf) API call.
|
||||
- When new VMs are being created, emulates the C(updateconf) API call via direct template merge.
|
||||
- Allows for complete modifications of the C(CONTEXT) attribute.
|
||||
type: dict
|
||||
version_added: 6.3.0
|
||||
author:
|
||||
- "Milan Ilic (@ilicmilan)"
|
||||
- "Jan Meerkamp (@meerkampdvv)"
|
||||
@@ -403,6 +410,30 @@ EXAMPLES = '''
|
||||
disk_saveas:
|
||||
name: bar-image
|
||||
disk_id: 1
|
||||
|
||||
- name: "Deploy 2 new instances with a custom 'start script'"
|
||||
community.general.one_vm:
|
||||
template_name: app_template
|
||||
count: 2
|
||||
updateconf:
|
||||
CONTEXT:
|
||||
START_SCRIPT: ip r r 169.254.16.86/32 dev eth0
|
||||
|
||||
- name: "Add a custom 'start script' to a running VM"
|
||||
community.general.one_vm:
|
||||
instance_ids: 351
|
||||
updateconf:
|
||||
CONTEXT:
|
||||
START_SCRIPT: ip r r 169.254.16.86/32 dev eth0
|
||||
|
||||
- name: "Update SSH public keys inside the VM's context"
|
||||
community.general.one_vm:
|
||||
instance_ids: 351
|
||||
updateconf:
|
||||
CONTEXT:
|
||||
SSH_PUBLIC_KEY: |-
|
||||
ssh-rsa ...
|
||||
ssh-ed25519 ...
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
@@ -510,6 +541,17 @@ instances:
|
||||
"TE_GALAXY": "bar",
|
||||
"USER_INPUTS": null
|
||||
}
|
||||
updateconf:
|
||||
description: A dictionary of key/values attributes that are set with the updateconf API call.
|
||||
type: dict
|
||||
version_added: 6.3.0
|
||||
sample: {
|
||||
"OS": { "ARCH": "x86_64" },
|
||||
"CONTEXT": {
|
||||
"START_SCRIPT": "ip r r 169.254.16.86/32 dev eth0",
|
||||
"SSH_PUBLIC_KEY": "ssh-rsa ...\\nssh-ed25519 ..."
|
||||
}
|
||||
}
|
||||
tagged_instances:
|
||||
description:
|
||||
- A list of instances info based on a specific attributes and/or
|
||||
@@ -615,6 +657,17 @@ tagged_instances:
|
||||
"TE_GALAXY": "bar",
|
||||
"USER_INPUTS": null
|
||||
}
|
||||
updateconf:
|
||||
description: A dictionary of key/values attributes that are set with the updateconf API call
|
||||
type: dict
|
||||
version_added: 6.3.0
|
||||
sample: {
|
||||
"OS": { "ARCH": "x86_64" },
|
||||
"CONTEXT": {
|
||||
"START_SCRIPT": "ip r r 169.254.16.86/32 dev eth0",
|
||||
"SSH_PUBLIC_KEY": "ssh-rsa ...\\nssh-ed25519 ..."
|
||||
}
|
||||
}
|
||||
'''
|
||||
|
||||
try:
|
||||
@@ -623,9 +676,52 @@ try:
|
||||
except ImportError:
|
||||
HAS_PYONE = False
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
import os
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.common.dict_transformations import dict_merge
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.opennebula import flatten, render
|
||||
|
||||
|
||||
UPDATECONF_ATTRIBUTES = {
|
||||
"OS": ["ARCH", "MACHINE", "KERNEL", "INITRD", "BOOTLOADER", "BOOT", "SD_DISK_BUS", "UUID"],
|
||||
"FEATURES": ["ACPI", "PAE", "APIC", "LOCALTIME", "HYPERV", "GUEST_AGENT"],
|
||||
"INPUT": ["TYPE", "BUS"],
|
||||
"GRAPHICS": ["TYPE", "LISTEN", "PASSWD", "KEYMAP"],
|
||||
"RAW": ["DATA", "DATA_VMX", "TYPE"],
|
||||
"CONTEXT": [],
|
||||
}
|
||||
|
||||
|
||||
def check_updateconf(module, to_check):
|
||||
'''Checks if attributes are compatible with one.vm.updateconf API call.'''
|
||||
for attr, subattributes in to_check.items():
|
||||
if attr not in UPDATECONF_ATTRIBUTES:
|
||||
module.fail_json(msg="'{0:}' is not a valid VM attribute.".format(attr))
|
||||
if not UPDATECONF_ATTRIBUTES[attr]:
|
||||
continue
|
||||
for subattr in subattributes:
|
||||
if subattr not in UPDATECONF_ATTRIBUTES[attr]:
|
||||
module.fail_json(msg="'{0:}' is not a valid VM subattribute of '{1:}'".format(subattr, attr))
|
||||
|
||||
|
||||
def parse_updateconf(vm_template):
|
||||
'''Extracts 'updateconf' attributes from a VM template.'''
|
||||
updateconf = {}
|
||||
for attr, subattributes in vm_template.items():
|
||||
if attr not in UPDATECONF_ATTRIBUTES:
|
||||
continue
|
||||
tmp = {}
|
||||
for subattr, value in subattributes.items():
|
||||
if UPDATECONF_ATTRIBUTES[attr] and subattr not in UPDATECONF_ATTRIBUTES[attr]:
|
||||
continue
|
||||
tmp[subattr] = value
|
||||
if tmp:
|
||||
updateconf[attr] = tmp
|
||||
return updateconf
|
||||
|
||||
|
||||
def get_template(module, client, predicate):
|
||||
|
||||
@@ -767,6 +863,8 @@ def get_vm_info(client, vm):
|
||||
|
||||
vm_labels, vm_attributes = get_vm_labels_and_attributes_dict(client, vm.ID)
|
||||
|
||||
updateconf = parse_updateconf(vm.TEMPLATE)
|
||||
|
||||
info = {
|
||||
'template_id': int(vm.TEMPLATE['TEMPLATE_ID']),
|
||||
'vm_id': vm.ID,
|
||||
@@ -785,7 +883,8 @@ def get_vm_info(client, vm):
|
||||
'uptime_h': int(vm_uptime),
|
||||
'attributes': vm_attributes,
|
||||
'mode': permissions_str,
|
||||
'labels': vm_labels
|
||||
'labels': vm_labels,
|
||||
'updateconf': updateconf,
|
||||
}
|
||||
|
||||
return info
|
||||
@@ -844,6 +943,28 @@ def set_vm_ownership(module, client, vms, owner_id, group_id):
|
||||
return changed
|
||||
|
||||
|
||||
def update_vm(module, client, vm, updateconf_dict):
|
||||
changed = False
|
||||
if not updateconf_dict:
|
||||
return changed
|
||||
|
||||
before = client.vm.info(vm.ID).TEMPLATE
|
||||
|
||||
client.vm.updateconf(vm.ID, render(updateconf_dict), 1) # 1: Merge new template with the existing one.
|
||||
|
||||
after = client.vm.info(vm.ID).TEMPLATE
|
||||
|
||||
changed = before != after
|
||||
return changed
|
||||
|
||||
|
||||
def update_vms(module, client, vms, *args):
|
||||
changed = False
|
||||
for vm in vms:
|
||||
changed = update_vm(module, client, vm, *args) or changed
|
||||
return changed
|
||||
|
||||
|
||||
def get_size_in_MB(module, size_str):
|
||||
|
||||
SYMBOLS = ['B', 'KB', 'MB', 'GB', 'TB']
|
||||
@@ -871,81 +992,46 @@ def get_size_in_MB(module, size_str):
|
||||
return size_in_MB
|
||||
|
||||
|
||||
def create_disk_str(module, client, template_id, disk_size_list):
|
||||
|
||||
if not disk_size_list:
|
||||
return ''
|
||||
|
||||
template = client.template.info(template_id)
|
||||
if isinstance(template.TEMPLATE['DISK'], list):
|
||||
# check if the number of disks is correct
|
||||
if len(template.TEMPLATE['DISK']) != len(disk_size_list):
|
||||
module.fail_json(msg='This template has ' + str(len(template.TEMPLATE['DISK'])) + ' disks but you defined ' + str(len(disk_size_list)))
|
||||
result = ''
|
||||
index = 0
|
||||
for DISKS in template.TEMPLATE['DISK']:
|
||||
disk = {}
|
||||
diskresult = ''
|
||||
# Get all info about existed disk e.g. IMAGE_ID,...
|
||||
for key, value in DISKS.items():
|
||||
disk[key] = value
|
||||
# copy disk attributes if it is not the size attribute
|
||||
diskresult += 'DISK = [' + ','.join('{key}="{val}"'.format(key=key, val=val) for key, val in disk.items() if key != 'SIZE')
|
||||
# Set the Disk Size
|
||||
diskresult += ', SIZE=' + str(int(get_size_in_MB(module, disk_size_list[index]))) + ']\n'
|
||||
result += diskresult
|
||||
index += 1
|
||||
else:
|
||||
if len(disk_size_list) > 1:
|
||||
module.fail_json(msg='This template has one disk but you defined ' + str(len(disk_size_list)))
|
||||
disk = {}
|
||||
# Get all info about existed disk e.g. IMAGE_ID,...
|
||||
for key, value in template.TEMPLATE['DISK'].items():
|
||||
disk[key] = value
|
||||
# copy disk attributes if it is not the size attribute
|
||||
result = 'DISK = [' + ','.join('{key}="{val}"'.format(key=key, val=val) for key, val in disk.items() if key != 'SIZE')
|
||||
# Set the Disk Size
|
||||
result += ', SIZE=' + str(int(get_size_in_MB(module, disk_size_list[0]))) + ']\n'
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def create_attributes_str(attributes_dict, labels_list):
|
||||
|
||||
attributes_str = ''
|
||||
|
||||
if labels_list:
|
||||
attributes_str += 'LABELS="' + ','.join('{label}'.format(label=label) for label in labels_list) + '"\n'
|
||||
if attributes_dict:
|
||||
attributes_str += '\n'.join('{key}="{val}"'.format(key=key.upper(), val=val) for key, val in attributes_dict.items()) + '\n'
|
||||
|
||||
return attributes_str
|
||||
|
||||
|
||||
def create_nics_str(network_attrs_list):
|
||||
nics_str = ''
|
||||
|
||||
for network in network_attrs_list:
|
||||
# Packing key-value dict in string with format key="value", key="value"
|
||||
network_str = ','.join('{key}="{val}"'.format(key=key, val=val) for key, val in network.items())
|
||||
nics_str = nics_str + 'NIC = [' + network_str + ']\n'
|
||||
|
||||
return nics_str
|
||||
|
||||
|
||||
def create_vm(module, client, template_id, attributes_dict, labels_list, disk_size, network_attrs_list, vm_start_on_hold, vm_persistent):
|
||||
|
||||
def create_vm(module, client, template_id, attributes_dict, labels_list, disk_size, network_attrs_list, vm_start_on_hold, vm_persistent, updateconf_dict):
|
||||
if attributes_dict:
|
||||
vm_name = attributes_dict.get('NAME', '')
|
||||
|
||||
disk_str = create_disk_str(module, client, template_id, disk_size)
|
||||
vm_extra_template_str = create_attributes_str(attributes_dict, labels_list) + create_nics_str(network_attrs_list) + disk_str
|
||||
template = client.template.info(template_id).TEMPLATE
|
||||
|
||||
disk_count = len(flatten(template.get('DISK', [])))
|
||||
if disk_size:
|
||||
size_count = len(flatten(disk_size))
|
||||
# check if the number of disks is correct
|
||||
if disk_count != size_count:
|
||||
module.fail_json(msg='This template has ' + str(disk_count) + ' disks but you defined ' + str(size_count))
|
||||
|
||||
vm_extra_template = dict_merge(template or {}, attributes_dict or {})
|
||||
vm_extra_template = dict_merge(vm_extra_template, {
|
||||
'LABELS': ','.join(labels_list),
|
||||
'NIC': flatten(network_attrs_list, extract=True),
|
||||
'DISK': flatten([
|
||||
disk if not size else dict_merge(disk, {
|
||||
'SIZE': str(int(get_size_in_MB(module, size))),
|
||||
})
|
||||
for disk, size in zip(
|
||||
flatten(template.get('DISK', [])),
|
||||
flatten(disk_size or [None] * disk_count),
|
||||
)
|
||||
if disk is not None
|
||||
], extract=True)
|
||||
})
|
||||
vm_extra_template = dict_merge(vm_extra_template, updateconf_dict or {})
|
||||
|
||||
try:
|
||||
vm_id = client.template.instantiate(template_id, vm_name, vm_start_on_hold, vm_extra_template_str, vm_persistent)
|
||||
vm_id = client.template.instantiate(template_id,
|
||||
vm_name,
|
||||
vm_start_on_hold,
|
||||
render(vm_extra_template),
|
||||
vm_persistent)
|
||||
except pyone.OneException as e:
|
||||
module.fail_json(msg=str(e))
|
||||
vm = get_vm_by_id(client, vm_id)
|
||||
|
||||
vm = get_vm_by_id(client, vm_id)
|
||||
return get_vm_info(client, vm)
|
||||
|
||||
|
||||
@@ -1028,8 +1114,10 @@ def get_all_vms_by_attributes(client, attributes_dict, labels_list):
|
||||
return vm_list
|
||||
|
||||
|
||||
def create_count_of_vms(
|
||||
module, client, template_id, count, attributes_dict, labels_list, disk_size, network_attrs_list, wait, wait_timeout, vm_start_on_hold, vm_persistent):
|
||||
def create_count_of_vms(module, client,
|
||||
template_id, count,
|
||||
attributes_dict, labels_list, disk_size, network_attrs_list,
|
||||
wait, wait_timeout, vm_start_on_hold, vm_persistent, updateconf_dict):
|
||||
new_vms_list = []
|
||||
|
||||
vm_name = ''
|
||||
@@ -1058,7 +1146,9 @@ def create_count_of_vms(
|
||||
new_vm_name += next_index
|
||||
# Update NAME value in the attributes in case there is index
|
||||
attributes_dict['NAME'] = new_vm_name
|
||||
new_vm_dict = create_vm(module, client, template_id, attributes_dict, labels_list, disk_size, network_attrs_list, vm_start_on_hold, vm_persistent)
|
||||
new_vm_dict = create_vm(module, client,
|
||||
template_id, attributes_dict, labels_list, disk_size, network_attrs_list,
|
||||
vm_start_on_hold, vm_persistent, updateconf_dict)
|
||||
new_vm_id = new_vm_dict.get('vm_id')
|
||||
new_vm = get_vm_by_id(client, new_vm_id)
|
||||
new_vms_list.append(new_vm)
|
||||
@@ -1076,9 +1166,10 @@ def create_count_of_vms(
|
||||
return True, new_vms_list, []
|
||||
|
||||
|
||||
def create_exact_count_of_vms(module, client, template_id, exact_count, attributes_dict, count_attributes_dict,
|
||||
labels_list, count_labels_list, disk_size, network_attrs_list, hard, wait, wait_timeout, vm_start_on_hold, vm_persistent):
|
||||
|
||||
def create_exact_count_of_vms(module, client,
|
||||
template_id, exact_count, attributes_dict, count_attributes_dict,
|
||||
labels_list, count_labels_list, disk_size, network_attrs_list,
|
||||
hard, wait, wait_timeout, vm_start_on_hold, vm_persistent, updateconf_dict):
|
||||
vm_list = get_all_vms_by_attributes(client, count_attributes_dict, count_labels_list)
|
||||
|
||||
vm_count_diff = exact_count - len(vm_list)
|
||||
@@ -1095,7 +1186,7 @@ def create_exact_count_of_vms(module, client, template_id, exact_count, attribut
|
||||
# Add more VMs
|
||||
changed, instances_list, tagged_instances = create_count_of_vms(module, client, template_id, vm_count_diff, attributes_dict,
|
||||
labels_list, disk_size, network_attrs_list, wait, wait_timeout,
|
||||
vm_start_on_hold, vm_persistent)
|
||||
vm_start_on_hold, vm_persistent, updateconf_dict)
|
||||
|
||||
tagged_instances_list += instances_list
|
||||
elif vm_count_diff < 0:
|
||||
@@ -1398,7 +1489,8 @@ def main():
|
||||
"labels": {"default": [], "type": "list", "elements": "str"},
|
||||
"count_labels": {"required": False, "type": "list", "elements": "str"},
|
||||
"disk_saveas": {"type": "dict"},
|
||||
"persistent": {"default": False, "type": "bool"}
|
||||
"persistent": {"default": False, "type": "bool"},
|
||||
"updateconf": {"type": "dict"},
|
||||
}
|
||||
|
||||
module = AnsibleModule(argument_spec=fields,
|
||||
@@ -1452,6 +1544,7 @@ def main():
|
||||
count_labels = params.get('count_labels')
|
||||
disk_saveas = params.get('disk_saveas')
|
||||
persistent = params.get('persistent')
|
||||
updateconf = params.get('updateconf')
|
||||
|
||||
if not (auth.username and auth.password):
|
||||
module.warn("Credentials missing")
|
||||
@@ -1470,6 +1563,9 @@ def main():
|
||||
attributes = copy.copy(count_attributes)
|
||||
check_attributes(module, count_attributes)
|
||||
|
||||
if updateconf:
|
||||
check_updateconf(module, updateconf)
|
||||
|
||||
if count_labels and not labels:
|
||||
module.warn('When you pass `count_labels` without `labels` option when deploying, `labels` option will have same values implicitly.')
|
||||
labels = count_labels
|
||||
@@ -1529,13 +1625,13 @@ def main():
|
||||
# Deploy an exact count of VMs
|
||||
changed, instances_list, tagged_instances_list = create_exact_count_of_vms(module, one_client, template_id, exact_count, attributes,
|
||||
count_attributes, labels, count_labels, disk_size,
|
||||
networks, hard, wait, wait_timeout, put_vm_on_hold, persistent)
|
||||
networks, hard, wait, wait_timeout, put_vm_on_hold, persistent, updateconf)
|
||||
vms = tagged_instances_list
|
||||
elif template_id is not None and state == 'present':
|
||||
# Deploy count VMs
|
||||
changed, instances_list, tagged_instances_list = create_count_of_vms(module, one_client, template_id, count,
|
||||
attributes, labels, disk_size, networks, wait, wait_timeout,
|
||||
put_vm_on_hold, persistent)
|
||||
put_vm_on_hold, persistent, updateconf)
|
||||
# instances_list - new instances
|
||||
# tagged_instances_list - all instances with specified `count_attributes` and `count_labels`
|
||||
vms = instances_list
|
||||
@@ -1587,6 +1683,9 @@ def main():
|
||||
if owner_id is not None or group_id is not None:
|
||||
changed = set_vm_ownership(module, one_client, vms, owner_id, group_id) or changed
|
||||
|
||||
if template_id is None and updateconf is not None:
|
||||
changed = update_vms(module, one_client, vms, updateconf) or changed
|
||||
|
||||
if wait and not module.check_mode and state != 'present':
|
||||
wait_for = {
|
||||
'absent': wait_for_done,
|
||||
|
||||
@@ -15,13 +15,17 @@ DOCUMENTATION = '''
|
||||
---
|
||||
module: opkg
|
||||
author: "Patrick Pelletier (@skinp)"
|
||||
short_description: Package manager for OpenWrt
|
||||
short_description: Package manager for OpenWrt and Openembedded/Yocto based Linux distributions
|
||||
description:
|
||||
- Manages OpenWrt packages
|
||||
- Manages ipk packages for OpenWrt and Openembedded/Yocto based Linux distributions
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Name of package(s) to install/remove.
|
||||
- C(NAME=VERSION) syntax is also supported to install a package
|
||||
in a certain version. See the examples. This only works on Yocto based
|
||||
Linux distributions (opkg>=0.3.2) and not for OpenWrt. This is
|
||||
supported since community.general 6.2.0.
|
||||
aliases: [pkg]
|
||||
required: true
|
||||
type: list
|
||||
@@ -64,6 +68,11 @@ EXAMPLES = '''
|
||||
name: foo
|
||||
state: present
|
||||
|
||||
- name: Install foo in version 1.2 (opkg>=0.3.2 on Yocto based Linux distributions)
|
||||
community.general.opkg:
|
||||
name: foo=1.2
|
||||
state: present
|
||||
|
||||
- name: Update cache and install foo
|
||||
community.general.opkg:
|
||||
name: foo
|
||||
@@ -89,112 +98,106 @@ EXAMPLES = '''
|
||||
force: overwrite
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.six.moves import shlex_quote
|
||||
from ansible_collections.community.general.plugins.module_utils.cmd_runner import CmdRunner, cmd_runner_fmt
|
||||
from ansible_collections.community.general.plugins.module_utils.module_helper import StateModuleHelper
|
||||
|
||||
|
||||
def update_package_db(module, opkg_path):
|
||||
""" Updates packages list. """
|
||||
|
||||
rc, out, err = module.run_command("%s update" % opkg_path)
|
||||
|
||||
if rc != 0:
|
||||
module.fail_json(msg="could not update package db")
|
||||
|
||||
|
||||
def query_package(module, opkg_path, name, state="present"):
|
||||
""" Returns whether a package is installed or not. """
|
||||
|
||||
if state == "present":
|
||||
|
||||
rc, out, err = module.run_command("%s list-installed | grep -q \"^%s \"" % (shlex_quote(opkg_path), shlex_quote(name)), use_unsafe_shell=True)
|
||||
if rc == 0:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def remove_packages(module, opkg_path, packages):
|
||||
""" Uninstalls one or more packages if installed. """
|
||||
|
||||
p = module.params
|
||||
force = p["force"]
|
||||
if force:
|
||||
force = "--force-%s" % force
|
||||
|
||||
remove_c = 0
|
||||
# Using a for loop in case of error, we can report the package that failed
|
||||
for package in packages:
|
||||
# Query the package first, to see if we even need to remove
|
||||
if not query_package(module, opkg_path, package):
|
||||
continue
|
||||
|
||||
rc, out, err = module.run_command("%s remove %s %s" % (opkg_path, force, package))
|
||||
|
||||
if query_package(module, opkg_path, package):
|
||||
module.fail_json(msg="failed to remove %s: %s" % (package, out))
|
||||
|
||||
remove_c += 1
|
||||
|
||||
if remove_c > 0:
|
||||
|
||||
module.exit_json(changed=True, msg="removed %s package(s)" % remove_c)
|
||||
|
||||
module.exit_json(changed=False, msg="package(s) already absent")
|
||||
|
||||
|
||||
def install_packages(module, opkg_path, packages):
|
||||
""" Installs one or more packages if not already installed. """
|
||||
|
||||
p = module.params
|
||||
force = p["force"]
|
||||
if force:
|
||||
force = "--force-%s" % force
|
||||
|
||||
install_c = 0
|
||||
|
||||
for package in packages:
|
||||
if query_package(module, opkg_path, package):
|
||||
continue
|
||||
|
||||
rc, out, err = module.run_command("%s install %s %s" % (opkg_path, force, package))
|
||||
|
||||
if not query_package(module, opkg_path, package):
|
||||
module.fail_json(msg="failed to install %s: %s" % (package, out))
|
||||
|
||||
install_c += 1
|
||||
|
||||
if install_c > 0:
|
||||
module.exit_json(changed=True, msg="installed %s package(s)" % (install_c))
|
||||
|
||||
module.exit_json(changed=False, msg="package(s) already present")
|
||||
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
class Opkg(StateModuleHelper):
|
||||
module = dict(
|
||||
argument_spec=dict(
|
||||
name=dict(aliases=["pkg"], required=True, type="list", elements="str"),
|
||||
state=dict(default="present", choices=["present", "installed", "absent", "removed"]),
|
||||
force=dict(default="", choices=["", "depends", "maintainer", "reinstall", "overwrite", "downgrade", "space", "postinstall", "remove",
|
||||
"checksum", "removal-of-dependent-packages"]),
|
||||
update_cache=dict(default=False, type='bool'),
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
opkg_path = module.get_bin_path('opkg', True, ['/bin'])
|
||||
def __init_module__(self):
|
||||
self.vars.set("install_c", 0, output=False, change=True)
|
||||
self.vars.set("remove_c", 0, output=False, change=True)
|
||||
|
||||
p = module.params
|
||||
state_map = dict(
|
||||
query="list-installed",
|
||||
present="install",
|
||||
installed="install",
|
||||
absent="remove",
|
||||
removed="remove",
|
||||
)
|
||||
|
||||
if p["update_cache"]:
|
||||
update_package_db(module, opkg_path)
|
||||
def _force(value):
|
||||
if value == "":
|
||||
value = None
|
||||
return cmd_runner_fmt.as_optval("--force-")(value, ctx_ignore_none=True)
|
||||
|
||||
pkgs = p["name"]
|
||||
self.runner = CmdRunner(
|
||||
self.module,
|
||||
command="opkg",
|
||||
arg_formats=dict(
|
||||
package=cmd_runner_fmt.as_list(),
|
||||
state=cmd_runner_fmt.as_map(state_map),
|
||||
force=cmd_runner_fmt.as_func(_force),
|
||||
update_cache=cmd_runner_fmt.as_bool("update")
|
||||
),
|
||||
)
|
||||
|
||||
if p["state"] in ["present", "installed"]:
|
||||
install_packages(module, opkg_path, pkgs)
|
||||
@staticmethod
|
||||
def split_name_and_version(package):
|
||||
""" Split the name and the version when using the NAME=VERSION syntax """
|
||||
splitted = package.split('=', 1)
|
||||
if len(splitted) == 1:
|
||||
return splitted[0], None
|
||||
else:
|
||||
return splitted[0], splitted[1]
|
||||
|
||||
elif p["state"] in ["absent", "removed"]:
|
||||
remove_packages(module, opkg_path, pkgs)
|
||||
def _package_in_desired_state(self, name, want_installed, version=None):
|
||||
dummy, out, dummy = self.runner("state package").run(state="query", package=name)
|
||||
|
||||
has_package = out.startswith(name + " - %s" % ("" if not version else (version + " ")))
|
||||
return want_installed == has_package
|
||||
|
||||
def state_present(self):
|
||||
if self.vars.update_cache:
|
||||
dummy, rc, dummy = self.runner("update_cache").run()
|
||||
if rc != 0:
|
||||
self.do_raise("could not update package db")
|
||||
with self.runner("state force package") as ctx:
|
||||
for package in self.vars.name:
|
||||
pkg_name, pkg_version = self.split_name_and_version(package)
|
||||
if not self._package_in_desired_state(pkg_name, want_installed=True, version=pkg_version) or self.vars.force == "reinstall":
|
||||
ctx.run(package=package)
|
||||
if not self._package_in_desired_state(pkg_name, want_installed=True, version=pkg_version):
|
||||
self.do_raise("failed to install %s" % package)
|
||||
self.vars.install_c += 1
|
||||
if self.vars.install_c > 0:
|
||||
self.vars.msg = "installed %s package(s)" % (self.vars.install_c)
|
||||
else:
|
||||
self.vars.msg = "package(s) already present"
|
||||
|
||||
def state_absent(self):
|
||||
if self.vars.update_cache:
|
||||
dummy, rc, dummy = self.runner("update_cache").run()
|
||||
if rc != 0:
|
||||
self.do_raise("could not update package db")
|
||||
with self.runner("state force package") as ctx:
|
||||
for package in self.vars.name:
|
||||
package, dummy = self.split_name_and_version(package)
|
||||
if not self._package_in_desired_state(package, want_installed=False):
|
||||
ctx.run(package=package)
|
||||
if not self._package_in_desired_state(package, want_installed=False):
|
||||
self.do_raise("failed to remove %s" % package)
|
||||
self.vars.remove_c += 1
|
||||
if self.vars.remove_c > 0:
|
||||
self.vars.msg = "removed %s package(s)" % (self.vars.remove_c)
|
||||
else:
|
||||
self.vars.msg = "package(s) already absent"
|
||||
|
||||
state_installed = state_present
|
||||
state_removed = state_absent
|
||||
|
||||
|
||||
def main():
|
||||
Opkg.execute()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -95,6 +95,9 @@ options:
|
||||
notes:
|
||||
- This module does not install the C(pipx) python package, however that can be easily done with the module M(ansible.builtin.pip).
|
||||
- This module does not require C(pipx) to be in the shell C(PATH), but it must be loadable by Python as a module.
|
||||
- >
|
||||
This module will honor C(pipx) environment variables such as but not limited to C(PIPX_HOME) and C(PIPX_BIN_DIR)
|
||||
passed using the R(environment Ansible keyword, playbooks_environment).
|
||||
- Please note that C(pipx) requires Python 3.6 or above.
|
||||
- >
|
||||
This first implementation does not verify whether a specified version constraint has been installed or not.
|
||||
|
||||
@@ -50,6 +50,9 @@ options:
|
||||
notes:
|
||||
- This module does not install the C(pipx) python package, however that can be easily done with the module M(ansible.builtin.pip).
|
||||
- This module does not require C(pipx) to be in the shell C(PATH), but it must be loadable by Python as a module.
|
||||
- >
|
||||
This module will honor C(pipx) environment variables such as but not limited to C(PIPX_HOME) and C(PIPX_BIN_DIR)
|
||||
passed using the R(environment Ansible keyword, playbooks_environment).
|
||||
- Please note that C(pipx) requires Python 3.6 or above.
|
||||
- See also the C(pipx) documentation at U(https://pypa.github.io/pipx/).
|
||||
author:
|
||||
|
||||
@@ -106,6 +106,14 @@ options:
|
||||
description:
|
||||
- sets DNS search domain for a container
|
||||
type: str
|
||||
tags:
|
||||
description:
|
||||
- List of tags to apply to the container.
|
||||
- Tags must start with C([a-z0-9_]) followed by zero or more of the following characters C([a-z0-9_-+.]).
|
||||
- Tags are only available in Proxmox 7+.
|
||||
type: list
|
||||
elements: str
|
||||
version_added: 6.2.0
|
||||
timeout:
|
||||
description:
|
||||
- timeout for operations
|
||||
@@ -391,6 +399,7 @@ EXAMPLES = r'''
|
||||
state: absent
|
||||
'''
|
||||
|
||||
import re
|
||||
import time
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
|
||||
@@ -415,11 +424,25 @@ class ProxmoxLxcAnsible(ProxmoxAnsible):
|
||||
return config['template']
|
||||
|
||||
def create_instance(self, vmid, node, disk, storage, cpus, memory, swap, timeout, clone, **kwargs):
|
||||
|
||||
# Version limited features
|
||||
minimum_version = {
|
||||
'tags': 7,
|
||||
}
|
||||
proxmox_node = self.proxmox_api.nodes(node)
|
||||
|
||||
# Remove all empty kwarg entries
|
||||
kwargs = dict((k, v) for k, v in kwargs.items() if v is not None)
|
||||
|
||||
version = self.version()
|
||||
pve_major_version = 3 if version < LooseVersion('4.0') else version.version[0]
|
||||
|
||||
# Fail on unsupported features
|
||||
for option, version in minimum_version.items():
|
||||
if pve_major_version < version and option in kwargs:
|
||||
self.module.fail_json(changed=False, msg="Feature {option} is only supported in PVE {version}+, and you're using PVE {pve_major_version}".
|
||||
format(option=option, version=version, pve_major_version=pve_major_version))
|
||||
|
||||
if VZ_TYPE == 'lxc':
|
||||
kwargs['cpulimit'] = cpus
|
||||
kwargs['rootfs'] = disk
|
||||
@@ -437,6 +460,14 @@ class ProxmoxLxcAnsible(ProxmoxAnsible):
|
||||
kwargs['cpus'] = cpus
|
||||
kwargs['disk'] = disk
|
||||
|
||||
# LXC tags are expected to be valid and presented as a comma/semi-colon delimited string
|
||||
if 'tags' in kwargs:
|
||||
re_tag = re.compile(r'^[a-z0-9_][a-z0-9_\-\+\.]*$')
|
||||
for tag in kwargs['tags']:
|
||||
if not re_tag.match(tag):
|
||||
self.module.fail_json(msg='%s is not a valid tag' % tag)
|
||||
kwargs['tags'] = ",".join(kwargs['tags'])
|
||||
|
||||
if clone is not None:
|
||||
if VZ_TYPE != 'lxc':
|
||||
self.module.fail_json(changed=False, msg="Clone operator is only supported for LXC enabled proxmox clusters.")
|
||||
@@ -569,6 +600,7 @@ def main():
|
||||
proxmox_default_behavior=dict(type='str', default='no_defaults', choices=['compatibility', 'no_defaults']),
|
||||
clone=dict(type='int'),
|
||||
clone_type=dict(default='opportunistic', choices=['full', 'linked', 'opportunistic']),
|
||||
tags=dict(type='list', elements='str')
|
||||
)
|
||||
module_args.update(proxmox_args)
|
||||
|
||||
@@ -674,7 +706,8 @@ def main():
|
||||
features=",".join(module.params['features']) if module.params['features'] is not None else None,
|
||||
unprivileged=ansible_to_proxmox_bool(module.params['unprivileged']),
|
||||
description=module.params['description'],
|
||||
hookscript=module.params['hookscript'])
|
||||
hookscript=module.params['hookscript'],
|
||||
tags=module.params['tags'])
|
||||
|
||||
module.exit_json(changed=True, msg="Deployed VM %s from template %s" % (vmid, module.params['ostemplate']))
|
||||
except Exception as e:
|
||||
|
||||
@@ -104,6 +104,7 @@ options:
|
||||
- Move the disk to this storage when I(state=moved).
|
||||
- You can move between storages only in scope of one VM.
|
||||
- Mutually exclusive with I(target_vmid).
|
||||
- Consider increasing I(timeout) in case of large disk images or slow storage backend.
|
||||
type: str
|
||||
target_vmid:
|
||||
description:
|
||||
@@ -113,8 +114,8 @@ options:
|
||||
type: int
|
||||
timeout:
|
||||
description:
|
||||
- Timeout in seconds to wait when moving disk.
|
||||
- Used only when I(state=moved).
|
||||
- Timeout in seconds to wait for slow operations such as importing disk or moving disk between storages.
|
||||
- Used only when I(state) is C(present) or C(moved).
|
||||
type: int
|
||||
default: 600
|
||||
aio:
|
||||
@@ -172,6 +173,7 @@ options:
|
||||
- C(<STORAGE>:<VMID>/<FULL_NAME>) or C(<ABSOLUTE_PATH>/<FULL_NAME>)
|
||||
- Attention! Only root can use absolute paths.
|
||||
- This parameter is mutually exclusive with I(size).
|
||||
- Increase I(timeout) parameter when importing large disk images or using slow storage.
|
||||
type: str
|
||||
iops:
|
||||
description:
|
||||
@@ -471,6 +473,16 @@ class ProxmoxDiskAnsible(ProxmoxAnsible):
|
||||
params.update(dict((k, int(v)) for k, v in params.items() if isinstance(v, bool)))
|
||||
return params
|
||||
|
||||
def wait_till_complete_or_timeout(self, node_name, task_id):
|
||||
timeout = self.module.params['timeout']
|
||||
while timeout:
|
||||
if self.api_task_ok(node_name, task_id):
|
||||
return True
|
||||
timeout -= 1
|
||||
if timeout <= 0:
|
||||
return False
|
||||
sleep(1)
|
||||
|
||||
def create_disk(self, disk, vmid, vm, vm_config):
|
||||
create = self.module.params['create']
|
||||
if create == 'disabled' and disk not in vm_config:
|
||||
@@ -484,20 +496,23 @@ class ProxmoxDiskAnsible(ProxmoxAnsible):
|
||||
|
||||
if import_string:
|
||||
config_str = "%s:%s,import-from=%s" % (self.module.params["storage"], "0", import_string)
|
||||
timeout_str = "Reached timeout while importing VM disk. Last line in task before timeout: %s"
|
||||
ok_str = "Disk %s imported into VM %s"
|
||||
else:
|
||||
config_str = "%s:%s" % (self.module.params["storage"], self.module.params["size"])
|
||||
ok_str = "Disk %s created in VM %s"
|
||||
timeout_str = "Reached timeout while creating VM disk. Last line in task before timeout: %s"
|
||||
|
||||
for k, v in attributes.items():
|
||||
config_str += ',%s=%s' % (k, v)
|
||||
|
||||
create_disk = {self.module.params["disk"]: config_str}
|
||||
self.proxmox_api.nodes(vm['node']).qemu(vmid).config.set(**create_disk)
|
||||
return True, "Disk %s created in VM %s" % (disk, vmid)
|
||||
disk_config_to_apply = {self.module.params["disk"]: config_str}
|
||||
|
||||
if create in ['disabled', 'regular'] and disk in vm_config:
|
||||
# UPDATE
|
||||
disk_config = disk_conf_str_to_dict(vm_config[disk])
|
||||
config_str = disk_config["volume"]
|
||||
ok_str = "Disk %s updated in VM %s"
|
||||
attributes = self.get_create_attributes()
|
||||
# 'import_from' fails on disk updates
|
||||
attributes.pop('import_from', None)
|
||||
@@ -513,9 +528,16 @@ class ProxmoxDiskAnsible(ProxmoxAnsible):
|
||||
if disk_config == attributes:
|
||||
return False, "Disk %s is up to date in VM %s" % (disk, vmid)
|
||||
|
||||
update_disk = {self.module.params["disk"]: config_str}
|
||||
self.proxmox_api.nodes(vm['node']).qemu(vmid).config.set(**update_disk)
|
||||
return True, "Disk %s updated in VM %s" % (disk, vmid)
|
||||
disk_config_to_apply = {self.module.params["disk"]: config_str}
|
||||
|
||||
current_task_id = self.proxmox_api.nodes(vm['node']).qemu(vmid).config.post(**disk_config_to_apply)
|
||||
task_success = self.wait_till_complete_or_timeout(vm['node'], current_task_id)
|
||||
if task_success:
|
||||
return True, ok_str % (disk, vmid)
|
||||
else:
|
||||
self.module.fail_json(
|
||||
msg=timeout_str % self.proxmox_api.nodes(vm['node']).tasks(current_task_id).log.get()[:1]
|
||||
)
|
||||
|
||||
def move_disk(self, disk, vmid, vm, vm_config):
|
||||
params = dict()
|
||||
@@ -535,20 +557,15 @@ class ProxmoxDiskAnsible(ProxmoxAnsible):
|
||||
if params['storage'] == disk_config['storage_name']:
|
||||
return False
|
||||
|
||||
taskid = self.proxmox_api.nodes(vm['node']).qemu(vmid).move_disk.post(**params)
|
||||
timeout = self.module.params['timeout']
|
||||
while timeout:
|
||||
status_data = self.proxmox_api.nodes(vm['node']).tasks(taskid).status.get()
|
||||
if status_data['status'] == 'stopped' and status_data['exitstatus'] == 'OK':
|
||||
return True
|
||||
if timeout <= 0:
|
||||
self.module.fail_json(
|
||||
msg='Reached timeout while waiting for moving VM disk. Last line in task before timeout: %s' %
|
||||
self.proxmox_api.nodes(vm['node']).tasks(taskid).log.get()[:1])
|
||||
|
||||
sleep(1)
|
||||
timeout -= 1
|
||||
return True
|
||||
task_id = self.proxmox_api.nodes(vm['node']).qemu(vmid).move_disk.post(**params)
|
||||
task_success = self.wait_till_complete_or_timeout(vm['node'], task_id)
|
||||
if task_success:
|
||||
return True
|
||||
else:
|
||||
self.module.fail_json(
|
||||
msg='Reached timeout while waiting for moving VM disk. Last line in task before timeout: %s' %
|
||||
self.proxmox_api.nodes(vm['node']).tasks(task_id).log.get()[:1]
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
@@ -699,7 +716,7 @@ def main():
|
||||
module.exit_json(changed=False, vmid=vmid, msg='Disk %s already detached in VM %s' % (disk, vmid))
|
||||
if disk not in vm_config:
|
||||
module.exit_json(changed=False, vmid=vmid, msg="Disk %s not present in VM %s config" % (disk, vmid))
|
||||
proxmox.proxmox_api.nodes(vm['node']).qemu(vmid).unlink.put(vmid=vmid, idlist=disk, force=0)
|
||||
proxmox.proxmox_api.nodes(vm['node']).qemu(vmid).unlink.put(idlist=disk, force=0)
|
||||
module.exit_json(changed=True, vmid=vmid, msg="Disk %s detached from VM %s" % (disk, vmid))
|
||||
except Exception as e:
|
||||
module.fail_json(msg="Failed to detach disk %s from VM %s with exception: %s" % (disk, vmid, str(e)))
|
||||
@@ -734,7 +751,7 @@ def main():
|
||||
try:
|
||||
if disk not in vm_config:
|
||||
module.exit_json(changed=False, vmid=vmid, msg="Disk %s is already absent in VM %s" % (disk, vmid))
|
||||
proxmox.proxmox_api.nodes(vm['node']).qemu(vmid).unlink.put(vmid=vmid, idlist=disk, force=1)
|
||||
proxmox.proxmox_api.nodes(vm['node']).qemu(vmid).unlink.put(idlist=disk, force=1)
|
||||
module.exit_json(changed=True, vmid=vmid, msg="Disk %s removed from VM %s" % (disk, vmid))
|
||||
except Exception as e:
|
||||
module.fail_json(vmid=vmid, msg='Unable to remove disk %s from VM %s: %s' % (disk, vmid, str(e)))
|
||||
|
||||
@@ -223,7 +223,7 @@ class ProxmoxNicAnsible(ProxmoxAnsible):
|
||||
|
||||
if interface in vminfo:
|
||||
if not self.module.check_mode:
|
||||
self.proxmox_api.nodes(vm['node']).qemu(vmid).config.set(vmid=vmid, delete=interface)
|
||||
self.proxmox_api.nodes(vm['node']).qemu(vmid).config.set(delete=interface)
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
@@ -152,15 +152,9 @@ import json
|
||||
import os
|
||||
import stat
|
||||
|
||||
import ansible_collections.community.general.plugins.module_utils.puppet as puppet_utils
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.six.moves import shlex_quote
|
||||
|
||||
|
||||
def _get_facter_dir():
|
||||
if os.getuid() == 0:
|
||||
return '/etc/facter/facts.d'
|
||||
else:
|
||||
return os.path.expanduser('~/.facter/facts.d')
|
||||
|
||||
|
||||
def _write_structured_data(basedir, basename, data):
|
||||
@@ -212,16 +206,6 @@ def main():
|
||||
)
|
||||
p = module.params
|
||||
|
||||
global PUPPET_CMD
|
||||
PUPPET_CMD = module.get_bin_path("puppet", False, ['/opt/puppetlabs/bin'])
|
||||
|
||||
if not PUPPET_CMD:
|
||||
module.fail_json(
|
||||
msg="Could not find puppet. Please ensure it is installed.")
|
||||
|
||||
global TIMEOUT_CMD
|
||||
TIMEOUT_CMD = module.get_bin_path("timeout", False)
|
||||
|
||||
if p['manifest']:
|
||||
if not os.path.exists(p['manifest']):
|
||||
module.fail_json(
|
||||
@@ -230,90 +214,24 @@ def main():
|
||||
|
||||
# Check if puppet is disabled here
|
||||
if not p['manifest']:
|
||||
rc, stdout, stderr = module.run_command(
|
||||
PUPPET_CMD + " config print agent_disabled_lockfile")
|
||||
if os.path.exists(stdout.strip()):
|
||||
module.fail_json(
|
||||
msg="Puppet agent is administratively disabled.",
|
||||
disabled=True)
|
||||
elif rc != 0:
|
||||
module.fail_json(
|
||||
msg="Puppet agent state could not be determined.")
|
||||
puppet_utils.ensure_agent_enabled(module)
|
||||
|
||||
if module.params['facts'] and not module.check_mode:
|
||||
_write_structured_data(
|
||||
_get_facter_dir(),
|
||||
puppet_utils.get_facter_dir(),
|
||||
module.params['facter_basename'],
|
||||
module.params['facts'])
|
||||
|
||||
if TIMEOUT_CMD:
|
||||
base_cmd = "%(timeout_cmd)s -s 9 %(timeout)s %(puppet_cmd)s" % dict(
|
||||
timeout_cmd=TIMEOUT_CMD,
|
||||
timeout=shlex_quote(p['timeout']),
|
||||
puppet_cmd=PUPPET_CMD)
|
||||
else:
|
||||
base_cmd = PUPPET_CMD
|
||||
runner = puppet_utils.puppet_runner(module)
|
||||
|
||||
if not p['manifest'] and not p['execute']:
|
||||
cmd = ("%(base_cmd)s agent --onetime"
|
||||
" --no-daemonize --no-usecacheonfailure --no-splay"
|
||||
" --detailed-exitcodes --verbose --color 0") % dict(base_cmd=base_cmd)
|
||||
if p['puppetmaster']:
|
||||
cmd += " --server %s" % shlex_quote(p['puppetmaster'])
|
||||
if p['show_diff']:
|
||||
cmd += " --show_diff"
|
||||
if p['confdir']:
|
||||
cmd += " --confdir %s" % shlex_quote(p['confdir'])
|
||||
if p['environment']:
|
||||
cmd += " --environment '%s'" % p['environment']
|
||||
if p['tags']:
|
||||
cmd += " --tags '%s'" % ','.join(p['tags'])
|
||||
if p['certname']:
|
||||
cmd += " --certname='%s'" % p['certname']
|
||||
if module.check_mode:
|
||||
cmd += " --noop"
|
||||
elif 'noop' in p:
|
||||
if p['noop']:
|
||||
cmd += " --noop"
|
||||
else:
|
||||
cmd += " --no-noop"
|
||||
if p['use_srv_records'] is not None:
|
||||
if not p['use_srv_records']:
|
||||
cmd += " --no-use_srv_records"
|
||||
else:
|
||||
cmd += " --use_srv_records"
|
||||
args_order = "_agent_fixed puppetmaster show_diff confdir environment tags certname noop use_srv_records"
|
||||
with runner(args_order) as ctx:
|
||||
rc, stdout, stderr = ctx.run()
|
||||
else:
|
||||
cmd = "%s apply --detailed-exitcodes " % base_cmd
|
||||
if p['logdest'] == 'syslog':
|
||||
cmd += "--logdest syslog "
|
||||
if p['logdest'] == 'all':
|
||||
cmd += " --logdest syslog --logdest console"
|
||||
if p['modulepath']:
|
||||
cmd += "--modulepath='%s'" % p['modulepath']
|
||||
if p['environment']:
|
||||
cmd += "--environment '%s' " % p['environment']
|
||||
if p['certname']:
|
||||
cmd += " --certname='%s'" % p['certname']
|
||||
if p['tags']:
|
||||
cmd += " --tags '%s'" % ','.join(p['tags'])
|
||||
if module.check_mode:
|
||||
cmd += "--noop "
|
||||
elif 'noop' in p:
|
||||
if p['noop']:
|
||||
cmd += " --noop"
|
||||
else:
|
||||
cmd += " --no-noop"
|
||||
if p['execute']:
|
||||
cmd += " --execute '%s'" % p['execute']
|
||||
else:
|
||||
cmd += " %s" % shlex_quote(p['manifest'])
|
||||
if p['summarize']:
|
||||
cmd += " --summarize"
|
||||
if p['debug']:
|
||||
cmd += " --debug"
|
||||
if p['verbose']:
|
||||
cmd += " --verbose"
|
||||
rc, stdout, stderr = module.run_command(cmd)
|
||||
args_order = "_apply_fixed logdest modulepath environment certname tags noop _execute summarize debug verbose"
|
||||
with runner(args_order) as ctx:
|
||||
rc, stdout, stderr = ctx.run(_execute=[p['execute'], p['manifest']])
|
||||
|
||||
if rc == 0:
|
||||
# success
|
||||
@@ -335,11 +253,11 @@ def main():
|
||||
elif rc == 124:
|
||||
# timeout
|
||||
module.exit_json(
|
||||
rc=rc, msg="%s timed out" % cmd, stdout=stdout, stderr=stderr)
|
||||
rc=rc, msg="%s timed out" % ctx.cmd, stdout=stdout, stderr=stderr)
|
||||
else:
|
||||
# failure
|
||||
module.fail_json(
|
||||
rc=rc, msg="%s failed with return code: %d" % (cmd, rc),
|
||||
rc=rc, msg="%s failed with return code: %d" % (ctx.cmd, rc),
|
||||
stdout=stdout, stderr=stderr)
|
||||
|
||||
|
||||
|
||||
@@ -13,7 +13,9 @@ DOCUMENTATION = '''
|
||||
module: rax_cbs
|
||||
short_description: Manipulate Rackspace Cloud Block Storage Volumes
|
||||
description:
|
||||
- Manipulate Rackspace Cloud Block Storage Volumes
|
||||
- Manipulate Rackspace Cloud Block Storage Volumes
|
||||
- This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
|
||||
- Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
|
||||
options:
|
||||
description:
|
||||
type: str
|
||||
|
||||
@@ -13,7 +13,9 @@ DOCUMENTATION = '''
|
||||
module: rax_cbs_attachments
|
||||
short_description: Manipulate Rackspace Cloud Block Storage Volume Attachments
|
||||
description:
|
||||
- Manipulate Rackspace Cloud Block Storage Volume Attachments
|
||||
- Manipulate Rackspace Cloud Block Storage Volume Attachments
|
||||
- This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
|
||||
- Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
|
||||
options:
|
||||
device:
|
||||
type: str
|
||||
|
||||
@@ -16,6 +16,8 @@ description:
|
||||
- creates / deletes or resize a Rackspace Cloud Databases instance
|
||||
and optionally waits for it to be 'running'. The name option needs to be
|
||||
unique since it's used to identify the instance.
|
||||
- This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
|
||||
- Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
|
||||
options:
|
||||
name:
|
||||
type: str
|
||||
|
||||
@@ -13,6 +13,8 @@ module: rax_cdb_database
|
||||
short_description: Create / delete a database in the Cloud Databases
|
||||
description:
|
||||
- create / delete a database in the Cloud Databases.
|
||||
- This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
|
||||
- Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
|
||||
options:
|
||||
cdb_id:
|
||||
type: str
|
||||
|
||||
@@ -14,6 +14,8 @@ module: rax_cdb_user
|
||||
short_description: Create / delete a Rackspace Cloud Database
|
||||
description:
|
||||
- create / delete a database in the Cloud Databases.
|
||||
- This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
|
||||
- Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
|
||||
options:
|
||||
cdb_id:
|
||||
type: str
|
||||
|
||||
@@ -13,7 +13,9 @@ DOCUMENTATION = '''
|
||||
module: rax_clb
|
||||
short_description: Create / delete a load balancer in Rackspace Public Cloud
|
||||
description:
|
||||
- creates / deletes a Rackspace Public Cloud load balancer.
|
||||
- creates / deletes a Rackspace Public Cloud load balancer.
|
||||
- This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
|
||||
- Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
|
||||
options:
|
||||
algorithm:
|
||||
type: str
|
||||
|
||||
@@ -13,7 +13,9 @@ DOCUMENTATION = '''
|
||||
module: rax_clb_nodes
|
||||
short_description: Add, modify and remove nodes from a Rackspace Cloud Load Balancer
|
||||
description:
|
||||
- Adds, modifies and removes nodes from a Rackspace Cloud Load Balancer
|
||||
- Adds, modifies and removes nodes from a Rackspace Cloud Load Balancer.
|
||||
- This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
|
||||
- Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
|
||||
options:
|
||||
address:
|
||||
type: str
|
||||
|
||||
@@ -12,7 +12,9 @@ DOCUMENTATION = '''
|
||||
module: rax_clb_ssl
|
||||
short_description: Manage SSL termination for a Rackspace Cloud Load Balancer
|
||||
description:
|
||||
- Set up, reconfigure, or remove SSL termination for an existing load balancer.
|
||||
- Set up, reconfigure, or remove SSL termination for an existing load balancer.
|
||||
- This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
|
||||
- Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
|
||||
options:
|
||||
loadbalancer:
|
||||
type: str
|
||||
|
||||
@@ -13,7 +13,9 @@ DOCUMENTATION = '''
|
||||
module: rax_dns
|
||||
short_description: Manage domains on Rackspace Cloud DNS
|
||||
description:
|
||||
- Manage domains on Rackspace Cloud DNS
|
||||
- Manage domains on Rackspace Cloud DNS.
|
||||
- This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
|
||||
- Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
|
||||
options:
|
||||
comment:
|
||||
type: str
|
||||
|
||||
@@ -13,7 +13,9 @@ DOCUMENTATION = '''
|
||||
module: rax_dns_record
|
||||
short_description: Manage DNS records on Rackspace Cloud DNS
|
||||
description:
|
||||
- Manage DNS records on Rackspace Cloud DNS
|
||||
- Manage DNS records on Rackspace Cloud DNS.
|
||||
- This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
|
||||
- Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
|
||||
options:
|
||||
comment:
|
||||
type: str
|
||||
|
||||
@@ -14,6 +14,8 @@ module: rax_facts
|
||||
short_description: Gather facts for Rackspace Cloud Servers
|
||||
description:
|
||||
- Gather facts for Rackspace Cloud Servers.
|
||||
- This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
|
||||
- Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
|
||||
options:
|
||||
address:
|
||||
type: str
|
||||
|
||||
@@ -13,7 +13,9 @@ DOCUMENTATION = '''
|
||||
module: rax_files
|
||||
short_description: Manipulate Rackspace Cloud Files Containers
|
||||
description:
|
||||
- Manipulate Rackspace Cloud Files Containers
|
||||
- Manipulate Rackspace Cloud Files Containers.
|
||||
- This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
|
||||
- Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
|
||||
options:
|
||||
clear_meta:
|
||||
description:
|
||||
|
||||
@@ -14,6 +14,8 @@ module: rax_files_objects
|
||||
short_description: Upload, download, and delete objects in Rackspace Cloud Files
|
||||
description:
|
||||
- Upload, download, and delete objects in Rackspace Cloud Files.
|
||||
- This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
|
||||
- Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
|
||||
options:
|
||||
clear_meta:
|
||||
description:
|
||||
|
||||
@@ -13,7 +13,9 @@ DOCUMENTATION = '''
|
||||
module: rax_identity
|
||||
short_description: Load Rackspace Cloud Identity
|
||||
description:
|
||||
- Verifies Rackspace Cloud credentials and returns identity information
|
||||
- Verifies Rackspace Cloud credentials and returns identity information.
|
||||
- This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
|
||||
- Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
|
||||
options:
|
||||
state:
|
||||
type: str
|
||||
|
||||
@@ -13,7 +13,9 @@ DOCUMENTATION = '''
|
||||
module: rax_keypair
|
||||
short_description: Create a keypair for use with Rackspace Cloud Servers
|
||||
description:
|
||||
- Create a keypair for use with Rackspace Cloud Servers
|
||||
- Create a keypair for use with Rackspace Cloud Servers.
|
||||
- This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
|
||||
- Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
|
||||
options:
|
||||
name:
|
||||
type: str
|
||||
|
||||
@@ -13,7 +13,9 @@ DOCUMENTATION = '''
|
||||
module: rax_meta
|
||||
short_description: Manipulate metadata for Rackspace Cloud Servers
|
||||
description:
|
||||
- Manipulate metadata for Rackspace Cloud Servers
|
||||
- Manipulate metadata for Rackspace Cloud Servers.
|
||||
- This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
|
||||
- Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
|
||||
options:
|
||||
address:
|
||||
type: str
|
||||
|
||||
@@ -13,12 +13,14 @@ DOCUMENTATION = '''
|
||||
module: rax_mon_alarm
|
||||
short_description: Create or delete a Rackspace Cloud Monitoring alarm
|
||||
description:
|
||||
- Create or delete a Rackspace Cloud Monitoring alarm that associates an
|
||||
existing rax_mon_entity, rax_mon_check, and rax_mon_notification_plan with
|
||||
criteria that specify what conditions will trigger which levels of
|
||||
notifications. Rackspace monitoring module flow | rax_mon_entity ->
|
||||
rax_mon_check -> rax_mon_notification -> rax_mon_notification_plan ->
|
||||
*rax_mon_alarm*
|
||||
- Create or delete a Rackspace Cloud Monitoring alarm that associates an
|
||||
existing rax_mon_entity, rax_mon_check, and rax_mon_notification_plan with
|
||||
criteria that specify what conditions will trigger which levels of
|
||||
notifications. Rackspace monitoring module flow | rax_mon_entity ->
|
||||
rax_mon_check -> rax_mon_notification -> rax_mon_notification_plan ->
|
||||
*rax_mon_alarm*.
|
||||
- This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
|
||||
- Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
|
||||
options:
|
||||
state:
|
||||
type: str
|
||||
|
||||
@@ -14,12 +14,14 @@ module: rax_mon_check
|
||||
short_description: Create or delete a Rackspace Cloud Monitoring check for an
|
||||
existing entity.
|
||||
description:
|
||||
- Create or delete a Rackspace Cloud Monitoring check associated with an
|
||||
existing rax_mon_entity. A check is a specific test or measurement that is
|
||||
performed, possibly from different monitoring zones, on the systems you
|
||||
monitor. Rackspace monitoring module flow | rax_mon_entity ->
|
||||
*rax_mon_check* -> rax_mon_notification -> rax_mon_notification_plan ->
|
||||
rax_mon_alarm
|
||||
- Create or delete a Rackspace Cloud Monitoring check associated with an
|
||||
existing rax_mon_entity. A check is a specific test or measurement that is
|
||||
performed, possibly from different monitoring zones, on the systems you
|
||||
monitor. Rackspace monitoring module flow | rax_mon_entity ->
|
||||
*rax_mon_check* -> rax_mon_notification -> rax_mon_notification_plan ->
|
||||
rax_mon_alarm
|
||||
- This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
|
||||
- Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
|
||||
options:
|
||||
state:
|
||||
type: str
|
||||
|
||||
@@ -13,11 +13,13 @@ DOCUMENTATION = '''
|
||||
module: rax_mon_entity
|
||||
short_description: Create or delete a Rackspace Cloud Monitoring entity
|
||||
description:
|
||||
- Create or delete a Rackspace Cloud Monitoring entity, which represents a device
|
||||
to monitor. Entities associate checks and alarms with a target system and
|
||||
provide a convenient, centralized place to store IP addresses. Rackspace
|
||||
monitoring module flow | *rax_mon_entity* -> rax_mon_check ->
|
||||
rax_mon_notification -> rax_mon_notification_plan -> rax_mon_alarm
|
||||
- Create or delete a Rackspace Cloud Monitoring entity, which represents a device
|
||||
to monitor. Entities associate checks and alarms with a target system and
|
||||
provide a convenient, centralized place to store IP addresses. Rackspace
|
||||
monitoring module flow | *rax_mon_entity* -> rax_mon_check ->
|
||||
rax_mon_notification -> rax_mon_notification_plan -> rax_mon_alarm.
|
||||
- This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
|
||||
- Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
|
||||
options:
|
||||
label:
|
||||
type: str
|
||||
|
||||
@@ -14,10 +14,12 @@ module: rax_mon_notification_plan
|
||||
short_description: Create or delete a Rackspace Cloud Monitoring notification
|
||||
plan.
|
||||
description:
|
||||
- Create or delete a Rackspace Cloud Monitoring notification plan by
|
||||
associating existing rax_mon_notifications with severity levels. Rackspace
|
||||
monitoring module flow | rax_mon_entity -> rax_mon_check ->
|
||||
rax_mon_notification -> *rax_mon_notification_plan* -> rax_mon_alarm
|
||||
- Create or delete a Rackspace Cloud Monitoring notification plan by
|
||||
associating existing rax_mon_notifications with severity levels. Rackspace
|
||||
monitoring module flow | rax_mon_entity -> rax_mon_check ->
|
||||
rax_mon_notification -> *rax_mon_notification_plan* -> rax_mon_alarm.
|
||||
- This module relies on the C(pyrax) package which is deprecated in favour of using Openstack API.
|
||||
- Unless maintainers step up to work on the module, it will be marked as deprecated in community.general 7.0.0 and removed in version 9.0.0.
|
||||
options:
|
||||
state:
|
||||
type: str
|
||||
|
||||
@@ -40,6 +40,11 @@ options:
|
||||
description:
|
||||
- access.redhat.com or Red Hat Satellite or Katello password
|
||||
type: str
|
||||
token:
|
||||
description:
|
||||
- sso.redhat.com API access token.
|
||||
type: str
|
||||
version_added: 6.3.0
|
||||
server_hostname:
|
||||
description:
|
||||
- Specify an alternative Red Hat Subscription Management or Red Hat Satellite or Katello server
|
||||
@@ -70,6 +75,11 @@ options:
|
||||
description:
|
||||
- Specify an HTTP proxy hostname.
|
||||
type: str
|
||||
server_proxy_scheme:
|
||||
description:
|
||||
- Specify an HTTP proxy scheme, for example C(http) or C(https).
|
||||
type: str
|
||||
version_added: 6.2.0
|
||||
server_proxy_port:
|
||||
description:
|
||||
- Specify an HTTP proxy port.
|
||||
@@ -289,10 +299,11 @@ class RegistrationBase(object):
|
||||
|
||||
REDHAT_REPO = "/etc/yum.repos.d/redhat.repo"
|
||||
|
||||
def __init__(self, module, username=None, password=None):
|
||||
def __init__(self, module, username=None, password=None, token=None):
|
||||
self.module = module
|
||||
self.username = username
|
||||
self.password = password
|
||||
self.token = token
|
||||
|
||||
def configure(self):
|
||||
raise NotImplementedError("Must be implemented by a sub-class")
|
||||
@@ -335,8 +346,8 @@ class RegistrationBase(object):
|
||||
|
||||
|
||||
class Rhsm(RegistrationBase):
|
||||
def __init__(self, module, username=None, password=None):
|
||||
RegistrationBase.__init__(self, module, username, password)
|
||||
def __init__(self, module, username=None, password=None, token=None):
|
||||
RegistrationBase.__init__(self, module, username, password, token)
|
||||
self.module = module
|
||||
|
||||
def enable(self):
|
||||
@@ -392,7 +403,7 @@ class Rhsm(RegistrationBase):
|
||||
else:
|
||||
return False
|
||||
|
||||
def register(self, username, password, auto_attach, activationkey, org_id,
|
||||
def register(self, username, password, token, auto_attach, activationkey, org_id,
|
||||
consumer_type, consumer_name, consumer_id, force_register, environment,
|
||||
release):
|
||||
'''
|
||||
@@ -428,6 +439,8 @@ class Rhsm(RegistrationBase):
|
||||
|
||||
if activationkey:
|
||||
args.extend(['--activationkey', activationkey])
|
||||
elif token:
|
||||
args.extend(['--token', token])
|
||||
else:
|
||||
if username:
|
||||
args.extend(['--username', username])
|
||||
@@ -789,6 +802,7 @@ def main():
|
||||
'state': {'default': 'present', 'choices': ['present', 'absent']},
|
||||
'username': {},
|
||||
'password': {'no_log': True},
|
||||
'token': {'no_log': True},
|
||||
'server_hostname': {},
|
||||
'server_insecure': {},
|
||||
'server_prefix': {},
|
||||
@@ -806,6 +820,7 @@ def main():
|
||||
'consumer_id': {},
|
||||
'force_register': {'default': False, 'type': 'bool'},
|
||||
'server_proxy_hostname': {},
|
||||
'server_proxy_scheme': {},
|
||||
'server_proxy_port': {},
|
||||
'server_proxy_user': {},
|
||||
'server_proxy_password': {'no_log': True},
|
||||
@@ -825,17 +840,20 @@ def main():
|
||||
['server_proxy_hostname', 'server_proxy_port'],
|
||||
['server_proxy_user', 'server_proxy_password']],
|
||||
mutually_exclusive=[['activationkey', 'username'],
|
||||
['activationkey', 'token'],
|
||||
['token', 'username'],
|
||||
['activationkey', 'consumer_id'],
|
||||
['activationkey', 'environment'],
|
||||
['activationkey', 'auto_attach'],
|
||||
['pool', 'pool_ids']],
|
||||
required_if=[['state', 'present', ['username', 'activationkey'], True]],
|
||||
required_if=[['state', 'present', ['username', 'activationkey', 'token'], True]],
|
||||
)
|
||||
|
||||
rhsm.module = module
|
||||
state = module.params['state']
|
||||
username = module.params['username']
|
||||
password = module.params['password']
|
||||
token = module.params['token']
|
||||
server_hostname = module.params['server_hostname']
|
||||
server_insecure = module.params['server_insecure']
|
||||
server_prefix = module.params['server_prefix']
|
||||
@@ -908,7 +926,7 @@ def main():
|
||||
try:
|
||||
rhsm.enable()
|
||||
rhsm.configure(**module.params)
|
||||
rhsm.register(username, password, auto_attach, activationkey, org_id,
|
||||
rhsm.register(username, password, token, auto_attach, activationkey, org_id,
|
||||
consumer_type, consumer_name, consumer_id, force_register,
|
||||
environment, release)
|
||||
if syspurpose and 'sync' in syspurpose and syspurpose['sync'] is True:
|
||||
|
||||
@@ -92,7 +92,7 @@ EXAMPLES = '''
|
||||
RETURN = '''
|
||||
scaleway_compute_private_network:
|
||||
description: Information on the VPC.
|
||||
returned: success when C(state=present)
|
||||
returned: success when I(state=present)
|
||||
type: dict
|
||||
sample:
|
||||
{
|
||||
|
||||
@@ -19,7 +19,7 @@ short_description: Scaleway database backups management module
|
||||
version_added: 1.2.0
|
||||
author: Guillaume Rodriguez (@guillaume_ro_fr)
|
||||
description:
|
||||
- This module manages database backups on Scaleway account U(https://developer.scaleway.com).
|
||||
- "This module manages database backups on Scaleway account U(https://developer.scaleway.com)."
|
||||
extends_documentation_fragment:
|
||||
- community.general.scaleway
|
||||
options:
|
||||
@@ -58,7 +58,7 @@ options:
|
||||
description:
|
||||
- Name used to identify the database backup.
|
||||
- Required for C(present) state.
|
||||
- Ignored when C(state=absent), C(state=exported) or C(state=restored).
|
||||
- Ignored when I(state=absent), I(state=exported) or I(state=restored).
|
||||
type: str
|
||||
required: false
|
||||
|
||||
@@ -66,7 +66,7 @@ options:
|
||||
description:
|
||||
- Name used to identify the database.
|
||||
- Required for C(present) and C(restored) states.
|
||||
- Ignored when C(state=absent) or C(state=exported).
|
||||
- Ignored when I(state=absent) or I(state=exported).
|
||||
type: str
|
||||
required: false
|
||||
|
||||
@@ -74,14 +74,14 @@ options:
|
||||
description:
|
||||
- UUID of the instance associated to the database backup.
|
||||
- Required for C(present) and C(restored) states.
|
||||
- Ignored when C(state=absent) or C(state=exported).
|
||||
- Ignored when I(state=absent) or I(state=exported).
|
||||
type: str
|
||||
required: false
|
||||
|
||||
expires_at:
|
||||
description:
|
||||
- Expiration datetime of the database backup (ISO 8601 format).
|
||||
- Ignored when C(state=absent), C(state=exported) or C(state=restored).
|
||||
- Ignored when I(state=absent), I(state=exported) or I(state=restored).
|
||||
type: str
|
||||
required: false
|
||||
|
||||
@@ -139,7 +139,7 @@ EXAMPLES = '''
|
||||
RETURN = '''
|
||||
metadata:
|
||||
description: Backup metadata.
|
||||
returned: when C(state=present), C(state=exported) or C(state=restored)
|
||||
returned: when I(state=present), I(state=exported) or I(state=restored)
|
||||
type: dict
|
||||
sample: {
|
||||
"metadata": {
|
||||
|
||||
@@ -26,7 +26,7 @@ options:
|
||||
region:
|
||||
type: str
|
||||
description:
|
||||
- Scaleway compute zone
|
||||
- Scaleway compute zone.
|
||||
required: true
|
||||
choices:
|
||||
- ams1
|
||||
|
||||
@@ -88,8 +88,8 @@ EXAMPLES = '''
|
||||
|
||||
RETURN = '''
|
||||
data:
|
||||
description: This is only present when C(state=present)
|
||||
returned: when C(state=present)
|
||||
description: This is only present when I(state=present).
|
||||
returned: when I(state=present)
|
||||
type: dict
|
||||
sample: {
|
||||
"ips": [
|
||||
|
||||
@@ -29,19 +29,19 @@ options:
|
||||
name:
|
||||
type: str
|
||||
description:
|
||||
- Name of the load-balancer
|
||||
- Name of the load-balancer.
|
||||
required: true
|
||||
|
||||
description:
|
||||
type: str
|
||||
description:
|
||||
- Description of the load-balancer
|
||||
- Description of the load-balancer.
|
||||
required: true
|
||||
|
||||
organization_id:
|
||||
type: str
|
||||
description:
|
||||
- Organization identifier
|
||||
- Organization identifier.
|
||||
required: true
|
||||
|
||||
state:
|
||||
@@ -56,7 +56,7 @@ options:
|
||||
region:
|
||||
type: str
|
||||
description:
|
||||
- Scaleway zone
|
||||
- Scaleway zone.
|
||||
required: true
|
||||
choices:
|
||||
- nl-ams
|
||||
@@ -68,7 +68,7 @@ options:
|
||||
elements: str
|
||||
default: []
|
||||
description:
|
||||
- List of tags to apply to the load-balancer
|
||||
- List of tags to apply to the load-balancer.
|
||||
|
||||
wait:
|
||||
description:
|
||||
@@ -79,14 +79,14 @@ options:
|
||||
wait_timeout:
|
||||
type: int
|
||||
description:
|
||||
- Time to wait for the load-balancer to reach the expected state
|
||||
- Time to wait for the load-balancer to reach the expected state.
|
||||
required: false
|
||||
default: 300
|
||||
|
||||
wait_sleep_time:
|
||||
type: int
|
||||
description:
|
||||
- Time to wait before every attempt to check the state of the load-balancer
|
||||
- Time to wait before every attempt to check the state of the load-balancer.
|
||||
required: false
|
||||
default: 3
|
||||
'''
|
||||
|
||||
@@ -20,7 +20,7 @@ author:
|
||||
options:
|
||||
api_url:
|
||||
description:
|
||||
- Scaleway API URL
|
||||
- Scaleway API URL.
|
||||
default: 'https://account.scaleway.com'
|
||||
aliases: ['base_url']
|
||||
extends_documentation_fragment:
|
||||
@@ -42,7 +42,7 @@ EXAMPLES = r'''
|
||||
RETURN = r'''
|
||||
---
|
||||
scaleway_organization_info:
|
||||
description: Response from Scaleway API
|
||||
description: Response from Scaleway API.
|
||||
returned: success
|
||||
type: list
|
||||
elements: dict
|
||||
|
||||
@@ -18,8 +18,7 @@ short_description: Scaleway private network management
|
||||
version_added: 4.5.0
|
||||
author: Pascal MANGIN (@pastral)
|
||||
description:
|
||||
- This module manages private network on Scaleway account
|
||||
(U(https://developer.scaleway.com)).
|
||||
- "This module manages private network on Scaleway account (U(https://developer.scaleway.com))."
|
||||
extends_documentation_fragment:
|
||||
- community.general.scaleway
|
||||
|
||||
@@ -88,7 +87,7 @@ EXAMPLES = '''
|
||||
RETURN = '''
|
||||
scaleway_private_network:
|
||||
description: Information on the VPC.
|
||||
returned: success when C(state=present)
|
||||
returned: success when I(state=present)
|
||||
type: dict
|
||||
sample:
|
||||
{
|
||||
|
||||
@@ -18,8 +18,7 @@ module: scaleway_security_group
|
||||
short_description: Scaleway Security Group management module
|
||||
author: Antoine Barbare (@abarbare)
|
||||
description:
|
||||
- This module manages Security Group on Scaleway account
|
||||
U(https://developer.scaleway.com).
|
||||
- "This module manages Security Group on Scaleway account U(https://developer.scaleway.com)."
|
||||
extends_documentation_fragment:
|
||||
- community.general.scaleway
|
||||
|
||||
@@ -105,8 +104,8 @@ EXAMPLES = '''
|
||||
|
||||
RETURN = '''
|
||||
data:
|
||||
description: This is only present when C(state=present)
|
||||
returned: when C(state=present)
|
||||
description: This is only present when I(state=present).
|
||||
returned: when I(state=present)
|
||||
type: dict
|
||||
sample: {
|
||||
"scaleway_security_group": {
|
||||
|
||||
@@ -18,8 +18,7 @@ module: scaleway_security_group_rule
|
||||
short_description: Scaleway Security Group Rule management module
|
||||
author: Antoine Barbare (@abarbare)
|
||||
description:
|
||||
- This module manages Security Group Rule on Scaleway account
|
||||
U(https://developer.scaleway.com)
|
||||
- "This module manages Security Group Rule on Scaleway account U(https://developer.scaleway.com)."
|
||||
extends_documentation_fragment:
|
||||
- community.general.scaleway
|
||||
requirements:
|
||||
@@ -53,7 +52,7 @@ options:
|
||||
protocol:
|
||||
type: str
|
||||
description:
|
||||
- Network protocol to use
|
||||
- Network protocol to use.
|
||||
choices:
|
||||
- TCP
|
||||
- UDP
|
||||
@@ -62,20 +61,20 @@ options:
|
||||
|
||||
port:
|
||||
description:
|
||||
- Port related to the rule, null value for all the ports
|
||||
- Port related to the rule, null value for all the ports.
|
||||
required: true
|
||||
type: int
|
||||
|
||||
ip_range:
|
||||
type: str
|
||||
description:
|
||||
- IPV4 CIDR notation to apply to the rule
|
||||
- IPV4 CIDR notation to apply to the rule.
|
||||
default: 0.0.0.0/0
|
||||
|
||||
direction:
|
||||
type: str
|
||||
description:
|
||||
- Rule direction
|
||||
- Rule direction.
|
||||
choices:
|
||||
- inbound
|
||||
- outbound
|
||||
@@ -84,7 +83,7 @@ options:
|
||||
action:
|
||||
type: str
|
||||
description:
|
||||
- Rule action
|
||||
- Rule action.
|
||||
choices:
|
||||
- accept
|
||||
- drop
|
||||
@@ -93,7 +92,7 @@ options:
|
||||
security_group:
|
||||
type: str
|
||||
description:
|
||||
- Security Group unique identifier
|
||||
- Security Group unique identifier.
|
||||
required: true
|
||||
'''
|
||||
|
||||
@@ -113,8 +112,8 @@ EXAMPLES = '''
|
||||
|
||||
RETURN = '''
|
||||
data:
|
||||
description: This is only present when C(state=present)
|
||||
returned: when C(state=present)
|
||||
description: This is only present when I(state=present).
|
||||
returned: when I(state=present)
|
||||
type: dict
|
||||
sample: {
|
||||
"scaleway_security_group_rule": {
|
||||
|
||||
@@ -19,8 +19,7 @@ module: scaleway_sshkey
|
||||
short_description: Scaleway SSH keys management module
|
||||
author: Remy Leone (@remyleone)
|
||||
description:
|
||||
- This module manages SSH keys on Scaleway account
|
||||
U(https://developer.scaleway.com)
|
||||
- "This module manages SSH keys on Scaleway account U(https://developer.scaleway.com)."
|
||||
extends_documentation_fragment:
|
||||
- community.general.scaleway
|
||||
|
||||
@@ -42,7 +41,7 @@ options:
|
||||
api_url:
|
||||
type: str
|
||||
description:
|
||||
- Scaleway API URL
|
||||
- Scaleway API URL.
|
||||
default: 'https://account.scaleway.com'
|
||||
aliases: ['base_url']
|
||||
'''
|
||||
@@ -67,8 +66,8 @@ EXAMPLES = '''
|
||||
|
||||
RETURN = '''
|
||||
data:
|
||||
description: This is only present when C(state=present)
|
||||
returned: when C(state=present)
|
||||
description: This is only present when I(state=present).
|
||||
returned: when I(state=present)
|
||||
type: dict
|
||||
sample: {
|
||||
"ssh_public_keys": [
|
||||
|
||||
@@ -19,8 +19,8 @@ module: scaleway_user_data
|
||||
short_description: Scaleway user_data management module
|
||||
author: Remy Leone (@remyleone)
|
||||
description:
|
||||
- "This module manages user_data on compute instances on Scaleway."
|
||||
- "It can be used to configure cloud-init for instance"
|
||||
- This module manages user_data on compute instances on Scaleway.
|
||||
- It can be used to configure cloud-init for instance.
|
||||
extends_documentation_fragment:
|
||||
- community.general.scaleway
|
||||
|
||||
@@ -30,20 +30,20 @@ options:
|
||||
server_id:
|
||||
type: str
|
||||
description:
|
||||
- Scaleway Compute instance ID of the server
|
||||
- Scaleway Compute instance ID of the server.
|
||||
required: true
|
||||
|
||||
user_data:
|
||||
type: dict
|
||||
description:
|
||||
- User defined data. Typically used with C(cloud-init).
|
||||
- Pass your cloud-init script here as a string
|
||||
- Pass your C(cloud-init) script here as a string.
|
||||
required: false
|
||||
|
||||
region:
|
||||
type: str
|
||||
description:
|
||||
- Scaleway compute zone
|
||||
- Scaleway compute zone.
|
||||
required: true
|
||||
choices:
|
||||
- ams1
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user