diff options
Diffstat (limited to 'ansible_collections/vmware/vmware_rest/plugins')
144 files changed, 45300 insertions, 0 deletions
diff --git a/ansible_collections/vmware/vmware_rest/plugins/doc_fragments/__init__.py b/ansible_collections/vmware/vmware_rest/plugins/doc_fragments/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/doc_fragments/__init__.py diff --git a/ansible_collections/vmware/vmware_rest/plugins/doc_fragments/moid.py b/ansible_collections/vmware/vmware_rest/plugins/doc_fragments/moid.py new file mode 100644 index 00000000..c241b7cb --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/doc_fragments/moid.py @@ -0,0 +1,53 @@ +# Copyright: (c) 2021, Alina Buzachis <@alinabuzachis> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +class ModuleDocFragment(object): + # Parameters for the Lookup Managed Object Reference (MoID) plugins + DOCUMENTATION = r""" + options: + _terms: + description: Path to query. + required: true + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - You can use this optional parameter to set the location of a log file. + - This file will be used to record the HTTP REST interaction. + - The file will be stored on the host that run the module. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +""" diff --git a/ansible_collections/vmware/vmware_rest/plugins/lookup/cluster_moid.py b/ansible_collections/vmware/vmware_rest/plugins/lookup/cluster_moid.py new file mode 100644 index 00000000..22a3629d --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/lookup/cluster_moid.py @@ -0,0 +1,68 @@ +# Copyright: (c) 2021, Alina Buzachis <@alinabuzachis> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +name: cluster_moid +short_description: Look up MoID for vSphere cluster objects using vCenter REST API +description: + - Returns Managed Object Reference (MoID) of the vSphere cluster object contained in the specified path. +author: + - Alina Buzachis (@alinabuzachis) +version_added: 2.1.0 +requirements: + - vSphere 7.0.2 or greater + - python >= 3.6 + - aiohttp +extends_documentation_fragment: +- vmware.vmware_rest.moid +""" + + +EXAMPLES = r""" +# lookup sample +- name: set connection info + ansible.builtin.set_fact: + connection_args: + vcenter_hostname: "vcenter.test" + vcenter_username: "administrator@vsphere.local" + vcenter_password: "1234" + +- name: lookup MoID of the object + ansible.builtin.debug: msg="{{ lookup('vmware.vmware_rest.cluster_moid', '/my_dc/host/my_cluster', **connection_args) }}" + +- name: lookup MoID of the object inside the path + ansible.builtin.debug: msg="{{ lookup('vmware.vmware_rest.cluster_moid', '/my_dc/host/') }}" +""" + + +RETURN = r""" +_raw: + description: MoID of the vSphere cluster object + type: str + sample: domain-c1007 +""" + + +from ansible_collections.vmware.vmware_rest.plugins.plugin_utils.lookup import ( + Lookup, + get_credentials, +) +from ansible_collections.cloud.common.plugins.plugin_utils.turbo.lookup import ( + TurboLookupBase as LookupBase, +) + + +class LookupModule(LookupBase): + async def _run(self, terms, variables, **kwargs): + self.set_options(var_options=variables, direct=get_credentials(**kwargs)) + self.set_option("object_type", "cluster") + result = await Lookup.entry_point(terms, self._options) + return [result] + + run = _run if not hasattr(LookupBase, "run_on_daemon") else LookupBase.run_on_daemon diff --git a/ansible_collections/vmware/vmware_rest/plugins/lookup/datacenter_moid.py b/ansible_collections/vmware/vmware_rest/plugins/lookup/datacenter_moid.py new file mode 100644 index 00000000..d3f644eb --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/lookup/datacenter_moid.py @@ -0,0 +1,68 @@ +# Copyright: (c) 2021, Alina Buzachis <@alinabuzachis> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +name: datacenter_moid +short_description: Look up MoID for vSphere datacenter objects using vCenter REST API +description: + - Returns Managed Object Reference (MoID) of the vSphere datacenter object contained in the specified path. +author: + - Alina Buzachis (@alinabuzachis) +version_added: 2.1.0 +requirements: + - vSphere 7.0.2 or greater + - python >= 3.6 + - aiohttp +extends_documentation_fragment: +- vmware.vmware_rest.moid +""" + + +EXAMPLES = r""" +# lookup sample +- name: set connection info + ansible.builtin.set_fact: + connection_args: + vcenter_hostname: "vcenter.test" + vcenter_username: "administrator@vsphere.local" + vcenter_password: "1234" + +- name: lookup MoID of the object + ansible.builtin.debug: msg="{{ lookup('vmware.vmware_rest.datacenter_moid', '/my_dc', **connection_args) }}" + +- name: lookup MoID of the object inside the path + ansible.builtin.debug: msg="{{ lookup('vmware.vmware_rest.datacenter_moid', '/my_folder/') }}" +""" + + +RETURN = r""" +_raw: + description: MoID of the vSphere datacenter object + type: str + sample: datacenter-1001 +""" + + +from ansible_collections.vmware.vmware_rest.plugins.plugin_utils.lookup import ( + Lookup, + get_credentials, +) +from ansible_collections.cloud.common.plugins.plugin_utils.turbo.lookup import ( + TurboLookupBase as LookupBase, +) + + +class LookupModule(LookupBase): + async def _run(self, terms, variables, **kwargs): + self.set_options(var_options=variables, direct=get_credentials(**kwargs)) + self.set_option("object_type", "datacenter") + result = await Lookup.entry_point(terms, self._options) + return [result] + + run = _run if not hasattr(LookupBase, "run_on_daemon") else LookupBase.run_on_daemon diff --git a/ansible_collections/vmware/vmware_rest/plugins/lookup/datastore_moid.py b/ansible_collections/vmware/vmware_rest/plugins/lookup/datastore_moid.py new file mode 100644 index 00000000..27d3c779 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/lookup/datastore_moid.py @@ -0,0 +1,68 @@ +# Copyright: (c) 2021, Alina Buzachis <@alinabuzachis> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +name: datastore_moid +short_description: Look up MoID for vSphere datastore objects using vCenter REST API +description: + - Returns Managed Object Reference (MoID) of the vSphere datastore object object contained in the specified path. +author: + - Alina Buzachis (@alinabuzachis) +version_added: 2.1.0 +requirements: + - vSphere 7.0.2 or greater + - python >= 3.6 + - aiohttp +extends_documentation_fragment: +- vmware.vmware_rest.moid +""" + + +EXAMPLES = r""" +# lookup sample +- name: set connection info + ansible.builtin.set_fact: + connection_args: + vcenter_hostname: "vcenter.test" + vcenter_username: "administrator@vsphere.local" + vcenter_password: "1234" + +- name: lookup MoID of the object + ansible.builtin.debug: msg="{{ lookup('vmware.vmware_rest.datastore_moid', '/my_dc/host/my_cluster/esxi1.test/ro_datastore', **connection_args) }}" + +- name: lookup MoID of the object inside the path + ansible.builtin.debug: msg="{{ lookup('vmware.vmware_rest.datastore_moid', '/my_dc/datastore/') }}" +""" + + +RETURN = r""" +_raw: + description: MoID of the vSphere datastore object + type: str + sample: datastore-1019 +""" + + +from ansible_collections.vmware.vmware_rest.plugins.plugin_utils.lookup import ( + Lookup, + get_credentials, +) +from ansible_collections.cloud.common.plugins.plugin_utils.turbo.lookup import ( + TurboLookupBase as LookupBase, +) + + +class LookupModule(LookupBase): + async def _run(self, terms, variables, **kwargs): + self.set_options(var_options=variables, direct=get_credentials(**kwargs)) + self.set_option("object_type", "datastore") + result = await Lookup.entry_point(terms, self._options) + return [result] + + run = _run if not hasattr(LookupBase, "run_on_daemon") else LookupBase.run_on_daemon diff --git a/ansible_collections/vmware/vmware_rest/plugins/lookup/folder_moid.py b/ansible_collections/vmware/vmware_rest/plugins/lookup/folder_moid.py new file mode 100644 index 00000000..aeca68ee --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/lookup/folder_moid.py @@ -0,0 +1,68 @@ +# Copyright: (c) 2021, Alina Buzachis <@alinabuzachis> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +name: folder_moid +short_description: Look up MoID for vSphere folder objects using vCenter REST API +description: + - Returns Managed Object Reference (MoID) of the vSphere folder object contained in the specified path. +author: + - Alina Buzachis (@alinabuzachis) +version_added: 2.1.0 +requirements: + - vSphere 7.0.2 or greater + - python >= 3.6 + - aiohttp +extends_documentation_fragment: +- vmware.vmware_rest.moid +""" + + +EXAMPLES = r""" +# lookup sample +- name: set connection info + ansible.builtin.set_fact: + connection_args: + vcenter_hostname: "vcenter.test" + vcenter_username: "administrator@vsphere.local" + vcenter_password: "1234" + +- name: lookup MoID of the object + ansible.builtin.debug: msg="{{ lookup('vmware.vmware_rest.folder_moid', '/my_dc/vm/foo/bar', **connection_args) }}" + +- name: lookup MoID of the object inside the path + ansible.builtin.debug: msg="{{ lookup('vmware.vmware_rest.folder_moid', '/my_dc/vm/foo/') }}" +""" + + +RETURN = r""" +_raw: + description: MoID of the vSphere folder object + type: str + sample: group-v1029 +""" + + +from ansible_collections.vmware.vmware_rest.plugins.plugin_utils.lookup import ( + Lookup, + get_credentials, +) +from ansible_collections.cloud.common.plugins.plugin_utils.turbo.lookup import ( + TurboLookupBase as LookupBase, +) + + +class LookupModule(LookupBase): + async def _run(self, terms, variables, **kwargs): + self.set_options(var_options=variables, direct=get_credentials(**kwargs)) + self.set_option("object_type", "folder") + result = await Lookup.entry_point(terms, self._options) + return [result] + + run = _run if not hasattr(LookupBase, "run_on_daemon") else LookupBase.run_on_daemon diff --git a/ansible_collections/vmware/vmware_rest/plugins/lookup/host_moid.py b/ansible_collections/vmware/vmware_rest/plugins/lookup/host_moid.py new file mode 100644 index 00000000..9e3b7bfc --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/lookup/host_moid.py @@ -0,0 +1,68 @@ +# Copyright: (c) 2021, Alina Buzachis <@alinabuzachis> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +name: host_moid +short_description: Look up MoID for vSphere host objects using vCenter REST API +description: + - Returns Managed Object Reference (MoID) of the vSphere host object contained in the specified path. +author: + - Alina Buzachis (@alinabuzachis) +version_added: 2.1.0 +requirements: + - vSphere 7.0.2 or greater + - python >= 3.6 + - aiohttp +extends_documentation_fragment: +- vmware.vmware_rest.moid +""" + + +EXAMPLES = r""" +# lookup sample +- name: set connection info + ansible.builtin.set_fact: + connection_args: + vcenter_hostname: "vcenter.test" + vcenter_username: "administrator@vsphere.local" + vcenter_password: "1234" + +- name: lookup MoID of the object + ansible.builtin.debug: msg="{{ lookup('vmware.vmware_rest.host_moid', '/my_dc/host/my_cluster/esxi1.test', **connection_args) }}" + +- name: lookup MoID of the object inside the path + ansible.builtin.debug: msg="{{ lookup('vmware.vmware_rest.host_moid', '/my_dc/host/my_cluster/') }}" +""" + + +RETURN = r""" +_raw: + description: MoID of the vSphere host object + type: str + sample: host-1014 +""" + + +from ansible_collections.vmware.vmware_rest.plugins.plugin_utils.lookup import ( + Lookup, + get_credentials, +) +from ansible_collections.cloud.common.plugins.plugin_utils.turbo.lookup import ( + TurboLookupBase as LookupBase, +) + + +class LookupModule(LookupBase): + async def _run(self, terms, variables, **kwargs): + self.set_options(var_options=variables, direct=get_credentials(**kwargs)) + self.set_option("object_type", "host") + result = await Lookup.entry_point(terms, self._options) + return [result] + + run = _run if not hasattr(LookupBase, "run_on_daemon") else LookupBase.run_on_daemon diff --git a/ansible_collections/vmware/vmware_rest/plugins/lookup/network_moid.py b/ansible_collections/vmware/vmware_rest/plugins/lookup/network_moid.py new file mode 100644 index 00000000..26b9dd80 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/lookup/network_moid.py @@ -0,0 +1,68 @@ +# Copyright: (c) 2021, Alina Buzachis <@alinabuzachis> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +name: network_moid +short_description: Look up MoID for vSphere network objects using vCenter REST API +description: + - Returns Managed Object Reference (MoID) of the vSphere network object contained in the specified path. +author: + - Alina Buzachis (@alinabuzachis) +version_added: 2.1.0 +requirements: + - vSphere 7.0.2 or greater + - python >= 3.6 + - aiohttp +extends_documentation_fragment: +- vmware.vmware_rest.moid +""" + + +EXAMPLES = r""" +# lookup sample +- name: set connection info + ansible.builtin.set_fact: + connection_args: + vcenter_hostname: "vcenter.test" + vcenter_username: "administrator@vsphere.local" + vcenter_password: "1234" + +- name: lookup MoID of the object + ansible.builtin.debug: msg="{{ lookup('vmware.vmware_rest.network_moid', '/my_dc/network/test_network', **connection_args) }}" + +- name: lookup MoID of the object inside the path + ansible.builtin.debug: msg="{{ lookup('vmware.vmware_rest.network_moid', '/my_dc/network/') }}" +""" + + +RETURN = r""" +_raw: + description: MoID of the vSphere network object + type: str + sample: network-1017 +""" + + +from ansible_collections.vmware.vmware_rest.plugins.plugin_utils.lookup import ( + Lookup, + get_credentials, +) +from ansible_collections.cloud.common.plugins.plugin_utils.turbo.lookup import ( + TurboLookupBase as LookupBase, +) + + +class LookupModule(LookupBase): + async def _run(self, terms, variables, **kwargs): + self.set_options(var_options=variables, direct=get_credentials(**kwargs)) + self.set_option("object_type", "network") + result = await Lookup.entry_point(terms, self._options) + return [result] + + run = _run if not hasattr(LookupBase, "run_on_daemon") else LookupBase.run_on_daemon diff --git a/ansible_collections/vmware/vmware_rest/plugins/lookup/resource_pool_moid.py b/ansible_collections/vmware/vmware_rest/plugins/lookup/resource_pool_moid.py new file mode 100644 index 00000000..c5d45be0 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/lookup/resource_pool_moid.py @@ -0,0 +1,68 @@ +# Copyright: (c) 2021, Alina Buzachis <@alinabuzachis> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +name: resource_pool_moid +short_description: Look up MoID for vSphere resource pool objects using vCenter REST API +description: + - Returns Managed Object Reference (MoID) of the vSphere resource pool object contained in the specified path. +author: + - Alina Buzachis (@alinabuzachis) +version_added: 2.1.0 +requirements: + - vSphere 7.0.2 or greater + - python >= 3.6 + - aiohttp +extends_documentation_fragment: +- vmware.vmware_rest.moid +""" + + +EXAMPLES = r""" +# lookup sample +- name: set connection info + ansible.builtin.set_fact: + connection_args: + vcenter_hostname: "vcenter.test" + vcenter_username: "administrator@vsphere.local" + vcenter_password: "1234" + +- name: lookup MoID of the object + ansible.builtin.debug: msg="{{ lookup('vmware.vmware_rest.resource_pool_moid', '/my_dc/host/my_cluster/Resources/my_resource_pool', **connection_args) }}" + +- name: lookup MoID of the object inside the path + ansible.builtin.debug: msg="{{ lookup('vmware.vmware_rest.resource_pool_moid', '/my_dc/host/my_cluster/Resources/') }}" +""" + + +RETURN = r""" +_raw: + description: MoID of the vSphere resource pool object + type: str + sample: resgroup-1008 +""" + + +from ansible_collections.vmware.vmware_rest.plugins.plugin_utils.lookup import ( + Lookup, + get_credentials, +) +from ansible_collections.cloud.common.plugins.plugin_utils.turbo.lookup import ( + TurboLookupBase as LookupBase, +) + + +class LookupModule(LookupBase): + async def _run(self, terms, variables, **kwargs): + self.set_options(var_options=variables, direct=get_credentials(**kwargs)) + self.set_option("object_type", "resource_pool") + result = await Lookup.entry_point(terms, self._options) + return [result] + + run = _run if not hasattr(LookupBase, "run_on_daemon") else LookupBase.run_on_daemon diff --git a/ansible_collections/vmware/vmware_rest/plugins/lookup/vm_moid.py b/ansible_collections/vmware/vmware_rest/plugins/lookup/vm_moid.py new file mode 100644 index 00000000..4a81ec55 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/lookup/vm_moid.py @@ -0,0 +1,68 @@ +# Copyright: (c) 2021, Alina Buzachis <@alinabuzachis> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +name: vm_moid +short_description: Look up MoID for vSphere vm objects using vCenter REST API +description: + - Returns Managed Object Reference (MoID) of the vSphere vm object contained in the specified path. +author: + - Alina Buzachis (@alinabuzachis) +version_added: 2.1.0 +requirements: + - vSphere 7.0.2 or greater + - python >= 3.6 + - aiohttp +extends_documentation_fragment: +- vmware.vmware_rest.moid +""" + + +EXAMPLES = r""" +# lookup sample +- name: set connection info + ansible.builtin.set_fact: + connection_args: + vcenter_hostname: "vcenter.test" + vcenter_username: "administrator@vsphere.local" + vcenter_password: "1234" + +- name: lookup MoID of the object + ansible.builtin.debug: msg="{{ lookup('vmware.vmware_rest.vm_moid', '/my_dc/host/my_cluster/esxi1.test/test_vm1', **connection_args) }}" + +- name: lookup MoID of the object inside the path + ansible.builtin.debug: msg="{{ lookup('vmware.vmware_rest.vm_moid', '/my_dc/vm/') }}" +""" + + +RETURN = r""" +_raw: + description: MoID of the vSphere vm object + type: str + sample: vm-1026 +""" + + +from ansible_collections.vmware.vmware_rest.plugins.plugin_utils.lookup import ( + Lookup, + get_credentials, +) +from ansible_collections.cloud.common.plugins.plugin_utils.turbo.lookup import ( + TurboLookupBase as LookupBase, +) + + +class LookupModule(LookupBase): + async def _run(self, terms, variables, **kwargs): + self.set_options(var_options=variables, direct=get_credentials(**kwargs)) + self.set_option("object_type", "vm") + result = await Lookup.entry_point(terms, self._options) + return [result] + + run = _run if not hasattr(LookupBase, "run_on_daemon") else LookupBase.run_on_daemon diff --git a/ansible_collections/vmware/vmware_rest/plugins/module_utils/vmware_rest.py b/ansible_collections/vmware/vmware_rest/plugins/module_utils/vmware_rest.py new file mode 100644 index 00000000..c61fa020 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/module_utils/vmware_rest.py @@ -0,0 +1,419 @@ +# This file is maintained in the vmware_rest_code_generator project +# https://github.com/ansible-collections/vmware_rest_code_generator +# Copyright (c) 2021 Ansible Project +# +# This code is part of Ansible, but is an independent component. +# This particular file snippet, and this file snippet only, is BSD licensed. +# Modules you write using this snippet, which is embedded dynamically by Ansible +# still belong to the author of the module, and may assign their own license +# to the complete work. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +import hashlib +import importlib +import json +import re + +from ansible.module_utils.basic import missing_required_lib +from ansible.module_utils.parsing.convert_bool import boolean + + +async def open_session( + vcenter_hostname=None, + vcenter_username=None, + vcenter_password=None, + validate_certs=True, + log_file=None, +): + validate_certs = boolean(validate_certs) + m = hashlib.sha256() + m.update(vcenter_hostname.encode()) + m.update(vcenter_username.encode()) + m.update(vcenter_password.encode()) + if log_file: + m.update(log_file.encode()) + m.update(b"yes" if validate_certs else b"no") + digest = m.hexdigest() + # TODO: Handle session timeout + if digest in open_session._pool: + return open_session._pool[digest] + + exceptions = importlib.import_module( + "ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions" + ) + try: + aiohttp = importlib.import_module("aiohttp") + except ImportError: + raise exceptions.EmbeddedModuleFailure(msg=missing_required_lib("aiohttp")) + + if not aiohttp: + raise exceptions.EmbeddedModuleFailure(msg="Failed to import aiohttp") + + if log_file: + trace_config = aiohttp.TraceConfig() + + async def on_request_end(session, trace_config_ctx, params): + with open(log_file, "a+", encoding="utf-8") as fd: + answer = await params.response.text() + fd.write( + f"{params.method}: {params.url}\n" + f"headers: {params.headers}\n" + f" status: {params.response.status}\n" + f" answer: {answer}\n\n" + ) + + trace_config.on_request_end.append(on_request_end) + trace_configs = [trace_config] + else: + trace_configs = [] + + auth = aiohttp.BasicAuth(vcenter_username, vcenter_password) + if validate_certs: + connector = aiohttp.TCPConnector(limit=20) + else: + connector = aiohttp.TCPConnector(limit=20, ssl=False) + async with aiohttp.ClientSession( + connector=connector, connector_owner=False, trace_configs=trace_configs + ) as session: + try: + async with session.post( + "https://{hostname}/rest/com/vmware/cis/session".format( + hostname=vcenter_hostname + ), + auth=auth, + ) as resp: + if resp.status != 200: + raise exceptions.EmbeddedModuleFailure( + "Authentication failure. code: {0}, json: {1}".format( + resp.status, await resp.text() + ) + ) + json = await resp.json() + except aiohttp.client_exceptions.ClientConnectorError as e: + raise exceptions.EmbeddedModuleFailure(f"Authentication failure: {e}") + + session_id = json["value"] + session = aiohttp.ClientSession( + connector=connector, + headers={ + "vmware-api-session-id": session_id, + "content-type": "application/json", + }, + connector_owner=False, + trace_configs=trace_configs, + ) + open_session._pool[digest] = session + return session + + +open_session._pool = {} + + +def gen_args(params, in_query_parameter): + args = "" + for i in in_query_parameter: + if i.startswith("filter."): # < 7.0.2 + v = params.get("filter_" + i[7:]) + else: + v = params.get(i) + if not v: + continue + if not args: + args = "?" + else: + args += "&" + if isinstance(v, list): + for j in v: + if j == v[-1]: + args += (i + "=") + j + else: + args += (i + "=") + j + "&" + elif isinstance(v, bool) and v: + args += i + "=true" + else: + args += (i + "=") + v + return args + + +def session_timeout(params): + exceptions = importlib.import_module( + "ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions" + ) + try: + aiohttp = importlib.import_module("aiohttp") + except ImportError: + raise exceptions.EmbeddedModuleFailure(msg=missing_required_lib("aiohttp")) + + if not aiohttp: + raise exceptions.EmbeddedModuleFailure(msg="Failed to import aiohttp") + out = {} + if params.get("session_timeout"): + out["timeout"] = aiohttp.ClientTimeout(total=params.get("session_timeout")) + return out + + +async def update_changed_flag(data, status, operation): + if data is None: + data = {"value": {}} + elif isinstance(data, list): # e.g: appliance_infraprofile_configs_info + data = {"value": data} + elif isinstance(data, str): + data = {"value": data} + elif isinstance(data, dict) and "value" not in data: # 7.0.2+ + data = {"value": data} + elif isinstance(data, bool): + data = {"value": data} + + if isinstance(data["value"], str) and data["value"][0] in [ + "{", + "]", + ]: # e.g: appliance_infraprofile_configs + data["value"] == json.loads(data["value"]) + + if status == 500: + data["failed"] = True + data["changed"] = False + elif operation in ["create", "clone", "instant_clone"] and status in [200, 201]: + data["failed"] = False + data["changed"] = True + elif operation == "update" and status in [200, 204]: + data["failed"] = False + data["changed"] = True + elif operation == "upgrade" and status in [200]: + data["failed"] = False + data["changed"] = True + elif operation == "set" and status in [200, 204]: + data["failed"] = False + data["changed"] = True + elif operation == "delete" and status in [200, 204]: + data["failed"] = False + data["changed"] = True + elif operation == "delete" and status == 404: + data["failed"] = False + data["changed"] = False + elif operation in ["get", "list"] and status in [200]: + data["failed"] = False + data["changed"] = False + elif operation in ["get", "list"] and status in [404]: + data["failed"] = True + data["changed"] = False + + elif status >= 400: + data["failed"] = True + data["changed"] = False + + if not isinstance(data["value"], dict): + pass + elif data.get("type") == "com.vmware.vapi.std.errors.not_found": + if operation == "delete": + data["failed"] = False + data["changed"] = False + else: + data["failed"] = True + data["changed"] = False + elif data.get("type") == "com.vmware.vapi.std.errors.already_in_desired_state": + data["failed"] = False + data["changed"] = False + elif data.get("type") == "com.vmware.vapi.std.errors.already_exists": + data["failed"] = False + data["changed"] = False + elif ( + data.get("value", {}).get("error_type") in ["NOT_FOUND"] + and operation == "delete" + ): + data["failed"] = False + data["changed"] = False + elif data.get("value", {}).get("error_type") in [ + "ALREADY_EXISTS", + "ALREADY_IN_DESIRED_STATE", + ]: + data["failed"] = False + data["changed"] = False + elif data.get("type") == "com.vmware.vapi.std.errors.resource_in_use": + # NOTE: this is a shortcut/hack. We get this issue if a CDROM already exists + data["failed"] = False + data["changed"] = False + elif ( + data.get("type") == "com.vmware.vapi.std.errors.internal_server_error" + and data["value"] + and data["value"]["messages"] + and data["value"]["messages"][0]["args"] + == [ + "com.vmware.vim.binding.vim.fault.DuplicateName cannot be cast to com.vmware.vim.binding.vim.fault.AlreadyConnected" + ] + ): + # NOTE: another one for vcenter_host + data["failed"] = False + data["changed"] = False + elif data.get("type", "").startswith("com.vmware.vapi.std.errors"): + data["failed"] = True + # 7.0.3, vcenter_ovf_libraryitem returns status 200 on failure + elif data.get("value", {}).get("error", {}).get("errors", []): + data["failed"] = True + + return data + + +async def list_devices(session, url): + existing_entries = [] + + async with session.get(url) as resp: + _json = await resp.json() + return _json + + +async def build_full_device_list(session, url, device_list): + import asyncio + + device_ids = [] + + if isinstance(device_list, list): + value = device_list + else: # 7.0.2 < + value = device_list["value"] + for i in value: + # Content library returns string {"value": "library_id"} + if isinstance(i, str): + device_ids.append(i) + continue + fields = list(i.values()) + if len(fields) != 1: + # The list already comes with all the details + return device_list + device_ids.append(fields[0]) + + tasks = [ + asyncio.ensure_future(get_device_info(session, url, _id)) for _id in device_ids + ] + + return [await i for i in tasks] + + +async def get_device_info(session, url, _id): + # remove the action=foo from the URL + m = re.search("(.+)(action=[-a-z]+)(.*)", url) + if m: + url = f"{m.group(1)}{m.group(3)}" + url = url.rstrip("?") + + # workaround for content_library_item_info + if "item?library_id=" in url: + item_url = url.split("?")[0] + "/" + _id + else: + item_url = url + "/" + _id + + async with session.get(item_url) as resp: + if resp.status == 200: + _json = await resp.json() + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + _json["id"] = str(_id) + return _json + + +async def exists( + params, session, url, uniquity_keys=None, per_id_url=None, comp_func=None +): + if not uniquity_keys: + uniquity_keys = [] + if not per_id_url: + per_id_url = url + + def default_comp_func(device): + for k in uniquity_keys: + if not params.get(k): + continue + if isinstance(device, dict): # 7.0.2 < + v = device["value"].get(k) + elif isinstance(device, list): + v = device + else: + exceptions = importlib.import_module( + "ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions" + ) + raise exceptions.EmbeddedModuleFailure(msg="Unexpect type") + + if isinstance(k, int) or isinstance(v, str): + k = str(k) + v = str(v) + if v == params.get(k): + return device + + if not comp_func: + comp_func = default_comp_func + + uniquity_keys += ["label", "pci_slot_number", "sata"] + + devices = await list_devices(session, url) + full_devices = await build_full_device_list(session, per_id_url, devices) + + for device in full_devices: + if comp_func(device): + return device + + +def set_subkey(root, path, value): + cur_loc = root + splitted = path.split("/") + for j in splitted[:-1]: + if j not in cur_loc: + cur_loc[j] = {} + cur_loc = cur_loc[j] + cur_loc[splitted[-1]] = value + + +def prepare_payload(params, payload_format): + payload = {} + for i in payload_format["body"].keys(): + if params[i] is None: + continue + + path = payload_format["body"][i] + set_subkey(payload, path, params[i]) + return payload + + +def get_subdevice_type(url): + """If url needs a subkey, return its name.""" + candidates = [] + for i in url.split("/"): + if i.startswith("{"): + candidates.append(i[1:-1]) + if len(candidates) != 2: + return + return candidates[-1].split("}")[0] + + +def get_device_type(url): + device_type = url.split("/")[-1] + # NOTE: This mapping can be extracted from the delete end-point of the + # resource, e.g: + # /rest/vcenter/vm/{vm}/hardware/ethernet/{nic} -> nic + # Also, it sounds like we can use "list_index" instead + if device_type == "ethernet": + return "nic" + elif device_type in ["sata", "scsi"]: + return "adapter" + elif device_type in ["parallel", "serial"]: + return "port" + else: + return device_type diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_access_consolecli.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_access_consolecli.py new file mode 100644 index 00000000..d852df20 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_access_consolecli.py @@ -0,0 +1,262 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_access_consolecli +short_description: Set enabled state of the console-based controlled CLI (TTY1). +description: Set enabled state of the console-based controlled CLI (TTY1). +options: + enabled: + description: + - Console-based controlled CLI is enabled. This parameter is mandatory. + required: true + type: bool + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - set + default: set + description: [] + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Disable the Console CLI + vmware.vmware_rest.appliance_access_consolecli: + enabled: false +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Disable the Console CLI +value: + description: Disable the Console CLI + returned: On success + sample: 0 + type: int +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "set": {"query": {}, "body": {"enabled": "enabled"}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["enabled"] = {"required": True, "type": "bool"} + argument_spec["state"] = {"type": "str", "choices": ["set"], "default": "set"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/access/consolecli").format( + **params + ) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _set(params, session): + _in_query_parameters = PAYLOAD_FORMAT["set"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["set"]) + subdevice_type = get_subdevice_type("/api/appliance/access/consolecli") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ("https://{vcenter_hostname}" "/api/appliance/access/consolecli").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, json=payload, **session_timeout(params)) as resp: + before = await resp.json() + + async with session.put(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # The PUT answer does not let us know if the resource has actually been + # modified + if resp.status < 300: + async with session.get( + _url, json=payload, **session_timeout(params) + ) as resp_get: + after = await resp_get.json() + if before == after: + return await update_changed_flag(after, resp_get.status, "get") + return await update_changed_flag(_json, resp.status, "set") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_access_consolecli_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_access_consolecli_info.py new file mode 100644 index 00000000..1fb5644b --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_access_consolecli_info.py @@ -0,0 +1,214 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_access_consolecli_info +short_description: Get enabled state of the console-based controlled CLI (TTY1). +description: Get enabled state of the console-based controlled CLI (TTY1). +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Check if the Console CLI is enabled + vmware.vmware_rest.appliance_access_consolecli_info: +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Check if the Console CLI is enabled +value: + description: Check if the Console CLI is enabled + returned: On success + sample: 0 + type: int +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/access/consolecli").format( + **params + ) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ("https://{vcenter_hostname}" "/api/appliance/access/consolecli").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_access_dcui.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_access_dcui.py new file mode 100644 index 00000000..4a8aad36 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_access_dcui.py @@ -0,0 +1,260 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_access_dcui +short_description: Set enabled state of Direct Console User Interface (DCUI TTY2). +description: Set enabled state of Direct Console User Interface (DCUI TTY2). +options: + enabled: + description: + - DCUI is enabled. This parameter is mandatory. + required: true + type: bool + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - set + default: set + description: [] + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Disable the Direct Console User Interface + vmware.vmware_rest.appliance_access_dcui: + enabled: false +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Disable the Direct Console User Interface +value: + description: Disable the Direct Console User Interface + returned: On success + sample: 0 + type: int +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "set": {"query": {}, "body": {"enabled": "enabled"}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["enabled"] = {"required": True, "type": "bool"} + argument_spec["state"] = {"type": "str", "choices": ["set"], "default": "set"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/access/dcui").format(**params) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _set(params, session): + _in_query_parameters = PAYLOAD_FORMAT["set"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["set"]) + subdevice_type = get_subdevice_type("/api/appliance/access/dcui") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ("https://{vcenter_hostname}" "/api/appliance/access/dcui").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, json=payload, **session_timeout(params)) as resp: + before = await resp.json() + + async with session.put(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # The PUT answer does not let us know if the resource has actually been + # modified + if resp.status < 300: + async with session.get( + _url, json=payload, **session_timeout(params) + ) as resp_get: + after = await resp_get.json() + if before == after: + return await update_changed_flag(after, resp_get.status, "get") + return await update_changed_flag(_json, resp.status, "set") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_access_dcui_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_access_dcui_info.py new file mode 100644 index 00000000..f0d0ca90 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_access_dcui_info.py @@ -0,0 +1,212 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_access_dcui_info +short_description: Get enabled state of Direct Console User Interface (DCUI TTY2). +description: Get enabled state of Direct Console User Interface (DCUI TTY2). +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Check if the Direct Console User Interface is enabled + vmware.vmware_rest.appliance_access_dcui_info: +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Check if the Direct Console User Interface is enabled +value: + description: Check if the Direct Console User Interface is enabled + returned: On success + sample: 0 + type: int +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/access/dcui").format(**params) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ("https://{vcenter_hostname}" "/api/appliance/access/dcui").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_access_shell.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_access_shell.py new file mode 100644 index 00000000..c0233e56 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_access_shell.py @@ -0,0 +1,282 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_access_shell +short_description: Set enabled state of BASH, that is, access to BASH from within + the controlled CLI. +description: Set enabled state of BASH, that is, access to BASH from within the controlled + CLI. +options: + enabled: + description: + - Enabled can be set to true or false This parameter is mandatory. + required: true + type: bool + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - set + default: set + description: [] + type: str + timeout: + description: + - The timeout (in seconds) specifies how long you enable the Shell access. The + maximum timeout is 86400 seconds(1 day). This parameter is mandatory. + required: true + type: int + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Disable the Shell + vmware.vmware_rest.appliance_access_shell: + enabled: false + timeout: 600 + +- name: Enable the Shell with a timeout + vmware.vmware_rest.appliance_access_shell: + enabled: true + timeout: 600 + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Disable the Shell +value: + description: Disable the Shell + returned: On success + sample: + enabled: 0 + timeout: 0 + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "set": { + "query": {}, + "body": {"enabled": "enabled", "timeout": "timeout"}, + "path": {}, + } +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["enabled"] = {"required": True, "type": "bool"} + argument_spec["state"] = {"type": "str", "choices": ["set"], "default": "set"} + argument_spec["timeout"] = {"required": True, "type": "int"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/access/shell").format(**params) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _set(params, session): + _in_query_parameters = PAYLOAD_FORMAT["set"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["set"]) + subdevice_type = get_subdevice_type("/api/appliance/access/shell") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ("https://{vcenter_hostname}" "/api/appliance/access/shell").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, json=payload, **session_timeout(params)) as resp: + before = await resp.json() + + async with session.put(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # The PUT answer does not let us know if the resource has actually been + # modified + if resp.status < 300: + async with session.get( + _url, json=payload, **session_timeout(params) + ) as resp_get: + after = await resp_get.json() + if before == after: + return await update_changed_flag(after, resp_get.status, "get") + return await update_changed_flag(_json, resp.status, "set") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_access_shell_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_access_shell_info.py new file mode 100644 index 00000000..1193ef97 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_access_shell_info.py @@ -0,0 +1,217 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_access_shell_info +short_description: Get enabled state of BASH, that is, access to BASH from within + the controlled CLI. +description: Get enabled state of BASH, that is, access to BASH from within the controlled + CLI. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Check if the Shell is enabled + vmware.vmware_rest.appliance_access_shell_info: + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Check if the Shell is enabled +value: + description: Check if the Shell is enabled + returned: On success + sample: + enabled: 0 + timeout: 0 + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/access/shell").format(**params) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ("https://{vcenter_hostname}" "/api/appliance/access/shell").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_access_ssh.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_access_ssh.py new file mode 100644 index 00000000..d053a06c --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_access_ssh.py @@ -0,0 +1,261 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_access_ssh +short_description: Set enabled state of the SSH-based controlled CLI. +description: Set enabled state of the SSH-based controlled CLI. +options: + enabled: + description: + - SSH-based controlled CLI is enabled. This parameter is mandatory. + required: true + type: bool + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - set + default: set + description: [] + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Ensure the SSH access ie enabled + vmware.vmware_rest.appliance_access_ssh: + enabled: true + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Ensure the SSH access ie enabled +value: + description: Ensure the SSH access ie enabled + returned: On success + sample: 1 + type: int +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "set": {"query": {}, "body": {"enabled": "enabled"}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["enabled"] = {"required": True, "type": "bool"} + argument_spec["state"] = {"type": "str", "choices": ["set"], "default": "set"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/access/ssh").format(**params) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _set(params, session): + _in_query_parameters = PAYLOAD_FORMAT["set"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["set"]) + subdevice_type = get_subdevice_type("/api/appliance/access/ssh") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ("https://{vcenter_hostname}" "/api/appliance/access/ssh").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, json=payload, **session_timeout(params)) as resp: + before = await resp.json() + + async with session.put(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # The PUT answer does not let us know if the resource has actually been + # modified + if resp.status < 300: + async with session.get( + _url, json=payload, **session_timeout(params) + ) as resp_get: + after = await resp_get.json() + if before == after: + return await update_changed_flag(after, resp_get.status, "get") + return await update_changed_flag(_json, resp.status, "set") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_access_ssh_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_access_ssh_info.py new file mode 100644 index 00000000..58b75904 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_access_ssh_info.py @@ -0,0 +1,213 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_access_ssh_info +short_description: Get enabled state of the SSH-based controlled CLI. +description: Get enabled state of the SSH-based controlled CLI. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Check is the SSH access is enabled + vmware.vmware_rest.appliance_access_ssh_info: + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Check is the SSH access is enabled +value: + description: Check is the SSH access is enabled + returned: On success + sample: 1 + type: int +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/access/ssh").format(**params) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ("https://{vcenter_hostname}" "/api/appliance/access/ssh").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_health_applmgmt_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_health_applmgmt_info.py new file mode 100644 index 00000000..e419ca47 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_health_applmgmt_info.py @@ -0,0 +1,215 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_health_applmgmt_info +short_description: Get health status of applmgmt services. +description: Get health status of applmgmt services. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Get the health state of applmgmt + vmware.vmware_rest.appliance_health_applmgmt_info: + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get the health state of applmgmt +value: + description: Get the health state of applmgmt + returned: On success + sample: green + type: str +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/health/applmgmt").format( + **params + ) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ("https://{vcenter_hostname}" "/api/appliance/health/applmgmt").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_health_database_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_health_database_info.py new file mode 100644 index 00000000..e374841e --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_health_database_info.py @@ -0,0 +1,222 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_health_database_info +short_description: Returns the health status of the database. +description: Returns the health status of the database. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Get the database heath status + vmware.vmware_rest.appliance_health_database_info: + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get the database heath status +value: + description: Get the database heath status + returned: On success + sample: + messages: + - message: + args: [] + default_message: DB state is Healthy + id: desc + severity: ' ' + status: HEALTHY + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/health/database").format( + **params + ) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ("https://{vcenter_hostname}" "/api/appliance/health/database").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_health_databasestorage_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_health_databasestorage_info.py new file mode 100644 index 00000000..7d156bad --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_health_databasestorage_info.py @@ -0,0 +1,215 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_health_databasestorage_info +short_description: Get database storage health. +description: Get database storage health. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Get the database storage heath status + vmware.vmware_rest.appliance_health_databasestorage_info: + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get the database storage heath status +value: + description: Get the database storage heath status + returned: On success + sample: green + type: str +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ( + "https://{vcenter_hostname}" "/api/appliance/health/database-storage" + ).format(**params) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ( + "https://{vcenter_hostname}" "/api/appliance/health/database-storage" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_health_load_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_health_load_info.py new file mode 100644 index 00000000..3e1b3e14 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_health_load_info.py @@ -0,0 +1,213 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_health_load_info +short_description: Get load health. +description: Get load health. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Get the system load status + vmware.vmware_rest.appliance_health_load_info: + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get the system load status +value: + description: Get the system load status + returned: On success + sample: green + type: str +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/health/load").format(**params) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ("https://{vcenter_hostname}" "/api/appliance/health/load").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_health_mem_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_health_mem_info.py new file mode 100644 index 00000000..495078fe --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_health_mem_info.py @@ -0,0 +1,213 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_health_mem_info +short_description: Get memory health. +description: Get memory health. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Get the system mem status + vmware.vmware_rest.appliance_health_mem_info: + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get the system mem status +value: + description: Get the system mem status + returned: On success + sample: green + type: str +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/health/mem").format(**params) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ("https://{vcenter_hostname}" "/api/appliance/health/mem").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_health_softwarepackages_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_health_softwarepackages_info.py new file mode 100644 index 00000000..a384ca94 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_health_softwarepackages_info.py @@ -0,0 +1,220 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_health_softwarepackages_info +short_description: Get information on available software updates available in the + remote vSphere Update Manager repository +description: Get information on available software updates available in the remote + vSphere Update Manager repository. Red indicates that security updates are available. + Orange indicates that non-security updates are available. Green indicates that there + are no updates available. Gray indicates that there was an error retreiving information + on software updates. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Get the health of the software package manager + vmware.vmware_rest.appliance_health_softwarepackages_info: + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get the health of the software package manager +value: + description: Get the health of the software package manager + returned: On success + sample: green + type: str +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ( + "https://{vcenter_hostname}" "/api/appliance/health/software-packages" + ).format(**params) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ( + "https://{vcenter_hostname}" "/api/appliance/health/software-packages" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_health_storage_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_health_storage_info.py new file mode 100644 index 00000000..395fe7a6 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_health_storage_info.py @@ -0,0 +1,215 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_health_storage_info +short_description: Get storage health. +description: Get storage health. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Get the health of the storage system + vmware.vmware_rest.appliance_health_storage_info: + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get the health of the storage system +value: + description: Get the health of the storage system + returned: On success + sample: green + type: str +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/health/storage").format( + **params + ) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ("https://{vcenter_hostname}" "/api/appliance/health/storage").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_health_swap_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_health_swap_info.py new file mode 100644 index 00000000..6b928932 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_health_swap_info.py @@ -0,0 +1,213 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_health_swap_info +short_description: Get swap health. +description: Get swap health. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Get the health of the swap + vmware.vmware_rest.appliance_health_swap_info: + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get the health of the swap +value: + description: Get the health of the swap + returned: On success + sample: green + type: str +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/health/swap").format(**params) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ("https://{vcenter_hostname}" "/api/appliance/health/swap").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_health_system_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_health_system_info.py new file mode 100644 index 00000000..2f8a590f --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_health_system_info.py @@ -0,0 +1,215 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_health_system_info +short_description: Get overall health of system. +description: Get overall health of system. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Get the system health status + vmware.vmware_rest.appliance_health_system_info: + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get the system health status +value: + description: Get the system health status + returned: On success + sample: green + type: str +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/health/system").format( + **params + ) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ("https://{vcenter_hostname}" "/api/appliance/health/system").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_infraprofile_configs.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_infraprofile_configs.py new file mode 100644 index 00000000..e5757b49 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_infraprofile_configs.py @@ -0,0 +1,291 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_infraprofile_configs +short_description: Exports the desired profile specification. +description: Exports the desired profile specification. +options: + description: + description: + - Custom description provided by the user. + - If unset description will be empty. + type: str + encryption_key: + description: + - Encryption Key to encrypt/decrypt profiles. + - If unset encryption will not be used for the profile. + type: str + profiles: + description: + - Profiles to be exported/imported. + - If unset or empty, all profiles will be returned. + - When clients pass a value of this structure as a parameter, the field must contain + the id of resources returned by M(vmware.vmware_rest.appliance_infraprofile_configs). + elements: str + type: list + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - export + description: [] + required: true + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Export the ApplianceManagement profile + vmware.vmware_rest.appliance_infraprofile_configs: + state: export + profiles: + - ApplianceManagement + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Export the ApplianceManagement profile +value: + description: Export the ApplianceManagement profile + returned: On success + sample: '{"action":"RESTART_SERVICE","productName":"VMware vCenter Server","version":"7.0.3.00600","creationTime":"2022-06-23T22:43:48+0000","profiles":{"ApplianceManagement":{"action":"RESTART_SERVICE","actionOn":{"SYSTEMD":["sendmail","rsyslog"],"VC_SERVICES":["applmgmt"]},"version":"7.0","description":"Appliance + Mangment Service","config":{"/etc/applmgmt/appliance/appliance.conf":{"Is shell + Enabled":true,"Shell Expiration Time":9,"TimeSync Mode (Host/NTP)":"NTP"},"/etc/sysconfig/clock":{"Time + zone":"\"UTC\"","UTC":"1"},"/usr/bin/systemctl/sshd.service":{"Enable SSH":"true"},"/etc/ntp.conf":{"Time + servers":["time.google.com"]},"/etc/mail/sendmail.cf":{"SMTP Port":null,"Mail + server":null},"/etc/vmware-syslog/syslog.conf":{"Port [2]":null,"Port [1]":null,"Port + [0]":null,"Protocol [2]":null,"Remote Syslog Host [1]":null,"Protocol [1]":null,"Remote + Syslog Host [0]":null,"Protocol [0]":null,"Remote Syslog Host [2]":null},"/etc/pam.d/system-auth":{"Deny + Login after these many Unsuccessful Attempts.":null,"Unlock root after (seconds)":null,"On + Error Login will be.":null,"Include Root user for SSH lockout.":null,"Unlock user + after (seconds)":null},"/etc/shadow":{"root":{"maximumDays":"90","warningDays":"7"},"bin":{"maximumDays":"90","warningDays":"7"},"daemon":{"maximumDays":"90","warningDays":"7"},"messagebus":{"maximumDays":"90","warningDays":"7"},"systemd-bus-proxy":{"maximumDays":"90","warningDays":"7"},"systemd-journal-gateway":{"maximumDays":"90","warningDays":"7"},"systemd-journal-remote":{"maximumDays":"90","warningDays":"7"},"systemd-journal-upload":{"maximumDays":"90","warningDays":"7"},"systemd-network":{"maximumDays":"90","warningDays":"7"},"systemd-resolve":{"maximumDays":"90","warningDays":"7"},"systemd-timesync":{"maximumDays":"90","warningDays":"7"},"nobody":{"maximumDays":"90","warningDays":"7"},"rpc":{"maximumDays":"90","warningDays":"7"},"ntp":{"maximumDays":"90","warningDays":"7"},"sshd":{"maximumDays":"90","warningDays":"7"},"smmsp":{"maximumDays":"90","warningDays":"7"},"apache":{"maximumDays":"90","warningDays":"7"},"sso-user":{"maximumDays":"90","warningDays":"7"},"vpostgres":{"maximumDays":"","warningDays":"7"},"vapiEndpoint":{"maximumDays":"90","warningDays":"7"},"eam":{"maximumDays":"90","warningDays":"7"},"vlcm":{"maximumDays":"90","warningDays":"7"},"vsan-health":{"maximumDays":"90","warningDays":"7"},"vsm":{"maximumDays":"90","warningDays":"7"},"vsphere-ui":{"maximumDays":"90","warningDays":"7"},"wcp":{"maximumDays":"","warningDays":"7"},"content-library":{"maximumDays":"90","warningDays":"7"},"imagebuilder":{"maximumDays":"90","warningDays":"7"},"perfcharts":{"maximumDays":"90","warningDays":"7"},"vpgmonusr":{"maximumDays":"","warningDays":"7"},"vtsdbmonusr":{"maximumDays":"","warningDays":"7"},"zuul":{"maximumDays":"90","warningDays":"7"},"Send + Waring before this No of Days.":null,"Password validity (days)":null}},"name":"ApplianceManagement"}}}' + type: str +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "export": { + "query": {}, + "body": { + "description": "description", + "encryption_key": "encryption_key", + "profiles": "profiles", + }, + "path": {}, + } +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["description"] = {"type": "str"} + argument_spec["encryption_key"] = {"no_log": True, "type": "str"} + argument_spec["profiles"] = {"type": "list", "elements": "str"} + argument_spec["state"] = {"required": True, "type": "str", "choices": ["export"]} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/infraprofile/configs").format( + **params + ) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _export(params, session): + _in_query_parameters = PAYLOAD_FORMAT["export"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["export"]) + subdevice_type = get_subdevice_type( + "/api/appliance/infraprofile/configs?action=export" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/appliance/infraprofile/configs?action=export" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "export") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_infraprofile_configs_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_infraprofile_configs_info.py new file mode 100644 index 00000000..bac5be91 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_infraprofile_configs_info.py @@ -0,0 +1,214 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_infraprofile_configs_info +short_description: List all the profiles which are registered. +description: List all the profiles which are registered. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: List infraprofile configs + vmware.vmware_rest.appliance_infraprofile_configs_info: + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: List infraprofile configs +value: + description: List infraprofile configs + returned: On success + sample: + - info: Appliance Mangment Service + name: ApplianceManagement + - info: ApplianceNetwork + name: ApplianceNetwork + - info: Authentication & Authorization Management + name: AuthManagement + type: list +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "list": {"query": {}, "body": {}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_list_and_get_module.j2 +def build_url(params): + _in_query_parameters = PAYLOAD_FORMAT["list"]["query"].keys() + return ("https://{vcenter_hostname}" "/api/appliance/infraprofile/configs").format( + **params + ) + gen_args(params, _in_query_parameters) + + +async def entry_point(module, session): + url = build_url(module.params) + async with session.get(url, **session_timeout(module.params)) as resp: + _json = await resp.json() + + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_localaccounts_globalpolicy.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_localaccounts_globalpolicy.py new file mode 100644 index 00000000..550331d3 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_localaccounts_globalpolicy.py @@ -0,0 +1,285 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_localaccounts_globalpolicy +short_description: Set the global password policy. +description: Set the global password policy. +options: + max_days: + description: + - Maximum number of days a password may be used. If the password is older than + this, a password change will be forced. + type: int + min_days: + description: + - Minimum number of days allowed between password changes. Any password changes + attempted sooner than this will be rejected. + type: int + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - set + default: set + description: [] + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + warn_days: + description: + - Number of days warning given before a password expires. A zero means warning + is given only upon the day of expiration. + type: int +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Update the global policy of the local accounts + vmware.vmware_rest.appliance_localaccounts_globalpolicy: + warn_days: 5 +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Update the global policy of the local accounts +value: + description: Update the global policy of the local accounts + returned: On success + sample: + max_days: -1 + min_days: -1 + warn_days: 5 + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "set": { + "query": {}, + "body": { + "max_days": "max_days", + "min_days": "min_days", + "warn_days": "warn_days", + }, + "path": {}, + } +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["max_days"] = {"type": "int"} + argument_spec["min_days"] = {"type": "int"} + argument_spec["state"] = {"type": "str", "choices": ["set"], "default": "set"} + argument_spec["warn_days"] = {"type": "int"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ( + "https://{vcenter_hostname}" "/api/appliance/local-accounts/global-policy" + ).format(**params) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _set(params, session): + _in_query_parameters = PAYLOAD_FORMAT["set"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["set"]) + subdevice_type = get_subdevice_type("/api/appliance/local-accounts/global-policy") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" "/api/appliance/local-accounts/global-policy" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.get(_url, json=payload, **session_timeout(params)) as resp: + before = await resp.json() + + async with session.put(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # The PUT answer does not let us know if the resource has actually been + # modified + if resp.status < 300: + async with session.get( + _url, json=payload, **session_timeout(params) + ) as resp_get: + after = await resp_get.json() + if before == after: + return await update_changed_flag(after, resp_get.status, "get") + return await update_changed_flag(_json, resp.status, "set") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_localaccounts_globalpolicy_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_localaccounts_globalpolicy_info.py new file mode 100644 index 00000000..cd8a7057 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_localaccounts_globalpolicy_info.py @@ -0,0 +1,218 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_localaccounts_globalpolicy_info +short_description: Get the global password policy. +description: Get the global password policy. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Get the global policy of the local accounts + vmware.vmware_rest.appliance_localaccounts_globalpolicy_info: + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get the global policy of the local accounts +value: + description: Get the global policy of the local accounts + returned: On success + sample: + max_days: -1 + min_days: -1 + warn_days: 5 + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ( + "https://{vcenter_hostname}" "/api/appliance/local-accounts/global-policy" + ).format(**params) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ( + "https://{vcenter_hostname}" "/api/appliance/local-accounts/global-policy" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_localaccounts_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_localaccounts_info.py new file mode 100644 index 00000000..af2491b6 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_localaccounts_info.py @@ -0,0 +1,265 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_localaccounts_info +short_description: Get the local user account information. +description: Get the local user account information. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + username: + description: + - User login name Required with I(state=['get']) + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: List the local accounts + vmware.vmware_rest.appliance_localaccounts_info: + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: List the local accounts +value: + description: List the local accounts + returned: On success + sample: + - enabled: 1 + fullname: root + has_password: 1 + last_password_change: '2022-06-23T00:00:00.000Z' + max_days_between_password_change: 90 + min_days_between_password_change: 0 + password_expires_at: '2022-09-21T00:00:00.000Z' + roles: + - superAdmin + warn_days_before_password_expiration: 7 + - enabled: 0 + has_password: 0 + inactive_at: '2022-09-14T00:00:00.000Z' + last_password_change: '2022-06-16T00:00:00.000Z' + max_days_between_password_change: 90 + min_days_between_password_change: 1 + password_expires_at: '2022-09-14T00:00:00.000Z' + roles: + - '' + warn_days_before_password_expiration: 7 + - enabled: 0 + has_password: 0 + last_password_change: '2022-06-16T00:00:00.000Z' + max_days_between_password_change: -1 + min_days_between_password_change: -1 + roles: + - '' + warn_days_before_password_expiration: -1 + type: list +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"username": "username"}}, + "list": {"query": {}, "body": {}, "path": {}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["username"] = {"no_log": True, "type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_list_and_get_module.j2 +def build_url(params): + if params.get("username"): + _in_query_parameters = PAYLOAD_FORMAT["get"]["query"].keys() + return ( + ("https://{vcenter_hostname}" "/api/appliance/local-accounts/").format( + **params + ) + + params["username"] + + gen_args(params, _in_query_parameters) + ) + _in_query_parameters = PAYLOAD_FORMAT["list"]["query"].keys() + return ("https://{vcenter_hostname}" "/api/appliance/local-accounts").format( + **params + ) + gen_args(params, _in_query_parameters) + + +async def entry_point(module, session): + url = build_url(module.params) + async with session.get(url, **session_timeout(module.params)) as resp: + _json = await resp.json() + + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + + if module.params.get("username"): + _json["id"] = module.params.get("username") + elif module.params.get("label"): # TODO extend the list of filter + _json = await exists(module.params, session, url) + elif ( + isinstance(_json["value"], list) + and len(_json["value"]) > 0 + and isinstance(_json["value"][0], str) + ): + # this is a list of id, we fetch the details + full_device_list = await build_full_device_list(session, url, _json) + _json = {"value": [i["value"] for i in full_device_list]} + + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_monitoring_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_monitoring_info.py new file mode 100644 index 00000000..85b7c1b9 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_monitoring_info.py @@ -0,0 +1,1057 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_monitoring_info +short_description: Get monitored item info +description: Get monitored item info +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + stat_id: + description: + - statistic item id Required with I(state=['get']) + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Get the list of the monitored items + vmware.vmware_rest.appliance_monitoring_info: + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get the list of the monitored items +value: + description: Get the list of the monitored items + returned: On success + sample: + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.read.rate.dm-1 + id: disk.read.rate.dm-1 + instance: dm-1 + name: com.vmware.applmgmt.mon.name.disk.read.rate.dm-1 + units: com.vmware.applmgmt.mon.unit.num_of_io_per_msec + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.read.rate.dm-10 + id: disk.read.rate.dm-10 + instance: dm-10 + name: com.vmware.applmgmt.mon.name.disk.read.rate.dm-10 + units: com.vmware.applmgmt.mon.unit.num_of_io_per_msec + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.read.rate.dm-11 + id: disk.read.rate.dm-11 + instance: dm-11 + name: com.vmware.applmgmt.mon.name.disk.read.rate.dm-11 + units: com.vmware.applmgmt.mon.unit.num_of_io_per_msec + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.read.rate.dm-12 + id: disk.read.rate.dm-12 + instance: dm-12 + name: com.vmware.applmgmt.mon.name.disk.read.rate.dm-12 + units: com.vmware.applmgmt.mon.unit.num_of_io_per_msec + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.read.rate.dm-13 + id: disk.read.rate.dm-13 + instance: dm-13 + name: com.vmware.applmgmt.mon.name.disk.read.rate.dm-13 + units: com.vmware.applmgmt.mon.unit.num_of_io_per_msec + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.read.rate.dm-14 + id: disk.read.rate.dm-14 + instance: dm-14 + name: com.vmware.applmgmt.mon.name.disk.read.rate.dm-14 + units: com.vmware.applmgmt.mon.unit.num_of_io_per_msec + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.read.rate.dm-15 + id: disk.read.rate.dm-15 + instance: dm-15 + name: com.vmware.applmgmt.mon.name.disk.read.rate.dm-15 + units: com.vmware.applmgmt.mon.unit.num_of_io_per_msec + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.read.rate.dm-2 + id: disk.read.rate.dm-2 + instance: dm-2 + name: com.vmware.applmgmt.mon.name.disk.read.rate.dm-2 + units: com.vmware.applmgmt.mon.unit.num_of_io_per_msec + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.read.rate.dm-3 + id: disk.read.rate.dm-3 + instance: dm-3 + name: com.vmware.applmgmt.mon.name.disk.read.rate.dm-3 + units: com.vmware.applmgmt.mon.unit.num_of_io_per_msec + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.read.rate.dm-4 + id: disk.read.rate.dm-4 + instance: dm-4 + name: com.vmware.applmgmt.mon.name.disk.read.rate.dm-4 + units: com.vmware.applmgmt.mon.unit.num_of_io_per_msec + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.read.rate.dm-5 + id: disk.read.rate.dm-5 + instance: dm-5 + name: com.vmware.applmgmt.mon.name.disk.read.rate.dm-5 + units: com.vmware.applmgmt.mon.unit.num_of_io_per_msec + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.read.rate.dm-6 + id: disk.read.rate.dm-6 + instance: dm-6 + name: com.vmware.applmgmt.mon.name.disk.read.rate.dm-6 + units: com.vmware.applmgmt.mon.unit.num_of_io_per_msec + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.read.rate.dm-7 + id: disk.read.rate.dm-7 + instance: dm-7 + name: com.vmware.applmgmt.mon.name.disk.read.rate.dm-7 + units: com.vmware.applmgmt.mon.unit.num_of_io_per_msec + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.read.rate.dm-8 + id: disk.read.rate.dm-8 + instance: dm-8 + name: com.vmware.applmgmt.mon.name.disk.read.rate.dm-8 + units: com.vmware.applmgmt.mon.unit.num_of_io_per_msec + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.read.rate.dm-9 + id: disk.read.rate.dm-9 + instance: dm-9 + name: com.vmware.applmgmt.mon.name.disk.read.rate.dm-9 + units: com.vmware.applmgmt.mon.unit.num_of_io_per_msec + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.write.rate.dm-1 + id: disk.write.rate.dm-1 + instance: dm-1 + name: com.vmware.applmgmt.mon.name.disk.write.rate.dm-1 + units: com.vmware.applmgmt.mon.unit.num_of_io_per_msec + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.write.rate.dm-10 + id: disk.write.rate.dm-10 + instance: dm-10 + name: com.vmware.applmgmt.mon.name.disk.write.rate.dm-10 + units: com.vmware.applmgmt.mon.unit.num_of_io_per_msec + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.write.rate.dm-11 + id: disk.write.rate.dm-11 + instance: dm-11 + name: com.vmware.applmgmt.mon.name.disk.write.rate.dm-11 + units: com.vmware.applmgmt.mon.unit.num_of_io_per_msec + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.write.rate.dm-12 + id: disk.write.rate.dm-12 + instance: dm-12 + name: com.vmware.applmgmt.mon.name.disk.write.rate.dm-12 + units: com.vmware.applmgmt.mon.unit.num_of_io_per_msec + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.write.rate.dm-13 + id: disk.write.rate.dm-13 + instance: dm-13 + name: com.vmware.applmgmt.mon.name.disk.write.rate.dm-13 + units: com.vmware.applmgmt.mon.unit.num_of_io_per_msec + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.write.rate.dm-14 + id: disk.write.rate.dm-14 + instance: dm-14 + name: com.vmware.applmgmt.mon.name.disk.write.rate.dm-14 + units: com.vmware.applmgmt.mon.unit.num_of_io_per_msec + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.write.rate.dm-15 + id: disk.write.rate.dm-15 + instance: dm-15 + name: com.vmware.applmgmt.mon.name.disk.write.rate.dm-15 + units: com.vmware.applmgmt.mon.unit.num_of_io_per_msec + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.write.rate.dm-2 + id: disk.write.rate.dm-2 + instance: dm-2 + name: com.vmware.applmgmt.mon.name.disk.write.rate.dm-2 + units: com.vmware.applmgmt.mon.unit.num_of_io_per_msec + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.write.rate.dm-3 + id: disk.write.rate.dm-3 + instance: dm-3 + name: com.vmware.applmgmt.mon.name.disk.write.rate.dm-3 + units: com.vmware.applmgmt.mon.unit.num_of_io_per_msec + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.write.rate.dm-4 + id: disk.write.rate.dm-4 + instance: dm-4 + name: com.vmware.applmgmt.mon.name.disk.write.rate.dm-4 + units: com.vmware.applmgmt.mon.unit.num_of_io_per_msec + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.write.rate.dm-5 + id: disk.write.rate.dm-5 + instance: dm-5 + name: com.vmware.applmgmt.mon.name.disk.write.rate.dm-5 + units: com.vmware.applmgmt.mon.unit.num_of_io_per_msec + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.write.rate.dm-6 + id: disk.write.rate.dm-6 + instance: dm-6 + name: com.vmware.applmgmt.mon.name.disk.write.rate.dm-6 + units: com.vmware.applmgmt.mon.unit.num_of_io_per_msec + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.write.rate.dm-7 + id: disk.write.rate.dm-7 + instance: dm-7 + name: com.vmware.applmgmt.mon.name.disk.write.rate.dm-7 + units: com.vmware.applmgmt.mon.unit.num_of_io_per_msec + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.write.rate.dm-8 + id: disk.write.rate.dm-8 + instance: dm-8 + name: com.vmware.applmgmt.mon.name.disk.write.rate.dm-8 + units: com.vmware.applmgmt.mon.unit.num_of_io_per_msec + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.write.rate.dm-9 + id: disk.write.rate.dm-9 + instance: dm-9 + name: com.vmware.applmgmt.mon.name.disk.write.rate.dm-9 + units: com.vmware.applmgmt.mon.unit.num_of_io_per_msec + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.latency.rate.dm-1 + id: disk.latency.rate.dm-1 + instance: dm-1 + name: com.vmware.applmgmt.mon.name.disk.latency.rate.dm-1 + units: com.vmware.applmgmt.mon.unit.msec_per_io + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.latency.rate.dm-10 + id: disk.latency.rate.dm-10 + instance: dm-10 + name: com.vmware.applmgmt.mon.name.disk.latency.rate.dm-10 + units: com.vmware.applmgmt.mon.unit.msec_per_io + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.latency.rate.dm-11 + id: disk.latency.rate.dm-11 + instance: dm-11 + name: com.vmware.applmgmt.mon.name.disk.latency.rate.dm-11 + units: com.vmware.applmgmt.mon.unit.msec_per_io + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.latency.rate.dm-12 + id: disk.latency.rate.dm-12 + instance: dm-12 + name: com.vmware.applmgmt.mon.name.disk.latency.rate.dm-12 + units: com.vmware.applmgmt.mon.unit.msec_per_io + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.latency.rate.dm-13 + id: disk.latency.rate.dm-13 + instance: dm-13 + name: com.vmware.applmgmt.mon.name.disk.latency.rate.dm-13 + units: com.vmware.applmgmt.mon.unit.msec_per_io + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.latency.rate.dm-14 + id: disk.latency.rate.dm-14 + instance: dm-14 + name: com.vmware.applmgmt.mon.name.disk.latency.rate.dm-14 + units: com.vmware.applmgmt.mon.unit.msec_per_io + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.latency.rate.dm-15 + id: disk.latency.rate.dm-15 + instance: dm-15 + name: com.vmware.applmgmt.mon.name.disk.latency.rate.dm-15 + units: com.vmware.applmgmt.mon.unit.msec_per_io + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.latency.rate.dm-2 + id: disk.latency.rate.dm-2 + instance: dm-2 + name: com.vmware.applmgmt.mon.name.disk.latency.rate.dm-2 + units: com.vmware.applmgmt.mon.unit.msec_per_io + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.latency.rate.dm-3 + id: disk.latency.rate.dm-3 + instance: dm-3 + name: com.vmware.applmgmt.mon.name.disk.latency.rate.dm-3 + units: com.vmware.applmgmt.mon.unit.msec_per_io + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.latency.rate.dm-4 + id: disk.latency.rate.dm-4 + instance: dm-4 + name: com.vmware.applmgmt.mon.name.disk.latency.rate.dm-4 + units: com.vmware.applmgmt.mon.unit.msec_per_io + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.latency.rate.dm-5 + id: disk.latency.rate.dm-5 + instance: dm-5 + name: com.vmware.applmgmt.mon.name.disk.latency.rate.dm-5 + units: com.vmware.applmgmt.mon.unit.msec_per_io + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.latency.rate.dm-6 + id: disk.latency.rate.dm-6 + instance: dm-6 + name: com.vmware.applmgmt.mon.name.disk.latency.rate.dm-6 + units: com.vmware.applmgmt.mon.unit.msec_per_io + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.latency.rate.dm-7 + id: disk.latency.rate.dm-7 + instance: dm-7 + name: com.vmware.applmgmt.mon.name.disk.latency.rate.dm-7 + units: com.vmware.applmgmt.mon.unit.msec_per_io + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.latency.rate.dm-8 + id: disk.latency.rate.dm-8 + instance: dm-8 + name: com.vmware.applmgmt.mon.name.disk.latency.rate.dm-8 + units: com.vmware.applmgmt.mon.unit.msec_per_io + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.latency.rate.dm-9 + id: disk.latency.rate.dm-9 + instance: dm-9 + name: com.vmware.applmgmt.mon.name.disk.latency.rate.dm-9 + units: com.vmware.applmgmt.mon.unit.msec_per_io + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.swap.util + id: swap.util + instance: '' + name: com.vmware.applmgmt.mon.name.swap.util + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.used.filesystem.swap + id: storage.used.filesystem.swap + instance: '' + name: com.vmware.applmgmt.mon.name.storage.used.filesystem.swap + units: com.vmware.applmgmt.mon.unit.percent + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.swap + id: swap + instance: '' + name: com.vmware.applmgmt.mon.name.swap + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.totalsize.filesystem.swap + id: storage.totalsize.filesystem.swap + instance: '' + name: com.vmware.applmgmt.mon.name.storage.totalsize.filesystem.swap + units: com.vmware.applmgmt.mon.unit.percent + - category: com.vmware.applmgmt.mon.cat.cpu + description: com.vmware.applmgmt.mon.descr.cpu.totalfrequency + id: cpu.totalfrequency + instance: '' + name: com.vmware.applmgmt.mon.name.cpu.totalfrequency + units: com.vmware.applmgmt.mon.unit.mhz + - category: com.vmware.applmgmt.mon.cat.cpu + description: com.vmware.applmgmt.mon.descr.cpu.systemload + id: cpu.systemload + instance: '' + name: com.vmware.applmgmt.mon.name.cpu.systemload + units: com.vmware.applmgmt.mon.unit.load_per_min + - category: com.vmware.applmgmt.mon.cat.memory + description: com.vmware.applmgmt.mon.descr.mem.util + id: mem.util + instance: '' + name: com.vmware.applmgmt.mon.name.mem.util + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.memory + description: com.vmware.applmgmt.mon.descr.mem.total + id: mem.total + instance: '' + name: com.vmware.applmgmt.mon.name.mem.total + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.memory + description: com.vmware.applmgmt.mon.descr.mem.usage + id: mem.usage + instance: '' + name: com.vmware.applmgmt.mon.name.mem.usage + units: com.vmware.applmgmt.mon.unit.percent + - category: com.vmware.applmgmt.mon.cat.network + description: com.vmware.applmgmt.mon.descr.net.rx.error.eth0 + id: net.rx.error.eth0 + instance: eth0 + name: com.vmware.applmgmt.mon.name.net.rx.error.eth0 + units: com.vmware.applmgmt.mon.unit.errors_per_sample + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.totalsize.directory.vcdb_hourly_stats + id: storage.totalsize.directory.vcdb_hourly_stats + instance: '' + name: com.vmware.applmgmt.mon.name.storage.totalsize.directory.vcdb_hourly_stats + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.network + description: com.vmware.applmgmt.mon.descr.net.rx.error.lo + id: net.rx.error.lo + instance: lo + name: com.vmware.applmgmt.mon.name.net.rx.error.lo + units: com.vmware.applmgmt.mon.unit.errors_per_sample + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.totalsize.directory.vcdb_daily_stats + id: storage.totalsize.directory.vcdb_daily_stats + instance: '' + name: com.vmware.applmgmt.mon.name.storage.totalsize.directory.vcdb_daily_stats + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.network + description: com.vmware.applmgmt.mon.descr.net.tx.error.eth0 + id: net.tx.error.eth0 + instance: eth0 + name: com.vmware.applmgmt.mon.name.net.tx.error.eth0 + units: com.vmware.applmgmt.mon.unit.errors_per_sample + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.totalsize.directory.vcdb_monthly_stats + id: storage.totalsize.directory.vcdb_monthly_stats + instance: '' + name: com.vmware.applmgmt.mon.name.storage.totalsize.directory.vcdb_monthly_stats + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.network + description: com.vmware.applmgmt.mon.descr.net.tx.error.lo + id: net.tx.error.lo + instance: lo + name: com.vmware.applmgmt.mon.name.net.tx.error.lo + units: com.vmware.applmgmt.mon.unit.errors_per_sample + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.totalsize.directory.vcdb_yearly_stats + id: storage.totalsize.directory.vcdb_yearly_stats + instance: '' + name: com.vmware.applmgmt.mon.name.storage.totalsize.directory.vcdb_yearly_stats + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.totalsize.directory.vcdb_stats + id: storage.totalsize.directory.vcdb_stats + instance: '' + name: com.vmware.applmgmt.mon.name.storage.totalsize.directory.vcdb_stats + units: com.vmware.applmgmt.mon.unit.percent + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.totalsize.filesystem.seat + id: storage.totalsize.filesystem.seat + instance: '' + name: com.vmware.applmgmt.mon.name.storage.totalsize.filesystem.seat + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.util.directory.vcdb_stats + id: storage.util.directory.vcdb_stats + instance: '' + name: com.vmware.applmgmt.mon.name.storage.util.directory.vcdb_stats + units: com.vmware.applmgmt.mon.unit.percent + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.totalsize.directory.vcdb_events + id: storage.totalsize.directory.vcdb_events + instance: '' + name: com.vmware.applmgmt.mon.name.storage.totalsize.directory.vcdb_events + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.util.directory.vcdb_events + id: storage.util.directory.vcdb_events + instance: '' + name: com.vmware.applmgmt.mon.name.storage.util.directory.vcdb_events + units: com.vmware.applmgmt.mon.unit.percent + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.totalsize.directory.vcdb_alarms + id: storage.totalsize.directory.vcdb_alarms + instance: '' + name: com.vmware.applmgmt.mon.name.storage.totalsize.directory.vcdb_alarms + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.util.directory.vcdb_alarms + id: storage.util.directory.vcdb_alarms + instance: '' + name: com.vmware.applmgmt.mon.name.storage.util.directory.vcdb_alarms + units: com.vmware.applmgmt.mon.unit.percent + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.totalsize.directory.vcdb_tasks + id: storage.totalsize.directory.vcdb_tasks + instance: '' + name: com.vmware.applmgmt.mon.name.storage.totalsize.directory.vcdb_tasks + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.util.directory.vcdb_tasks + id: storage.util.directory.vcdb_tasks + instance: '' + name: com.vmware.applmgmt.mon.name.storage.util.directory.vcdb_tasks + units: com.vmware.applmgmt.mon.unit.percent + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.used.filesystem.seat + id: storage.used.filesystem.seat + instance: '' + name: com.vmware.applmgmt.mon.name.storage.used.filesystem.seat + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.util.filesystem.seat + id: storage.util.filesystem.seat + instance: '' + name: com.vmware.applmgmt.mon.name.storage.util.filesystem.seat + units: com.vmware.applmgmt.mon.unit.percent + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.used.filesystem.db + id: storage.used.filesystem.db + instance: '' + name: com.vmware.applmgmt.mon.name.storage.used.filesystem.db + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.totalsize.filesystem.db + id: storage.totalsize.filesystem.db + instance: '' + name: com.vmware.applmgmt.mon.name.storage.totalsize.filesystem.db + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.util.filesystem.db + id: storage.util.filesystem.db + instance: '' + name: com.vmware.applmgmt.mon.name.storage.util.filesystem.db + units: com.vmware.applmgmt.mon.unit.percent + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.used.filesystem.dblog + id: storage.used.filesystem.dblog + instance: '' + name: com.vmware.applmgmt.mon.name.storage.used.filesystem.dblog + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.totalsize.filesystem.dblog + id: storage.totalsize.filesystem.dblog + instance: '' + name: com.vmware.applmgmt.mon.name.storage.totalsize.filesystem.dblog + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.util.filesystem.dblog + id: storage.util.filesystem.dblog + instance: '' + name: com.vmware.applmgmt.mon.name.storage.util.filesystem.dblog + units: com.vmware.applmgmt.mon.unit.percent + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.totalsize.filesystem.root + id: storage.totalsize.filesystem.root + instance: / + name: com.vmware.applmgmt.mon.name.storage.totalsize.filesystem.root + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.util.filesystem.root + id: storage.util.filesystem.root + instance: / + name: com.vmware.applmgmt.mon.name.storage.util.filesystem.root + units: com.vmware.applmgmt.mon.unit.percent + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.totalsize.filesystem.boot + id: storage.totalsize.filesystem.boot + instance: /boot + name: com.vmware.applmgmt.mon.name.storage.totalsize.filesystem.boot + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.util.filesystem.boot + id: storage.util.filesystem.boot + instance: /boot + name: com.vmware.applmgmt.mon.name.storage.util.filesystem.boot + units: com.vmware.applmgmt.mon.unit.percent + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.totalsize.filesystem.archive + id: storage.totalsize.filesystem.archive + instance: /storage/archive + name: com.vmware.applmgmt.mon.name.storage.totalsize.filesystem.archive + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.util.filesystem.archive + id: storage.util.filesystem.archive + instance: /storage/archive + name: com.vmware.applmgmt.mon.name.storage.util.filesystem.archive + units: com.vmware.applmgmt.mon.unit.percent + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.totalsize.filesystem.autodeploy + id: storage.totalsize.filesystem.autodeploy + instance: /storage/autodeploy + name: com.vmware.applmgmt.mon.name.storage.totalsize.filesystem.autodeploy + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.util.filesystem.autodeploy + id: storage.util.filesystem.autodeploy + instance: /storage/autodeploy + name: com.vmware.applmgmt.mon.name.storage.util.filesystem.autodeploy + units: com.vmware.applmgmt.mon.unit.percent + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.totalsize.filesystem.core + id: storage.totalsize.filesystem.core + instance: /storage/core + name: com.vmware.applmgmt.mon.name.storage.totalsize.filesystem.core + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.util.filesystem.core + id: storage.util.filesystem.core + instance: /storage/core + name: com.vmware.applmgmt.mon.name.storage.util.filesystem.core + units: com.vmware.applmgmt.mon.unit.percent + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.totalsize.filesystem.imagebuilder + id: storage.totalsize.filesystem.imagebuilder + instance: /storage/imagebuilder + name: com.vmware.applmgmt.mon.name.storage.totalsize.filesystem.imagebuilder + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.util.filesystem.imagebuilder + id: storage.util.filesystem.imagebuilder + instance: /storage/imagebuilder + name: com.vmware.applmgmt.mon.name.storage.util.filesystem.imagebuilder + units: com.vmware.applmgmt.mon.unit.percent + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.totalsize.filesystem.lifecycle + id: storage.totalsize.filesystem.lifecycle + instance: /storage/lifecycle + name: com.vmware.applmgmt.mon.name.storage.totalsize.filesystem.lifecycle + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.util.filesystem.lifecycle + id: storage.util.filesystem.lifecycle + instance: /storage/lifecycle + name: com.vmware.applmgmt.mon.name.storage.util.filesystem.lifecycle + units: com.vmware.applmgmt.mon.unit.percent + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.totalsize.filesystem.log + id: storage.totalsize.filesystem.log + instance: /storage/log + name: com.vmware.applmgmt.mon.name.storage.totalsize.filesystem.log + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.util.filesystem.log + id: storage.util.filesystem.log + instance: /storage/log + name: com.vmware.applmgmt.mon.name.storage.util.filesystem.log + units: com.vmware.applmgmt.mon.unit.percent + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.totalsize.filesystem.lvm_snapshot + id: storage.totalsize.filesystem.lvm_snapshot + instance: /storage/lvm_snapshot + name: com.vmware.applmgmt.mon.name.storage.totalsize.filesystem.lvm_snapshot + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.util.filesystem.lvm_snapshot + id: storage.util.filesystem.lvm_snapshot + instance: /storage/lvm_snapshot + name: com.vmware.applmgmt.mon.name.storage.util.filesystem.lvm_snapshot + units: com.vmware.applmgmt.mon.unit.percent + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.totalsize.filesystem.netdump + id: storage.totalsize.filesystem.netdump + instance: /storage/netdump + name: com.vmware.applmgmt.mon.name.storage.totalsize.filesystem.netdump + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.util.filesystem.netdump + id: storage.util.filesystem.netdump + instance: /storage/netdump + name: com.vmware.applmgmt.mon.name.storage.util.filesystem.netdump + units: com.vmware.applmgmt.mon.unit.percent + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.totalsize.filesystem.updatemgr + id: storage.totalsize.filesystem.updatemgr + instance: /storage/updatemgr + name: com.vmware.applmgmt.mon.name.storage.totalsize.filesystem.updatemgr + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.util.filesystem.updatemgr + id: storage.util.filesystem.updatemgr + instance: /storage/updatemgr + name: com.vmware.applmgmt.mon.name.storage.util.filesystem.updatemgr + units: com.vmware.applmgmt.mon.unit.percent + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.totalsize.filesystem.vtsdb + id: storage.totalsize.filesystem.vtsdb + instance: /storage/vtsdb + name: com.vmware.applmgmt.mon.name.storage.totalsize.filesystem.vtsdb + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.util.filesystem.vtsdb + id: storage.util.filesystem.vtsdb + instance: /storage/vtsdb + name: com.vmware.applmgmt.mon.name.storage.util.filesystem.vtsdb + units: com.vmware.applmgmt.mon.unit.percent + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.totalsize.filesystem.vtsdblog + id: storage.totalsize.filesystem.vtsdblog + instance: /storage/vtsdblog + name: com.vmware.applmgmt.mon.name.storage.totalsize.filesystem.vtsdblog + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.util.filesystem.vtsdblog + id: storage.util.filesystem.vtsdblog + instance: /storage/vtsdblog + name: com.vmware.applmgmt.mon.name.storage.util.filesystem.vtsdblog + units: com.vmware.applmgmt.mon.unit.percent + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.used.filesystem.root + id: storage.used.filesystem.root + instance: / + name: com.vmware.applmgmt.mon.name.storage.used.filesystem.root + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.used.filesystem.boot + id: storage.used.filesystem.boot + instance: /boot + name: com.vmware.applmgmt.mon.name.storage.used.filesystem.boot + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.used.filesystem.archive + id: storage.used.filesystem.archive + instance: /storage/archive + name: com.vmware.applmgmt.mon.name.storage.used.filesystem.archive + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.used.filesystem.autodeploy + id: storage.used.filesystem.autodeploy + instance: /storage/autodeploy + name: com.vmware.applmgmt.mon.name.storage.used.filesystem.autodeploy + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.used.filesystem.core + id: storage.used.filesystem.core + instance: /storage/core + name: com.vmware.applmgmt.mon.name.storage.used.filesystem.core + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.used.filesystem.imagebuilder + id: storage.used.filesystem.imagebuilder + instance: /storage/imagebuilder + name: com.vmware.applmgmt.mon.name.storage.used.filesystem.imagebuilder + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.used.filesystem.lifecycle + id: storage.used.filesystem.lifecycle + instance: /storage/lifecycle + name: com.vmware.applmgmt.mon.name.storage.used.filesystem.lifecycle + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.used.filesystem.log + id: storage.used.filesystem.log + instance: /storage/log + name: com.vmware.applmgmt.mon.name.storage.used.filesystem.log + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.used.filesystem.lvm_snapshot + id: storage.used.filesystem.lvm_snapshot + instance: /storage/lvm_snapshot + name: com.vmware.applmgmt.mon.name.storage.used.filesystem.lvm_snapshot + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.used.filesystem.netdump + id: storage.used.filesystem.netdump + instance: /storage/netdump + name: com.vmware.applmgmt.mon.name.storage.used.filesystem.netdump + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.used.filesystem.updatemgr + id: storage.used.filesystem.updatemgr + instance: /storage/updatemgr + name: com.vmware.applmgmt.mon.name.storage.used.filesystem.updatemgr + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.used.filesystem.vtsdb + id: storage.used.filesystem.vtsdb + instance: /storage/vtsdb + name: com.vmware.applmgmt.mon.name.storage.used.filesystem.vtsdb + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.used.filesystem.vtsdblog + id: storage.used.filesystem.vtsdblog + instance: /storage/vtsdblog + name: com.vmware.applmgmt.mon.name.storage.used.filesystem.vtsdblog + units: com.vmware.applmgmt.mon.unit.kb + - category: com.vmware.applmgmt.mon.cat.cpu + description: com.vmware.applmgmt.mon.descr.cpu.util + id: cpu.util + instance: '' + name: com.vmware.applmgmt.mon.name.cpu.util + units: com.vmware.applmgmt.mon.unit.percent + - category: com.vmware.applmgmt.mon.cat.cpu + description: com.vmware.applmgmt.mon.descr.cpu.steal + id: cpu.steal + instance: '' + name: com.vmware.applmgmt.mon.name.cpu.steal + units: com.vmware.applmgmt.mon.unit.percent + - category: com.vmware.applmgmt.mon.cat.memory + description: com.vmware.applmgmt.mon.descr.swap.pageRate + id: swap.pageRate + instance: '' + name: com.vmware.applmgmt.mon.name.swap.pageRate + units: com.vmware.applmgmt.mon.unit.pages_per_sec + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.read.rate.dm-0 + id: disk.read.rate.dm-0 + instance: dm-0 + name: com.vmware.applmgmt.mon.name.disk.read.rate.dm-0 + units: com.vmware.applmgmt.mon.unit.num_of_io_per_msec + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.write.rate.dm-0 + id: disk.write.rate.dm-0 + instance: dm-0 + name: com.vmware.applmgmt.mon.name.disk.write.rate.dm-0 + units: com.vmware.applmgmt.mon.unit.num_of_io_per_msec + - category: com.vmware.applmgmt.mon.cat.disk + description: com.vmware.applmgmt.mon.descr.disk.latency.rate.dm-0 + id: disk.latency.rate.dm-0 + instance: dm-0 + name: com.vmware.applmgmt.mon.name.disk.latency.rate.dm-0 + units: com.vmware.applmgmt.mon.unit.msec_per_io + - category: com.vmware.applmgmt.mon.cat.network + description: com.vmware.applmgmt.mon.descr.net.rx.activity.eth0 + id: net.rx.activity.eth0 + instance: eth0 + name: com.vmware.applmgmt.mon.name.net.rx.activity.eth0 + units: com.vmware.applmgmt.mon.unit.kb_per_sec + - category: com.vmware.applmgmt.mon.cat.network + description: com.vmware.applmgmt.mon.descr.net.rx.activity.lo + id: net.rx.activity.lo + instance: lo + name: com.vmware.applmgmt.mon.name.net.rx.activity.lo + units: com.vmware.applmgmt.mon.unit.kb_per_sec + - category: com.vmware.applmgmt.mon.cat.network + description: com.vmware.applmgmt.mon.descr.net.rx.packetRate.eth0 + id: net.rx.packetRate.eth0 + instance: eth0 + name: com.vmware.applmgmt.mon.name.net.rx.packetRate.eth0 + units: com.vmware.applmgmt.mon.unit.packets_per_sec + - category: com.vmware.applmgmt.mon.cat.network + description: com.vmware.applmgmt.mon.descr.net.rx.packetRate.lo + id: net.rx.packetRate.lo + instance: lo + name: com.vmware.applmgmt.mon.name.net.rx.packetRate.lo + units: com.vmware.applmgmt.mon.unit.packets_per_sec + - category: com.vmware.applmgmt.mon.cat.network + description: com.vmware.applmgmt.mon.descr.net.rx.drop.eth0 + id: net.rx.drop.eth0 + instance: eth0 + name: com.vmware.applmgmt.mon.name.net.rx.drop.eth0 + units: com.vmware.applmgmt.mon.unit.drops_per_sample + - category: com.vmware.applmgmt.mon.cat.network + description: com.vmware.applmgmt.mon.descr.net.rx.drop.lo + id: net.rx.drop.lo + instance: lo + name: com.vmware.applmgmt.mon.name.net.rx.drop.lo + units: com.vmware.applmgmt.mon.unit.drops_per_sample + - category: com.vmware.applmgmt.mon.cat.network + description: com.vmware.applmgmt.mon.descr.net.tx.activity.eth0 + id: net.tx.activity.eth0 + instance: eth0 + name: com.vmware.applmgmt.mon.name.net.tx.activity.eth0 + units: com.vmware.applmgmt.mon.unit.kb_per_sec + - category: com.vmware.applmgmt.mon.cat.network + description: com.vmware.applmgmt.mon.descr.net.tx.activity.lo + id: net.tx.activity.lo + instance: lo + name: com.vmware.applmgmt.mon.name.net.tx.activity.lo + units: com.vmware.applmgmt.mon.unit.kb_per_sec + - category: com.vmware.applmgmt.mon.cat.network + description: com.vmware.applmgmt.mon.descr.net.tx.packetRate.eth0 + id: net.tx.packetRate.eth0 + instance: eth0 + name: com.vmware.applmgmt.mon.name.net.tx.packetRate.eth0 + units: com.vmware.applmgmt.mon.unit.packets_per_sec + - category: com.vmware.applmgmt.mon.cat.network + description: com.vmware.applmgmt.mon.descr.net.tx.packetRate.lo + id: net.tx.packetRate.lo + instance: lo + name: com.vmware.applmgmt.mon.name.net.tx.packetRate.lo + units: com.vmware.applmgmt.mon.unit.packets_per_sec + - category: com.vmware.applmgmt.mon.cat.network + description: com.vmware.applmgmt.mon.descr.net.tx.drop.eth0 + id: net.tx.drop.eth0 + instance: eth0 + name: com.vmware.applmgmt.mon.name.net.tx.drop.eth0 + units: com.vmware.applmgmt.mon.unit.drops_per_sample + - category: com.vmware.applmgmt.mon.cat.network + description: com.vmware.applmgmt.mon.descr.net.tx.drop.lo + id: net.tx.drop.lo + instance: lo + name: com.vmware.applmgmt.mon.name.net.tx.drop.lo + units: com.vmware.applmgmt.mon.unit.drops_per_sample + - category: com.vmware.applmgmt.mon.cat.storage + description: com.vmware.applmgmt.mon.descr.storage.util.filesystem.swap + id: storage.util.filesystem.swap + instance: '' + name: com.vmware.applmgmt.mon.name.storage.util.filesystem.swap + units: com.vmware.applmgmt.mon.unit.percent + type: list +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"stat_id": "stat_id"}}, + "list": {"query": {}, "body": {}, "path": {}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["stat_id"] = {"type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_list_and_get_module.j2 +def build_url(params): + if params.get("stat_id"): + _in_query_parameters = PAYLOAD_FORMAT["get"]["query"].keys() + return ( + ("https://{vcenter_hostname}" "/api/appliance/monitoring/").format(**params) + + params["stat_id"] + + gen_args(params, _in_query_parameters) + ) + _in_query_parameters = PAYLOAD_FORMAT["list"]["query"].keys() + return ("https://{vcenter_hostname}" "/api/appliance/monitoring").format( + **params + ) + gen_args(params, _in_query_parameters) + + +async def entry_point(module, session): + url = build_url(module.params) + async with session.get(url, **session_timeout(module.params)) as resp: + _json = await resp.json() + + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + + if module.params.get("stat_id"): + _json["id"] = module.params.get("stat_id") + elif module.params.get("label"): # TODO extend the list of filter + _json = await exists(module.params, session, url) + elif ( + isinstance(_json["value"], list) + and len(_json["value"]) > 0 + and isinstance(_json["value"][0], str) + ): + # this is a list of id, we fetch the details + full_device_list = await build_full_device_list(session, url, _json) + _json = {"value": [i["value"] for i in full_device_list]} + + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_monitoring_query.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_monitoring_query.py new file mode 100644 index 00000000..0ac27c5a --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_monitoring_query.py @@ -0,0 +1,315 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_monitoring_query +short_description: Get monitoring data. +description: Get monitoring data. +options: + end_time: + description: + - End time in UTC This parameter is mandatory. + required: true + type: str + function: + choices: + - AVG + - COUNT + - MAX + - MIN + description: + - C(function_type) Defines aggregation function This parameter is mandatory. + required: true + type: str + interval: + choices: + - DAY1 + - HOURS2 + - HOURS6 + - MINUTES30 + - MINUTES5 + description: + - C(interval_type) Defines interval between the values in hours and mins, for + which aggregation will apply This parameter is mandatory. + required: true + type: str + names: + description: + - 'monitored item IDs Ex: CPU, MEMORY This parameter is mandatory.' + elements: str + required: true + type: list + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + start_time: + description: + - Start time in UTC This parameter is mandatory. + required: true + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Query the monitoring backend + vmware.vmware_rest.appliance_monitoring_query: + end_time: 2021-04-14T09:34:56Z + start_time: 2021-04-14T08:34:56Z + names: + - mem.total + interval: MINUTES5 + function: AVG + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Query the monitoring backend +value: + description: Query the monitoring backend + returned: On success + sample: + - data: + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + end_time: '2021-04-14T09:34:56.000Z' + function: AVG + interval: MINUTES5 + name: mem.total + start_time: '2021-04-14T08:34:56.000Z' + type: list +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "query": { + "query": { + "end_time": "end_time", + "function": "function", + "interval": "interval", + "names": "names", + "start_time": "start_time", + }, + "body": {}, + "path": {}, + } +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["end_time"] = {"required": True, "type": "str"} + argument_spec["function"] = { + "required": True, + "type": "str", + "choices": ["AVG", "COUNT", "MAX", "MIN"], + } + argument_spec["interval"] = { + "required": True, + "type": "str", + "choices": ["DAY1", "HOURS2", "HOURS6", "MINUTES30", "MINUTES5"], + } + argument_spec["names"] = {"required": True, "type": "list", "elements": "str"} + argument_spec["start_time"] = {"required": True, "type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/monitoring/query").format( + **params + ) + + +async def entry_point(module, session): + + func = globals()["_query"] + + return await func(module.params, session) + + +async def _query(params, session): + _in_query_parameters = PAYLOAD_FORMAT["query"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["query"]) + subdevice_type = get_subdevice_type("/api/appliance/monitoring/query") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/appliance/monitoring/query" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.get(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "query") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking.py new file mode 100644 index 00000000..6310e4a6 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking.py @@ -0,0 +1,312 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_networking +short_description: Reset and restarts network configuration on all interfaces, also + this will renew the DHCP lease for DHCP IP address. +description: Reset and restarts network configuration on all interfaces, also this + will renew the DHCP lease for DHCP IP address. +options: + ipv6_enabled: + description: + - IPv6 Enabled or not + type: bool + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - present + - reset + default: present + description: [] + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Set network information + vmware.vmware_rest.appliance_networking: + ipv6_enabled: false + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Set network information +id: + description: moid of the resource + returned: On success + sample: null + type: dict +value: + description: Set network information + returned: On success + sample: {} + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "update": {"query": {}, "body": {"ipv6_enabled": "ipv6_enabled"}, "path": {}}, + "reset": {"query": {}, "body": {}, "path": {}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["ipv6_enabled"] = {"type": "bool"} + argument_spec["state"] = { + "type": "str", + "choices": ["present", "reset"], + "default": "present", + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/networking").format(**params) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _reset(params, session): + _in_query_parameters = PAYLOAD_FORMAT["reset"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["reset"]) + subdevice_type = get_subdevice_type("/api/appliance/networking?action=reset") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/appliance/networking?action=reset" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "reset") + + +async def _update(params, session): + payload = prepare_payload(params, PAYLOAD_FORMAT["update"]) + _url = ("https://{vcenter_hostname}" "/api/appliance/networking").format(**params) + async with session.get(_url, **session_timeout(params)) as resp: + _json = await resp.json() + if "value" in _json: + value = _json["value"] + else: # 7.0.2 and greater + value = _json + for k, v in value.items(): + if k in payload: + if isinstance(payload[k], dict) and isinstance(v, dict): + to_delete = True + for _k in list(payload[k].keys()): + if payload[k][_k] != v.get(_k): + to_delete = False + if to_delete: + del payload[k] + elif payload[k] == v: + del payload[k] + elif payload[k] == {}: + del payload[k] + + if payload == {} or payload == {"spec": {}}: + # Nothing has changed + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + _json["id"] = params.get("None") + return await update_changed_flag(_json, resp.status, "get") + async with session.patch(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # e.g: content_configuration + if not _json and resp.status == 204: + async with session.get(_url, **session_timeout(params)) as resp_get: + _json_get = await resp_get.json() + if _json_get: + _json = _json_get + + _json["id"] = params.get("None") + return await update_changed_flag(_json, resp.status, "update") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_dns_domains.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_dns_domains.py new file mode 100644 index 00000000..bf5329a6 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_dns_domains.py @@ -0,0 +1,306 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_networking_dns_domains +short_description: Set DNS search domains. +description: Set DNS search domains. +options: + domain: + description: + - Domain to add. Required with I(state=['add']) + type: str + domains: + description: + - List of domains. Required with I(state=['set']) + elements: str + type: list + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - add + - set + default: set + description: [] + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Update the domain configuration + vmware.vmware_rest.appliance_networking_dns_domains: + domains: + - foobar + register: result + +- name: Add another domain configuration + vmware.vmware_rest.appliance_networking_dns_domains: + domain: barfoo + state: add + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Add another domain configuration +value: + description: Add another domain configuration + returned: On success + sample: {} + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "set": {"query": {}, "body": {"domains": "domains"}, "path": {}}, + "add": {"query": {}, "body": {"domain": "domain"}, "path": {}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["domain"] = {"type": "str"} + argument_spec["domains"] = {"type": "list", "elements": "str"} + argument_spec["state"] = { + "type": "str", + "choices": ["add", "set"], + "default": "set", + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ( + "https://{vcenter_hostname}" "/api/appliance/networking/dns/domains" + ).format(**params) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _add(params, session): + _in_query_parameters = PAYLOAD_FORMAT["add"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["add"]) + subdevice_type = get_subdevice_type("/api/appliance/networking/dns/domains") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/appliance/networking/dns/domains" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "add") + + +async def _set(params, session): + _in_query_parameters = PAYLOAD_FORMAT["set"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["set"]) + subdevice_type = get_subdevice_type("/api/appliance/networking/dns/domains") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" "/api/appliance/networking/dns/domains" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.get(_url, json=payload, **session_timeout(params)) as resp: + before = await resp.json() + + async with session.put(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # The PUT answer does not let us know if the resource has actually been + # modified + if resp.status < 300: + async with session.get( + _url, json=payload, **session_timeout(params) + ) as resp_get: + after = await resp_get.json() + if before == after: + return await update_changed_flag(after, resp_get.status, "get") + return await update_changed_flag(_json, resp.status, "set") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_dns_domains_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_dns_domains_info.py new file mode 100644 index 00000000..9b92e9a0 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_dns_domains_info.py @@ -0,0 +1,208 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_networking_dns_domains_info +short_description: Get list of DNS search domains. +description: Get list of DNS search domains. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Get DNS domains configuration + vmware.vmware_rest.appliance_networking_dns_domains_info: + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get DNS domains configuration +value: + description: Get DNS domains configuration + returned: On success + sample: [] + type: list +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "list": {"query": {}, "body": {}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_list_and_get_module.j2 +def build_url(params): + _in_query_parameters = PAYLOAD_FORMAT["list"]["query"].keys() + return ( + "https://{vcenter_hostname}" "/api/appliance/networking/dns/domains" + ).format(**params) + gen_args(params, _in_query_parameters) + + +async def entry_point(module, session): + url = build_url(module.params) + async with session.get(url, **session_timeout(module.params)) as resp: + _json = await resp.json() + + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_dns_hostname.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_dns_hostname.py new file mode 100644 index 00000000..03bbdae4 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_dns_hostname.py @@ -0,0 +1,301 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_networking_dns_hostname +short_description: Set the Fully Qualified Domain Name. +description: Set the Fully Qualified Domain Name. +options: + name: + description: + - FQDN. This parameter is mandatory. + required: true + type: str + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - set + - test + default: set + description: [] + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Test the hostname configuration + vmware.vmware_rest.appliance_networking_dns_hostname: + state: test + name: vcenter.test + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Test the hostname configuration +value: + description: Test the hostname configuration + returned: On success + sample: + messages: + - message: Hostname vcenter.test resolved using DNS to 192.168.123.8. + result: success + status: green + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "set": {"query": {}, "body": {"name": "name"}, "path": {}}, + "test": {"query": {}, "body": {"name": "name"}, "path": {}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["name"] = {"required": True, "type": "str"} + argument_spec["state"] = { + "type": "str", + "choices": ["set", "test"], + "default": "set", + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ( + "https://{vcenter_hostname}" "/api/appliance/networking/dns/hostname" + ).format(**params) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _set(params, session): + _in_query_parameters = PAYLOAD_FORMAT["set"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["set"]) + subdevice_type = get_subdevice_type("/api/appliance/networking/dns/hostname") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" "/api/appliance/networking/dns/hostname" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.get(_url, json=payload, **session_timeout(params)) as resp: + before = await resp.json() + + async with session.put(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # The PUT answer does not let us know if the resource has actually been + # modified + if resp.status < 300: + async with session.get( + _url, json=payload, **session_timeout(params) + ) as resp_get: + after = await resp_get.json() + if before == after: + return await update_changed_flag(after, resp_get.status, "get") + return await update_changed_flag(_json, resp.status, "set") + + +async def _test(params, session): + _in_query_parameters = PAYLOAD_FORMAT["test"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["test"]) + subdevice_type = get_subdevice_type( + "/api/appliance/networking/dns/hostname?action=test" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/appliance/networking/dns/hostname?action=test" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "test") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_dns_hostname_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_dns_hostname_info.py new file mode 100644 index 00000000..8c0e75a7 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_dns_hostname_info.py @@ -0,0 +1,215 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_networking_dns_hostname_info +short_description: Get the Fully Qualified Doman Name. +description: Get the Fully Qualified Doman Name. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Get the hostname configuration + vmware.vmware_rest.appliance_networking_dns_hostname_info: + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get the hostname configuration +value: + description: Get the hostname configuration + returned: On success + sample: vcenter.test + type: str +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ( + "https://{vcenter_hostname}" "/api/appliance/networking/dns/hostname" + ).format(**params) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ( + "https://{vcenter_hostname}" "/api/appliance/networking/dns/hostname" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_dns_servers.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_dns_servers.py new file mode 100644 index 00000000..91fb574c --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_dns_servers.py @@ -0,0 +1,401 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_networking_dns_servers +short_description: Set the DNS server configuration +description: Set the DNS server configuration. If you set the mode argument to "DHCP", + a DHCP refresh is forced. +options: + mode: + choices: + - dhcp + - is_static + description: + - C(dns_server_mode) Describes DNS Server source (DHCP,static) Required with I(state=['set']) + type: str + server: + description: + - DNS server. Required with I(state=['add']) + type: str + servers: + description: + - List of the currently used DNS servers. Required with I(state=['set', 'test']) + elements: str + type: list + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - add + - set + - test + default: set + description: [] + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Set static DNS servers + vmware.vmware_rest.appliance_networking_dns_servers: + servers: + - 1.1.1.1 + mode: is_static + state: set + register: result + +- name: Add another DNS server + vmware.vmware_rest.appliance_networking_dns_servers: + server: 8.8.4.4 + state: add + register: result + +- name: Use the DNS servers from the DHCP + vmware.vmware_rest.appliance_networking_dns_servers: + mode: dhcp + servers: [] + state: set + register: result + +- name: Test the DNS servers + vmware.vmware_rest.appliance_networking_dns_servers: + state: test + servers: + - google.com + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Add another DNS server +value: + description: Add another DNS server + returned: On success + sample: + mode: is_static + servers: + - 1.1.1.1 + - 192.168.123.1 + - 8.8.4.4 + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "set": {"query": {}, "body": {"mode": "mode", "servers": "servers"}, "path": {}}, + "add": {"query": {}, "body": {"server": "server"}, "path": {}}, + "test": {"query": {}, "body": {"servers": "servers"}, "path": {}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["mode"] = {"type": "str", "choices": ["dhcp", "is_static"]} + argument_spec["server"] = {"type": "str"} + argument_spec["servers"] = {"type": "list", "elements": "str"} + argument_spec["state"] = { + "type": "str", + "choices": ["add", "set", "test"], + "default": "set", + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ( + "https://{vcenter_hostname}" "/api/appliance/networking/dns/servers" + ).format(**params) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _add(params, session): + _in_query_parameters = PAYLOAD_FORMAT["add"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["add"]) + subdevice_type = get_subdevice_type("/api/appliance/networking/dns/servers") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/appliance/networking/dns/servers" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + if ( + resp.status == 500 + and "messages" in _json["value"] + and _json["value"]["messages"] + and "id" in _json["value"]["messages"][0] + and _json["value"]["messages"][0]["id"] + == "com.vmware.applmgmt.err_operation_failed" + and "args" in _json["value"]["messages"][0] + and "changing state RUNNING → CLOSED" + in _json["value"]["messages"][0]["args"][0] + ): + # vSphere 7.0.2, a network configuration changes of the appliance raise a systemd error, + # but the change is applied. The problem can be resolved by a yum update. + async with session.get( + _url, json=payload, **session_timeout(params) + ) as resp: + _json = {"value": await resp.json()} + + return await update_changed_flag(_json, resp.status, "add") + + +async def _set(params, session): + _in_query_parameters = PAYLOAD_FORMAT["set"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["set"]) + subdevice_type = get_subdevice_type("/api/appliance/networking/dns/servers") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" "/api/appliance/networking/dns/servers" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.get(_url, json=payload, **session_timeout(params)) as resp: + before = await resp.json() + + async with session.put(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + if ( + resp.status == 500 + and "messages" in _json["value"] + and _json["value"]["messages"] + and "id" in _json["value"]["messages"][0] + and _json["value"]["messages"][0]["id"] + == "com.vmware.applmgmt.err_operation_failed" + and "args" in _json["value"]["messages"][0] + and "changing state RUNNING → CLOSED" + in _json["value"]["messages"][0]["args"][0] + ): + # vSphere 7.0.2, a network configuration changes of the appliance raise a systemd error, + # but the change is applied. The problem can be resolved by a yum update. + async with session.get( + _url, json=payload, **session_timeout(params) + ) as resp: + _json = {"value": await resp.json()} + + # The PUT answer does not let us know if the resource has actually been + # modified + if resp.status < 300: + async with session.get( + _url, json=payload, **session_timeout(params) + ) as resp_get: + after = await resp_get.json() + if before == after: + return await update_changed_flag(after, resp_get.status, "get") + return await update_changed_flag(_json, resp.status, "set") + + +async def _test(params, session): + _in_query_parameters = PAYLOAD_FORMAT["test"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["test"]) + subdevice_type = get_subdevice_type( + "/api/appliance/networking/dns/servers?action=test" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/appliance/networking/dns/servers?action=test" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "test") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_dns_servers_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_dns_servers_info.py new file mode 100644 index 00000000..fa0b78f5 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_dns_servers_info.py @@ -0,0 +1,218 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_networking_dns_servers_info +short_description: Get DNS server configuration. +description: Get DNS server configuration. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Get the DNS servers + vmware.vmware_rest.appliance_networking_dns_servers_info: + register: original_DNS_config +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get the DNS servers +value: + description: Get the DNS servers + returned: On success + sample: + mode: is_static + servers: + - 192.168.123.1 + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ( + "https://{vcenter_hostname}" "/api/appliance/networking/dns/servers" + ).format(**params) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ( + "https://{vcenter_hostname}" "/api/appliance/networking/dns/servers" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_firewall_inbound.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_firewall_inbound.py new file mode 100644 index 00000000..21dc6a92 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_firewall_inbound.py @@ -0,0 +1,306 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_networking_firewall_inbound +short_description: Set the ordered list of firewall rules to allow or deny traffic + from one or more incoming IP addresses +description: 'Set the ordered list of firewall rules to allow or deny traffic from + one or more incoming IP addresses. This overwrites the existing firewall rules and + creates a new rule list. Within the list of traffic rules, rules are processed in + order of appearance, from top to bottom. For example, the list of rules can be as + follows: <table> <tr> <th>Address</th><th>Prefix</th><th>Interface Name</th><th>Policy</th> + </tr> <tr> <td>10.112.0.1</td><td>0</td><td>*</td><td>REJECT</td> </tr> <tr> <td>10.112.0.1</td><td>0</td><td>nic0</td><td>ACCEPT</td> + </tr> </table> In the above example, the first rule drops all packets originating + from 10.112.0.1 and<br> the second rule accepts all packets originating from 10.112.0.1 + only on nic0. In effect, the second rule is always ignored which is not desired, + hence the order has to be swapped. When a connection matches a firewall rule, further + processing for the connection stops, and the appliance ignores any additional firewall + rules you have set.' +options: + rules: + description: + - List of address-based firewall rules. This parameter is mandatory. + - 'Valid attributes are:' + - ' - C(address) (str): IPv4 or IPv6 address. ([''set''])' + - ' This key is required with [''set''].' + - ' - C(prefix) (int): CIDR prefix used to mask address. For example, an IPv4 + prefix of 24 ignores the low-order 8 bits of address. ([''set''])' + - ' This key is required with [''set''].' + - ' - C(policy) (str): C(policy) Defines firewall rule policies. ([''set''])' + - ' This key is required with [''set''].' + - ' - Accepted values:' + - ' - ACCEPT' + - ' - IGNORE' + - ' - REJECT' + - ' - RETURN' + - ' - C(interface_name) (str): The interface to which this rule applies. An empty + string indicates that the rule applies to all interfaces. ([''set''])' + elements: dict + required: true + type: list + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - set + default: set + description: [] + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Ensure the rules parameter is mandatory + vmware.vmware_rest.appliance_networking_firewall_inbound: + register: result + failed_when: + - not(result.failed) + - result.msg == 'missing required arguments: rules' + +- name: Set a firewall rule + vmware.vmware_rest.appliance_networking_firewall_inbound: + rules: + - address: 1.2.3.4 + prefix: 32 + policy: ACCEPT + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Ensure the rules parameter is mandatory +failed_when_result: + description: Ensure the rules parameter is mandatory + returned: On success + sample: 0 + type: int +msg: + description: Ensure the rules parameter is mandatory + returned: On success + sample: 'missing required arguments: rules' + type: str +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "set": {"query": {}, "body": {"rules": "rules"}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["rules"] = {"required": True, "type": "list", "elements": "dict"} + argument_spec["state"] = {"type": "str", "choices": ["set"], "default": "set"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ( + "https://{vcenter_hostname}" "/api/appliance/networking/firewall/inbound" + ).format(**params) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _set(params, session): + _in_query_parameters = PAYLOAD_FORMAT["set"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["set"]) + subdevice_type = get_subdevice_type("/api/appliance/networking/firewall/inbound") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" "/api/appliance/networking/firewall/inbound" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.get(_url, json=payload, **session_timeout(params)) as resp: + before = await resp.json() + + async with session.put(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # The PUT answer does not let us know if the resource has actually been + # modified + if resp.status < 300: + async with session.get( + _url, json=payload, **session_timeout(params) + ) as resp_get: + after = await resp_get.json() + if before == after: + return await update_changed_flag(after, resp_get.status, "get") + return await update_changed_flag(_json, resp.status, "set") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_firewall_inbound_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_firewall_inbound_info.py new file mode 100644 index 00000000..0c2171d2 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_firewall_inbound_info.py @@ -0,0 +1,222 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_networking_firewall_inbound_info +short_description: Get the ordered list of firewall rules +description: Get the ordered list of firewall rules. Within the list of traffic rules, + rules are processed in order of appearance, from top to bottom. When a connection + matches a firewall rule, further processing for the connection stops, and the appliance + ignores any additional firewall rules you have set. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Get the firewall inbound configuration + vmware.vmware_rest.appliance_networking_firewall_inbound_info: + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get the firewall inbound configuration +value: + description: Get the firewall inbound configuration + returned: On success + sample: + - address: 1.2.3.4 + interface_name: '*' + policy: ACCEPT + prefix: 32 + type: list +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ( + "https://{vcenter_hostname}" "/api/appliance/networking/firewall/inbound" + ).format(**params) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ( + "https://{vcenter_hostname}" "/api/appliance/networking/firewall/inbound" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_info.py new file mode 100644 index 00000000..6cd93bbf --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_info.py @@ -0,0 +1,240 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_networking_info +short_description: Get Networking information for all configured interfaces. +description: Get Networking information for all configured interfaces. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Get network information + vmware.vmware_rest.appliance_networking_info: + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get network information +value: + description: Get network information + returned: On success + sample: + dns: + hostname: vcenter.test + mode: STATIC + servers: + - 192.168.123.1 + interfaces: + nic0: + ipv4: + address: 192.168.123.8 + configurable: 1 + default_gateway: 192.168.123.1 + mode: STATIC + prefix: 24 + ipv6: + addresses: + - address: fe80::5054:ff:fea4:6e89 + origin: OTHER + prefix: 64 + status: PREFERRED + autoconf: 1 + configurable: 1 + default_gateway: '' + dhcp: 0 + mac: 52:54:00:a4:6e:89 + name: nic0 + status: up + vcenter_base_url: https://vcenter.test:443 + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/networking").format(**params) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ("https://{vcenter_hostname}" "/api/appliance/networking").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_interfaces_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_interfaces_info.py new file mode 100644 index 00000000..90991e6f --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_interfaces_info.py @@ -0,0 +1,266 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_networking_interfaces_info +short_description: Get information about a particular network interface. +description: Get information about a particular network interface. +options: + interface_name: + description: + - Network interface, for example, "nic0". Required with I(state=['get']) + type: str + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Get a list of the network interfaces + vmware.vmware_rest.appliance_networking_interfaces_info: + register: result + +- name: Get details about one network interfaces + vmware.vmware_rest.appliance_networking_interfaces_info: + interface_name: nic0 + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get details about one network interfaces +id: + description: moid of the resource + returned: On success + sample: nic0 + type: str +value: + description: Get details about one network interfaces + returned: On success + sample: + ipv4: + address: 192.168.123.8 + configurable: 1 + default_gateway: 192.168.123.1 + mode: STATIC + prefix: 24 + ipv6: + addresses: + - address: fe80::5054:ff:fea4:6e89 + origin: OTHER + prefix: 64 + status: PREFERRED + autoconf: 1 + configurable: 1 + default_gateway: '' + dhcp: 0 + mac: 52:54:00:a4:6e:89 + name: nic0 + status: up + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"interface_name": "interface_name"}}, + "list": {"query": {}, "body": {}, "path": {}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["interface_name"] = {"type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_list_and_get_module.j2 +def build_url(params): + if params.get("interface_name"): + _in_query_parameters = PAYLOAD_FORMAT["get"]["query"].keys() + return ( + ( + "https://{vcenter_hostname}" "/api/appliance/networking/interfaces/" + ).format(**params) + + params["interface_name"] + + gen_args(params, _in_query_parameters) + ) + _in_query_parameters = PAYLOAD_FORMAT["list"]["query"].keys() + return ("https://{vcenter_hostname}" "/api/appliance/networking/interfaces").format( + **params + ) + gen_args(params, _in_query_parameters) + + +async def entry_point(module, session): + url = build_url(module.params) + async with session.get(url, **session_timeout(module.params)) as resp: + _json = await resp.json() + + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + + if module.params.get("interface_name"): + _json["id"] = module.params.get("interface_name") + elif module.params.get("label"): # TODO extend the list of filter + _json = await exists(module.params, session, url) + elif ( + isinstance(_json["value"], list) + and len(_json["value"]) > 0 + and isinstance(_json["value"][0], str) + ): + # this is a list of id, we fetch the details + full_device_list = await build_full_device_list(session, url, _json) + _json = {"value": [i["value"] for i in full_device_list]} + + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_interfaces_ipv4.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_interfaces_ipv4.py new file mode 100644 index 00000000..8f97371e --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_interfaces_ipv4.py @@ -0,0 +1,324 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_networking_interfaces_ipv4 +short_description: Set IPv4 network configuration for specific network interface. +description: Set IPv4 network configuration for specific network interface. +options: + address: + description: + - The IPv4 address, for example, "10.20.80.191". + type: str + default_gateway: + description: + - The IPv4 address of the default gateway. This configures the global default + gateway on the appliance with the specified gateway address and interface. This + gateway replaces the existing default gateway configured on the appliance. However, + if the gateway address is link-local, then it is added for that interface. This + does not support configuration of multiple global default gateways through different + interfaces. + type: str + interface_name: + description: + - Network interface to update, for example, "nic0". This parameter is mandatory. + required: true + type: str + mode: + choices: + - DHCP + - STATIC + - UNCONFIGURED + description: + - The C(mode) defines different IPv4 address assignment modes. This parameter + is mandatory. + required: true + type: str + prefix: + description: + - The IPv4 CIDR prefix, for example, 24. See http://www.oav.net/mirrors/cidr.html + for netmask-to-prefix conversion. + type: int + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - set + default: set + description: [] + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Set the IPv4 network information of nic99 (which does not exist) + vmware.vmware_rest.appliance_networking_interfaces_ipv4: + interface_name: nic99 + config: + address: 10.20.80.191 + prefix: '32' + mode: STATIC + failed_when: + - not(result.failed) + - result.value.messages[0].default_message msg == "The interface is unknown." + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Set the IPv4 network information of nic99 (which does not exist) +failed_when_result: + description: Set the IPv4 network information of nic99 (which does not exist) + returned: On success + sample: 0 + type: int +msg: + description: Set the IPv4 network information of nic99 (which does not exist) + returned: On success + sample: 'missing required arguments: mode' + type: str +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "set": { + "query": {}, + "body": { + "address": "address", + "default_gateway": "default_gateway", + "mode": "mode", + "prefix": "prefix", + }, + "path": {"interface_name": "interface_name"}, + } +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["address"] = {"type": "str"} + argument_spec["default_gateway"] = {"type": "str"} + argument_spec["interface_name"] = {"required": True, "type": "str"} + argument_spec["mode"] = { + "required": True, + "type": "str", + "choices": ["DHCP", "STATIC", "UNCONFIGURED"], + } + argument_spec["prefix"] = {"type": "int"} + argument_spec["state"] = {"type": "str", "choices": ["set"], "default": "set"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ( + "https://{vcenter_hostname}" + "/api/appliance/networking/interfaces/{interface_name}/ipv4" + ).format(**params) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _set(params, session): + _in_query_parameters = PAYLOAD_FORMAT["set"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["set"]) + subdevice_type = get_subdevice_type( + "/api/appliance/networking/interfaces/{interface_name}/ipv4" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + "/api/appliance/networking/interfaces/{interface_name}/ipv4" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.get(_url, json=payload, **session_timeout(params)) as resp: + before = await resp.json() + + async with session.put(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # The PUT answer does not let us know if the resource has actually been + # modified + if resp.status < 300: + async with session.get( + _url, json=payload, **session_timeout(params) + ) as resp_get: + after = await resp_get.json() + if before == after: + return await update_changed_flag(after, resp_get.status, "get") + return await update_changed_flag(_json, resp.status, "set") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_interfaces_ipv4_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_interfaces_ipv4_info.py new file mode 100644 index 00000000..c88056d1 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_interfaces_ipv4_info.py @@ -0,0 +1,229 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_networking_interfaces_ipv4_info +short_description: Get IPv4 network configuration for specific NIC. +description: Get IPv4 network configuration for specific NIC. +options: + interface_name: + description: + - The Network interface to query, for example, "nic0". Required with I(state=['get']) + type: str + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Collect the IPv4 network information + vmware.vmware_rest.appliance_networking_interfaces_ipv4_info: + interface_name: nic0 + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Collect the IPv4 network information +value: + description: Collect the IPv4 network information + returned: On success + sample: + address: 192.168.123.8 + configurable: 1 + default_gateway: 192.168.123.1 + mode: STATIC + prefix: 24 + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"interface_name": "interface_name"}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["interface_name"] = {"type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ( + "https://{vcenter_hostname}" + "/api/appliance/networking/interfaces/{interface_name}/ipv4" + ).format(**params) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ( + "https://{vcenter_hostname}" + "/api/appliance/networking/interfaces/{interface_name}/ipv4" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_interfaces_ipv6.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_interfaces_ipv6.py new file mode 100644 index 00000000..3f38c364 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_interfaces_ipv6.py @@ -0,0 +1,322 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_networking_interfaces_ipv6 +short_description: Set IPv6 network configuration for specific interface. +description: Set IPv6 network configuration for specific interface. +options: + addresses: + description: + - The list of addresses to be statically assigned. This parameter is mandatory. + - 'Valid attributes are:' + - ' - C(address) (str): The IPv6 address, for example, fc00:10:20:83:20c:29ff:fe94:bb5a. + ([''set''])' + - ' This key is required with [''set''].' + - ' - C(prefix) (int): The IPv6 CIDR prefix, for example, 64. ([''set''])' + - ' This key is required with [''set''].' + elements: dict + required: true + type: list + autoconf: + description: + - An address will be assigned by Stateless Address Autoconfiguration (SLAAC). + This parameter is mandatory. + required: true + type: bool + default_gateway: + description: + - The default gateway for static IP address assignment. This configures the global + IPv6 default gateway on the appliance with the specified gateway address and + interface. This gateway replaces the existing default gateway configured on + the appliance. However, if the gateway address is link-local, then it is added + for that interface. This does not support configuration of multiple global default + gateways through different interfaces. This parameter is mandatory. + required: true + type: str + dhcp: + description: + - An address will be assigned by a DHCP server. This parameter is mandatory. + required: true + type: bool + interface_name: + description: + - Network interface to update, for example, "nic0". This parameter is mandatory. + required: true + type: str + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - set + default: set + description: [] + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Set the IPv6 network information of nic99 (which does not exist) + vmware.vmware_rest.appliance_networking_interfaces_ipv6: + interface_name: nic99 + mode: DHCP + failed_when: + - not(result.failed) + - result.value.messages[0].default_message msg == "The interface is unknown." + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Set the IPv6 network information of nic99 (which does not exist) +failed_when_result: + description: Set the IPv6 network information of nic99 (which does not exist) + returned: On success + sample: 0 + type: int +msg: + description: Set the IPv6 network information of nic99 (which does not exist) + returned: On success + sample: 'missing required arguments: addresses, autoconf, default_gateway, dhcp' + type: str +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "set": { + "query": {}, + "body": { + "addresses": "addresses", + "autoconf": "autoconf", + "default_gateway": "default_gateway", + "dhcp": "dhcp", + }, + "path": {"interface_name": "interface_name"}, + } +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["addresses"] = {"required": True, "type": "list", "elements": "dict"} + argument_spec["autoconf"] = {"required": True, "type": "bool"} + argument_spec["default_gateway"] = {"required": True, "type": "str"} + argument_spec["dhcp"] = {"required": True, "type": "bool"} + argument_spec["interface_name"] = {"required": True, "type": "str"} + argument_spec["state"] = {"type": "str", "choices": ["set"], "default": "set"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ( + "https://{vcenter_hostname}" + "/api/appliance/networking/interfaces/{interface_name}/ipv6" + ).format(**params) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _set(params, session): + _in_query_parameters = PAYLOAD_FORMAT["set"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["set"]) + subdevice_type = get_subdevice_type( + "/api/appliance/networking/interfaces/{interface_name}/ipv6" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + "/api/appliance/networking/interfaces/{interface_name}/ipv6" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.get(_url, json=payload, **session_timeout(params)) as resp: + before = await resp.json() + + async with session.put(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # The PUT answer does not let us know if the resource has actually been + # modified + if resp.status < 300: + async with session.get( + _url, json=payload, **session_timeout(params) + ) as resp_get: + after = await resp_get.json() + if before == after: + return await update_changed_flag(after, resp_get.status, "get") + return await update_changed_flag(_json, resp.status, "set") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_interfaces_ipv6_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_interfaces_ipv6_info.py new file mode 100644 index 00000000..b9f34076 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_interfaces_ipv6_info.py @@ -0,0 +1,233 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_networking_interfaces_ipv6_info +short_description: Get IPv6 network configuration for specific interface. +description: Get IPv6 network configuration for specific interface. +options: + interface_name: + description: + - Network interface to query, for example, "nic0". Required with I(state=['get']) + type: str + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Collect the IPv6 network information + vmware.vmware_rest.appliance_networking_interfaces_ipv6_info: + interface_name: nic0 + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Collect the IPv6 network information +value: + description: Collect the IPv6 network information + returned: On success + sample: + addresses: + - address: fe80::5054:ff:fea4:6e89 + origin: OTHER + prefix: 64 + status: PREFERRED + autoconf: 1 + configurable: 1 + default_gateway: '' + dhcp: 0 + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"interface_name": "interface_name"}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["interface_name"] = {"type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ( + "https://{vcenter_hostname}" + "/api/appliance/networking/interfaces/{interface_name}/ipv6" + ).format(**params) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ( + "https://{vcenter_hostname}" + "/api/appliance/networking/interfaces/{interface_name}/ipv6" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_noproxy.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_noproxy.py new file mode 100644 index 00000000..d4b961c7 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_noproxy.py @@ -0,0 +1,275 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_networking_noproxy +short_description: Sets servers for which no proxy configuration should be applied +description: Sets servers for which no proxy configuration should be applied. This + operation sets environment variables. In order for this operation to take effect, + a logout from appliance or a service restart is required. If IPv4 is enabled, "127.0.0.1" + and "localhost" will always bypass the proxy (even if they are not explicitly configured). +options: + servers: + description: + - List of strings representing servers to bypass proxy. A server can be a FQDN, + IP address, FQDN:port or IP:port combinations. This parameter is mandatory. + elements: str + required: true + type: list + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - set + default: set + description: [] + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Set HTTP noproxy configuration + vmware.vmware_rest.appliance_networking_noproxy: + servers: + - redhat.com + - ansible.com + register: result + +- name: Remove the noproxy entries + vmware.vmware_rest.appliance_networking_noproxy: + servers: [] + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Remove the noproxy entries +value: + description: Remove the noproxy entries + returned: On success + sample: {} + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "set": {"query": {}, "body": {"servers": "servers"}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["servers"] = {"required": True, "type": "list", "elements": "str"} + argument_spec["state"] = {"type": "str", "choices": ["set"], "default": "set"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/networking/noproxy").format( + **params + ) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _set(params, session): + _in_query_parameters = PAYLOAD_FORMAT["set"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["set"]) + subdevice_type = get_subdevice_type("/api/appliance/networking/noproxy") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ("https://{vcenter_hostname}" "/api/appliance/networking/noproxy").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, json=payload, **session_timeout(params)) as resp: + before = await resp.json() + + async with session.put(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # The PUT answer does not let us know if the resource has actually been + # modified + if resp.status < 300: + async with session.get( + _url, json=payload, **session_timeout(params) + ) as resp_get: + after = await resp_get.json() + if before == after: + return await update_changed_flag(after, resp_get.status, "get") + return await update_changed_flag(_json, resp.status, "set") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_noproxy_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_noproxy_info.py new file mode 100644 index 00000000..bc92ecdf --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_noproxy_info.py @@ -0,0 +1,217 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_networking_noproxy_info +short_description: Returns servers for which no proxy configuration will be applied. +description: Returns servers for which no proxy configuration will be applied. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Get HTTP noproxy configuration + vmware.vmware_rest.appliance_networking_noproxy_info: + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get HTTP noproxy configuration +value: + description: Get HTTP noproxy configuration + returned: On success + sample: + - localhost + - 127.0.0.1 + type: list +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/networking/noproxy").format( + **params + ) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ("https://{vcenter_hostname}" "/api/appliance/networking/noproxy").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_proxy.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_proxy.py new file mode 100644 index 00000000..4050053d --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_proxy.py @@ -0,0 +1,397 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_networking_proxy +short_description: Configures which proxy server to use for the specified protocol +description: Configures which proxy server to use for the specified protocol. This + operation sets environment variables for using proxy. In order for this configuration + to take effect a logout / service restart is required. +options: + config: + description: + - Proxy configuration for the specific protocol. Required with I(state=['test']) + - 'Valid attributes are:' + - ' - C(server) (str): URL of the proxy server ([''test''])' + - ' This key is required with [''test''].' + - ' - C(port) (int): Port to connect to the proxy server. In a ''get'' call, indicates + the port connected to the proxy server. In a ''set'' call, specifies the port + to connect to the proxy server. A value of -1 indicates the default port. ([''test''])' + - ' This key is required with [''test''].' + - ' - C(username) (str): Username for proxy server. ([''test''])' + - ' - C(password) (str): Password for proxy server. ([''test''])' + - ' - C(enabled) (bool): In the result of the C(#get) and C(#list) {@term operations} + this field indicates whether proxying is enabled for a particular protocol. + In the input to the C(test) and C(set) {@term operations} this field specifies + whether proxying should be enabled for a particular protocol. ([''test''])' + - ' This key is required with [''test''].' + type: dict + enabled: + description: + - In the result of the C(#get) and C(#list) {@term operations} this field indicates + whether proxying is enabled for a particular protocol. In the input to the C(test) + and C(set) {@term operations} this field specifies whether proxying should be + enabled for a particular protocol. Required with I(state=['set']) + type: bool + host: + description: + - A hostname, IPv4 or Ipv6 address. Required with I(state=['test']) + type: str + password: + description: + - Password for proxy server. + type: str + port: + description: + - Port to connect to the proxy server. In a 'get' call, indicates the port connected + to the proxy server. In a 'set' call, specifies the port to connect to the proxy + server. A value of -1 indicates the default port. Required with I(state=['set']) + type: int + protocol: + description: + - The protocol for which proxy should be set. This parameter is mandatory. + required: true + type: str + server: + description: + - URL of the proxy server Required with I(state=['set']) + type: str + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - absent + - set + - test + default: set + description: [] + type: str + username: + description: + - Username for proxy server. + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Set the HTTP proxy configuration + vmware.vmware_rest.appliance_networking_proxy: + enabled: true + server: http://datastore.test + port: 3128 + protocol: http + register: result + +- name: Delete the HTTP proxy configuration + vmware.vmware_rest.appliance_networking_proxy: + protocol: http + state: absent + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Delete the HTTP proxy configuration +value: + description: Delete the HTTP proxy configuration + returned: On success + sample: {} + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "set": { + "query": {}, + "body": { + "enabled": "enabled", + "password": "password", + "port": "port", + "server": "server", + "username": "username", + }, + "path": {"protocol": "protocol"}, + }, + "test": { + "query": {}, + "body": {"config": "config", "host": "host"}, + "path": {"protocol": "protocol"}, + }, + "delete": {"query": {}, "body": {}, "path": {"protocol": "protocol"}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["config"] = {"type": "dict"} + argument_spec["enabled"] = {"type": "bool"} + argument_spec["host"] = {"type": "str"} + argument_spec["password"] = {"no_log": True, "type": "str"} + argument_spec["port"] = {"type": "int"} + argument_spec["protocol"] = {"required": True, "type": "str"} + argument_spec["server"] = {"type": "str"} + argument_spec["state"] = { + "type": "str", + "choices": ["absent", "set", "test"], + "default": "set", + } + argument_spec["username"] = {"no_log": True, "type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/networking/proxy").format( + **params + ) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _delete(params, session): + _in_query_parameters = PAYLOAD_FORMAT["delete"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["delete"]) + subdevice_type = get_subdevice_type("/api/appliance/networking/proxy/{protocol}") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" "/api/appliance/networking/proxy/{protocol}" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.delete(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "delete") + + +async def _set(params, session): + _in_query_parameters = PAYLOAD_FORMAT["set"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["set"]) + subdevice_type = get_subdevice_type("/api/appliance/networking/proxy/{protocol}") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" "/api/appliance/networking/proxy/{protocol}" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.get(_url, json=payload, **session_timeout(params)) as resp: + before = await resp.json() + + async with session.put(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # The PUT answer does not let us know if the resource has actually been + # modified + if resp.status < 300: + async with session.get( + _url, json=payload, **session_timeout(params) + ) as resp_get: + after = await resp_get.json() + if before == after: + return await update_changed_flag(after, resp_get.status, "get") + return await update_changed_flag(_json, resp.status, "set") + + +async def _test(params, session): + _in_query_parameters = PAYLOAD_FORMAT["test"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["test"]) + subdevice_type = get_subdevice_type( + "/api/appliance/networking/proxy/{protocol}?action=test" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/appliance/networking/proxy/{protocol}?action=test" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "test") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_proxy_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_proxy_info.py new file mode 100644 index 00000000..3c0ab8e5 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_networking_proxy_info.py @@ -0,0 +1,249 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_networking_proxy_info +short_description: Gets the proxy configuration for a specific protocol. +description: Gets the proxy configuration for a specific protocol. +options: + protocol: + description: + - The protocol whose proxy configuration is requested. Required with I(state=['get']) + type: str + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Get the HTTP proxy configuration + vmware.vmware_rest.appliance_networking_proxy_info: + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get the HTTP proxy configuration +value: + description: Get the HTTP proxy configuration + returned: On success + sample: + ftp: + enabled: 0 + port: -1 + server: '' + http: + enabled: 0 + port: -1 + server: '' + https: + enabled: 0 + port: -1 + server: '' + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"protocol": "protocol"}}, + "list": {"query": {}, "body": {}, "path": {}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["protocol"] = {"type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_list_and_get_module.j2 +def build_url(params): + if params.get("protocol"): + _in_query_parameters = PAYLOAD_FORMAT["get"]["query"].keys() + return ( + ("https://{vcenter_hostname}" "/api/appliance/networking/proxy/").format( + **params + ) + + params["protocol"] + + gen_args(params, _in_query_parameters) + ) + _in_query_parameters = PAYLOAD_FORMAT["list"]["query"].keys() + return ("https://{vcenter_hostname}" "/api/appliance/networking/proxy").format( + **params + ) + gen_args(params, _in_query_parameters) + + +async def entry_point(module, session): + url = build_url(module.params) + async with session.get(url, **session_timeout(module.params)) as resp: + _json = await resp.json() + + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + + if module.params.get("protocol"): + _json["id"] = module.params.get("protocol") + elif module.params.get("label"): # TODO extend the list of filter + _json = await exists(module.params, session, url) + elif ( + isinstance(_json["value"], list) + and len(_json["value"]) > 0 + and isinstance(_json["value"][0], str) + ): + # this is a list of id, we fetch the details + full_device_list = await build_full_device_list(session, url, _json) + _json = {"value": [i["value"] for i in full_device_list]} + + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_ntp.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_ntp.py new file mode 100644 index 00000000..4f114a92 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_ntp.py @@ -0,0 +1,326 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_ntp +short_description: Set NTP servers +description: Set NTP servers. This method updates old NTP servers from configuration + and sets the input NTP servers in the configuration. If NTP based time synchronization + is used internally, the NTP daemon will be restarted to reload given NTP configuration. + In case NTP based time synchronization is not used, this method only replaces servers + in the NTP configuration. +options: + servers: + description: + - List of host names or ip addresses of ntp servers. This parameter is mandatory. + elements: str + required: true + type: list + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - set + - test + default: set + description: [] + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Adjust the NTP configuration + vmware.vmware_rest.appliance_ntp: + servers: + - time.google.com + +- name: Test the NTP configuration + vmware.vmware_rest.appliance_ntp: + state: test + servers: + - time.google.com + register: result + +- name: Adjust the NTP configuration + vmware.vmware_rest.appliance_ntp: + vcenter_hostname: '{{ vcsa_host }}' + servers: + - time.google.com + delegate_to: localhost + +- name: Test the NTP configuration + vmware.vmware_rest.appliance_ntp: + vcenter_hostname: '{{ vcsa_host }}' + state: test + servers: + - time.google.com + delegate_to: localhost + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Test the NTP configuration +value: + description: Test the NTP configuration + returned: On success + sample: + - message: + args: [] + default_message: NTP Server is reachable. + id: com.vmware.appliance.ntp_sync.success + server: time.google.com + status: SERVER_REACHABLE + type: list +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "set": {"query": {}, "body": {"servers": "servers"}, "path": {}}, + "test": {"query": {}, "body": {"servers": "servers"}, "path": {}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["servers"] = {"required": True, "type": "list", "elements": "str"} + argument_spec["state"] = { + "type": "str", + "choices": ["set", "test"], + "default": "set", + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/ntp").format(**params) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _set(params, session): + _in_query_parameters = PAYLOAD_FORMAT["set"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["set"]) + subdevice_type = get_subdevice_type("/api/appliance/ntp") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ("https://{vcenter_hostname}" "/api/appliance/ntp").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, json=payload, **session_timeout(params)) as resp: + before = await resp.json() + + async with session.put(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # The PUT answer does not let us know if the resource has actually been + # modified + if resp.status < 300: + async with session.get( + _url, json=payload, **session_timeout(params) + ) as resp_get: + after = await resp_get.json() + if before == after: + return await update_changed_flag(after, resp_get.status, "get") + return await update_changed_flag(_json, resp.status, "set") + + +async def _test(params, session): + _in_query_parameters = PAYLOAD_FORMAT["test"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["test"]) + subdevice_type = get_subdevice_type("/api/appliance/ntp?action=test") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/appliance/ntp?action=test" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "test") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_ntp_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_ntp_info.py new file mode 100644 index 00000000..61a02532 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_ntp_info.py @@ -0,0 +1,232 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_ntp_info +short_description: Get the NTP configuration status +description: Get the NTP configuration status. If you run the 'timesync.get' command, + you can retrieve the current time synchronization method (NTP- or VMware Tools-based). + The 'ntp' command always returns the NTP server information, even when the time + synchronization mode is not set to NTP. If the time synchronization mode is not + NTP-based, the NTP server status is displayed as down. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Get the NTP configuration + vmware.vmware_rest.appliance_ntp_info: + +- name: Get the NTP configuration + vmware.vmware_rest.appliance_ntp_info: + register: result + +- name: Get the NTP configuration + vmware.vmware_rest.appliance_ntp_info: + vcenter_hostname: '{{ vcsa_host }}' + delegate_to: localhost + +- name: Get the NTP configuration + vmware.vmware_rest.appliance_ntp_info: + vcenter_hostname: '{{ vcsa_host }}' + delegate_to: localhost + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get the NTP configuration +value: + description: Get the NTP configuration + returned: On success + sample: + - time.google.com + type: list +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/ntp").format(**params) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ("https://{vcenter_hostname}" "/api/appliance/ntp").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_services.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_services.py new file mode 100644 index 00000000..8d7d6eee --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_services.py @@ -0,0 +1,326 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_services +short_description: Restarts a service +description: Restarts a service +options: + service: + description: + - identifier of the service to restart This parameter is mandatory. + required: true + type: str + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - restart + - start + - stop + description: [] + required: true + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Stop the ntpd service + vmware.vmware_rest.appliance_services: + service: ntpd + state: stop + register: result + +- name: Start the ntpd service + vmware.vmware_rest.appliance_services: + service: ntpd + state: start + register: result + +- name: Restart the ntpd service + vmware.vmware_rest.appliance_services: + service: ntpd + state: restart + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Restart the ntpd service +value: + description: Restart the ntpd service + returned: On success + sample: {} + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "start": {"query": {}, "body": {}, "path": {"service": "service"}}, + "restart": {"query": {}, "body": {}, "path": {"service": "service"}}, + "stop": {"query": {}, "body": {}, "path": {"service": "service"}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["service"] = {"required": True, "type": "str"} + argument_spec["state"] = { + "required": True, + "type": "str", + "choices": ["restart", "start", "stop"], + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/services").format(**params) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _restart(params, session): + _in_query_parameters = PAYLOAD_FORMAT["restart"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["restart"]) + subdevice_type = get_subdevice_type( + "/api/appliance/services/{service}?action=restart" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/appliance/services/{service}?action=restart" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "restart") + + +async def _start(params, session): + _in_query_parameters = PAYLOAD_FORMAT["start"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["start"]) + subdevice_type = get_subdevice_type( + "/api/appliance/services/{service}?action=start" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/appliance/services/{service}?action=start" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "start") + + +async def _stop(params, session): + _in_query_parameters = PAYLOAD_FORMAT["stop"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["stop"]) + subdevice_type = get_subdevice_type("/api/appliance/services/{service}?action=stop") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/appliance/services/{service}?action=stop" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "stop") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_services_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_services_info.py new file mode 100644 index 00000000..dd8a07a6 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_services_info.py @@ -0,0 +1,243 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_services_info +short_description: Returns the state of a service. +description: Returns the state of a service. +options: + service: + description: + - identifier of the service whose state is being queried. Required with I(state=['get']) + type: str + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Get information about ntpd + vmware.vmware_rest.appliance_services_info: + service: ntpd + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get information about ntpd +id: + description: moid of the resource + returned: On success + sample: ntpd + type: str +value: + description: Get information about ntpd + returned: On success + sample: + description: ntpd.service + state: STARTED + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"service": "service"}}, + "list": {"query": {}, "body": {}, "path": {}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["service"] = {"type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_list_and_get_module.j2 +def build_url(params): + if params.get("service"): + _in_query_parameters = PAYLOAD_FORMAT["get"]["query"].keys() + return ( + ("https://{vcenter_hostname}" "/api/appliance/services/").format(**params) + + params["service"] + + gen_args(params, _in_query_parameters) + ) + _in_query_parameters = PAYLOAD_FORMAT["list"]["query"].keys() + return ("https://{vcenter_hostname}" "/api/appliance/services").format( + **params + ) + gen_args(params, _in_query_parameters) + + +async def entry_point(module, session): + url = build_url(module.params) + async with session.get(url, **session_timeout(module.params)) as resp: + _json = await resp.json() + + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + + if module.params.get("service"): + _json["id"] = module.params.get("service") + elif module.params.get("label"): # TODO extend the list of filter + _json = await exists(module.params, session, url) + elif ( + isinstance(_json["value"], list) + and len(_json["value"]) > 0 + and isinstance(_json["value"][0], str) + ): + # this is a list of id, we fetch the details + full_device_list = await build_full_device_list(session, url, _json) + _json = {"value": [i["value"] for i in full_device_list]} + + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_shutdown.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_shutdown.py new file mode 100644 index 00000000..a999b0e8 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_shutdown.py @@ -0,0 +1,337 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_shutdown +short_description: Cancel pending shutdown action. +description: Cancel pending shutdown action. +options: + delay: + description: + - Minutes after which poweroff should start. If 0 is specified, poweroff will + start immediately. Required with I(state=['poweroff', 'reboot']) + type: int + reason: + description: + - Reason for peforming poweroff. Required with I(state=['poweroff', 'reboot']) + type: str + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - cancel + - poweroff + - reboot + description: [] + required: true + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Shutdown the appliance + vmware.vmware_rest.appliance_shutdown: + state: poweroff + reason: this is an example + delay: 600 + register: result + +- name: Abort the shutdown of the appliance + vmware.vmware_rest.appliance_shutdown: + state: cancel + register: result + +- name: Reboot the appliance + vmware.vmware_rest.appliance_shutdown: + state: reboot + reason: this is an example + delay: 600 + register: result + +- name: Abort the reboot + vmware.vmware_rest.appliance_shutdown: + state: cancel + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Abort the reboot +value: + description: Abort the reboot + returned: On success + sample: {} + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "poweroff": { + "query": {}, + "body": {"delay": "delay", "reason": "reason"}, + "path": {}, + }, + "cancel": {"query": {}, "body": {}, "path": {}}, + "reboot": {"query": {}, "body": {"delay": "delay", "reason": "reason"}, "path": {}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["delay"] = {"type": "int"} + argument_spec["reason"] = {"type": "str"} + argument_spec["state"] = { + "required": True, + "type": "str", + "choices": ["cancel", "poweroff", "reboot"], + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/shutdown").format(**params) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _cancel(params, session): + _in_query_parameters = PAYLOAD_FORMAT["cancel"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["cancel"]) + subdevice_type = get_subdevice_type("/api/appliance/shutdown?action=cancel") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/appliance/shutdown?action=cancel" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "cancel") + + +async def _poweroff(params, session): + _in_query_parameters = PAYLOAD_FORMAT["poweroff"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["poweroff"]) + subdevice_type = get_subdevice_type("/api/appliance/shutdown?action=poweroff") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/appliance/shutdown?action=poweroff" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "poweroff") + + +async def _reboot(params, session): + _in_query_parameters = PAYLOAD_FORMAT["reboot"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["reboot"]) + subdevice_type = get_subdevice_type("/api/appliance/shutdown?action=reboot") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/appliance/shutdown?action=reboot" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "reboot") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_shutdown_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_shutdown_info.py new file mode 100644 index 00000000..2251ca1f --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_shutdown_info.py @@ -0,0 +1,220 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_shutdown_info +short_description: Get details about the pending shutdown action. +description: Get details about the pending shutdown action. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Ensure there is no ongoing shutdown + vmware.vmware_rest.appliance_shutdown_info: + register: result + +- name: Get the ongoing shutdown + vmware.vmware_rest.appliance_shutdown_info: + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get the ongoing shutdown +value: + description: Get the ongoing shutdown + returned: On success + sample: + action: reboot + reason: this is an example + shutdown_time: '2022-06-24T08:45:02.000Z' + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/shutdown").format(**params) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ("https://{vcenter_hostname}" "/api/appliance/shutdown").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_system_globalfips.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_system_globalfips.py new file mode 100644 index 00000000..4e409d0d --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_system_globalfips.py @@ -0,0 +1,273 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_system_globalfips +short_description: Enable/Disable Global FIPS mode for the appliance +description: Enable/Disable Global FIPS mode for the appliance. <p><b>Caution:</b> + Changing the value of this setting will reboot the Appliance. +options: + enabled: + description: + - FIPS setting state. + type: bool + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - present + default: present + description: [] + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +""" + +RETURN = r""" +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "update": {"query": {}, "body": {"enabled": "enabled"}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["enabled"] = {"type": "bool"} + argument_spec["state"] = { + "type": "str", + "choices": ["present"], + "default": "present", + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/system/global-fips").format( + **params + ) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _update(params, session): + payload = prepare_payload(params, PAYLOAD_FORMAT["update"]) + _url = ("https://{vcenter_hostname}" "/api/appliance/system/global-fips").format( + **params + ) + async with session.get(_url, **session_timeout(params)) as resp: + _json = await resp.json() + if "value" in _json: + value = _json["value"] + else: # 7.0.2 and greater + value = _json + for k, v in value.items(): + if k in payload: + if isinstance(payload[k], dict) and isinstance(v, dict): + to_delete = True + for _k in list(payload[k].keys()): + if payload[k][_k] != v.get(_k): + to_delete = False + if to_delete: + del payload[k] + elif payload[k] == v: + del payload[k] + elif payload[k] == {}: + del payload[k] + + if payload == {} or payload == {"spec": {}}: + # Nothing has changed + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + _json["id"] = params.get("None") + return await update_changed_flag(_json, resp.status, "get") + async with session.put(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # e.g: content_configuration + if not _json and resp.status == 204: + async with session.get(_url, **session_timeout(params)) as resp_get: + _json_get = await resp_get.json() + if _json_get: + _json = _json_get + + _json["id"] = params.get("None") + return await update_changed_flag(_json, resp.status, "update") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_system_globalfips_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_system_globalfips_info.py new file mode 100644 index 00000000..986b0ef7 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_system_globalfips_info.py @@ -0,0 +1,206 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_system_globalfips_info +short_description: Get current appliance FIPS settings. +description: Get current appliance FIPS settings. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +""" + +RETURN = r""" +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/system/global-fips").format( + **params + ) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ("https://{vcenter_hostname}" "/api/appliance/system/global-fips").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_system_storage.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_system_storage.py new file mode 100644 index 00000000..fa21cd93 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_system_storage.py @@ -0,0 +1,287 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_system_storage +short_description: Resize all partitions to 100 percent of disk size. +description: Resize all partitions to 100 percent of disk size. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - resize + - resize_ex + description: [] + required: true + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Resize the first partition and return the state of the partition before and + after the operation + vmware.vmware_rest.appliance_system_storage: + state: resize_ex + register: result + +- name: Resize the first partition + vmware.vmware_rest.appliance_system_storage: + state: resize + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Resize the first partition and return the state of the partition before and after the operation +value: + description: Resize the first partition and return the state of the partition before + and after the operation + returned: On success + sample: {} + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "resize_ex": {"query": {}, "body": {}, "path": {}}, + "resize": {"query": {}, "body": {}, "path": {}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["state"] = { + "required": True, + "type": "str", + "choices": ["resize", "resize_ex"], + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/system/storage").format( + **params + ) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _resize(params, session): + _in_query_parameters = PAYLOAD_FORMAT["resize"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["resize"]) + subdevice_type = get_subdevice_type("/api/appliance/system/storage?action=resize") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/appliance/system/storage?action=resize" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "resize") + + +async def _resize_ex(params, session): + _in_query_parameters = PAYLOAD_FORMAT["resize_ex"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["resize_ex"]) + subdevice_type = get_subdevice_type( + "/api/appliance/system/storage?action=resize-ex" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/appliance/system/storage?action=resize-ex" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "resize_ex") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_system_storage_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_system_storage_info.py new file mode 100644 index 00000000..29ded58f --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_system_storage_info.py @@ -0,0 +1,208 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_system_storage_info +short_description: Get disk to partition mapping. +description: Get disk to partition mapping. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Get the appliance storage information + vmware.vmware_rest.appliance_system_storage_info: + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get the appliance storage information +value: + description: Get the appliance storage information + returned: On success + sample: [] + type: list +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "list": {"query": {}, "body": {}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_list_and_get_module.j2 +def build_url(params): + _in_query_parameters = PAYLOAD_FORMAT["list"]["query"].keys() + return ("https://{vcenter_hostname}" "/api/appliance/system/storage").format( + **params + ) + gen_args(params, _in_query_parameters) + + +async def entry_point(module, session): + url = build_url(module.params) + async with session.get(url, **session_timeout(module.params)) as resp: + _json = await resp.json() + + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_system_time_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_system_time_info.py new file mode 100644 index 00000000..c2ba5802 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_system_time_info.py @@ -0,0 +1,217 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_system_time_info +short_description: Get system time. +description: Get system time. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Get the current time + vmware.vmware_rest.appliance_system_time_info: + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get the current time +value: + description: Get the current time + returned: On success + sample: + date: Thu 06-23-2022 + seconds_since_epoch: null + time: 10:45:11 PM + timezone: UTC + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/system/time").format(**params) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ("https://{vcenter_hostname}" "/api/appliance/system/time").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_system_time_timezone.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_system_time_timezone.py new file mode 100644 index 00000000..9a86e801 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_system_time_timezone.py @@ -0,0 +1,263 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_system_time_timezone +short_description: Set time zone. +description: Set time zone. +options: + name: + description: + - Time zone name. This parameter is mandatory. + required: true + type: str + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - set + default: set + description: [] + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Use the UTC timezone + vmware.vmware_rest.appliance_system_time_timezone: + name: UTC + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Use the UTC timezone +value: + description: Use the UTC timezone + returned: On success + sample: UTC + type: str +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "set": {"query": {}, "body": {"name": "name"}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["name"] = {"required": True, "type": "str"} + argument_spec["state"] = {"type": "str", "choices": ["set"], "default": "set"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/system/time/timezone").format( + **params + ) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _set(params, session): + _in_query_parameters = PAYLOAD_FORMAT["set"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["set"]) + subdevice_type = get_subdevice_type("/api/appliance/system/time/timezone") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ("https://{vcenter_hostname}" "/api/appliance/system/time/timezone").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, json=payload, **session_timeout(params)) as resp: + before = await resp.json() + + async with session.put(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # The PUT answer does not let us know if the resource has actually been + # modified + if resp.status < 300: + async with session.get( + _url, json=payload, **session_timeout(params) + ) as resp_get: + after = await resp_get.json() + if before == after: + return await update_changed_flag(after, resp_get.status, "get") + return await update_changed_flag(_json, resp.status, "set") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_system_time_timezone_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_system_time_timezone_info.py new file mode 100644 index 00000000..40ec9382 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_system_time_timezone_info.py @@ -0,0 +1,215 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_system_time_timezone_info +short_description: Get time zone. +description: Get time zone. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Get the timezone configuration + vmware.vmware_rest.appliance_system_time_timezone_info: + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get the timezone configuration +value: + description: Get the timezone configuration + returned: On success + sample: UTC + type: str +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/system/time/timezone").format( + **params + ) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ("https://{vcenter_hostname}" "/api/appliance/system/time/timezone").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_system_version_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_system_version_info.py new file mode 100644 index 00000000..9b06192b --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_system_version_info.py @@ -0,0 +1,222 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_system_version_info +short_description: Get the version. +description: Get the version. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Get the VCSA version + vmware.vmware_rest.appliance_system_version_info: + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get the VCSA version +value: + description: Get the VCSA version + returned: On success + sample: + build: '19717403' + install_time: '2022-06-16T18:25:58.876Z' + product: VMware vCenter Server + releasedate: May 12, 2022 + summary: Patch for VMware vCenter Server 7.0 + type: vCenter Server with an embedded Platform Services Controller + version: 7.0.3.00600 + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/system/version").format( + **params + ) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ("https://{vcenter_hostname}" "/api/appliance/system/version").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_timesync.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_timesync.py new file mode 100644 index 00000000..20be8381 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_timesync.py @@ -0,0 +1,268 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_timesync +short_description: Set time synchronization mode. +description: Set time synchronization mode. +options: + mode: + choices: + - DISABLED + - HOST + - NTP + description: + - The C(time_sync_mode) defines time synchronization modes This parameter is mandatory. + required: true + type: str + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - set + default: set + description: [] + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Ensure we use NTP + vmware.vmware_rest.appliance_timesync: + mode: NTP +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Ensure we use NTP +value: + description: Ensure we use NTP + returned: On success + sample: NTP + type: str +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "set": {"query": {}, "body": {"mode": "mode"}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["mode"] = { + "required": True, + "type": "str", + "choices": ["DISABLED", "HOST", "NTP"], + } + argument_spec["state"] = {"type": "str", "choices": ["set"], "default": "set"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/timesync").format(**params) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _set(params, session): + _in_query_parameters = PAYLOAD_FORMAT["set"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["set"]) + subdevice_type = get_subdevice_type("/api/appliance/timesync") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ("https://{vcenter_hostname}" "/api/appliance/timesync").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, json=payload, **session_timeout(params)) as resp: + before = await resp.json() + + async with session.put(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # The PUT answer does not let us know if the resource has actually been + # modified + if resp.status < 300: + async with session.get( + _url, json=payload, **session_timeout(params) + ) as resp_get: + after = await resp_get.json() + if before == after: + return await update_changed_flag(after, resp_get.status, "get") + return await update_changed_flag(_json, resp.status, "set") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_timesync_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_timesync_info.py new file mode 100644 index 00000000..2b2ed965 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_timesync_info.py @@ -0,0 +1,213 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_timesync_info +short_description: Get time synchronization mode. +description: Get time synchronization mode. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Get information regarding the clock synchronization + vmware.vmware_rest.appliance_timesync_info: + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get information regarding the clock synchronization +value: + description: Get information regarding the clock synchronization + returned: On success + sample: NTP + type: str +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/timesync").format(**params) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ("https://{vcenter_hostname}" "/api/appliance/timesync").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_update_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_update_info.py new file mode 100644 index 00000000..ec4af001 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_update_info.py @@ -0,0 +1,215 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_update_info +short_description: Gets the current status of the appliance update. +description: Gets the current status of the appliance update. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Check if the system is up to date + vmware.vmware_rest.appliance_update_info: + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Check if the system is up to date +value: + description: Check if the system is up to date + returned: On success + sample: + state: UP_TO_DATE + version: 7.0.3.00600 + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/appliance/update").format(**params) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ("https://{vcenter_hostname}" "/api/appliance/update").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_vmon_service.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_vmon_service.py new file mode 100644 index 00000000..98052f0f --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_vmon_service.py @@ -0,0 +1,417 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_vmon_service +short_description: Lists details of services managed by vMon. +description: Lists details of services managed by vMon. +options: + service: + description: + - identifier of the service whose properties are being updated. + - The parameter must be the id of a resource returned by M(vmware.vmware_rest.appliance_vmon_service). + Required with I(state=['restart', 'start', 'stop']) + type: str + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + startup_type: + choices: + - AUTOMATIC + - DISABLED + - MANUAL + description: + - The I(startup_type) enumerated type defines valid Startup Type for services + managed by vMon. + type: str + state: + choices: + - list_details + - present + - restart + - start + - stop + default: present + description: [] + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Adjust vpxd configuration + vmware.vmware_rest.appliance_vmon_service: + service: vpxd + startup_type: AUTOMATIC + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Adjust vpxd configuration +id: + description: moid of the resource + returned: On success + sample: vpxd + type: str +value: + description: Adjust vpxd configuration + returned: On success + sample: {} + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "restart": {"query": {}, "body": {}, "path": {"service": "service"}}, + "start": {"query": {}, "body": {}, "path": {"service": "service"}}, + "update": { + "query": {}, + "body": {"startup_type": "spec/startup_type"}, + "path": {"service": "service"}, + }, + "stop": {"query": {}, "body": {}, "path": {"service": "service"}}, + "list_details": {"query": {}, "body": {}, "path": {}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["service"] = {"type": "str"} + argument_spec["startup_type"] = { + "type": "str", + "choices": ["AUTOMATIC", "DISABLED", "MANUAL"], + } + argument_spec["state"] = { + "type": "str", + "choices": ["list_details", "present", "restart", "start", "stop"], + "default": "present", + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/rest/appliance/vmon/service").format( + **params + ) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _list_details(params, session): + _in_query_parameters = PAYLOAD_FORMAT["list_details"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["list_details"]) + subdevice_type = get_subdevice_type("/rest/appliance/vmon/service") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/rest/appliance/vmon/service" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.get(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "list_details") + + +async def _restart(params, session): + _in_query_parameters = PAYLOAD_FORMAT["restart"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["restart"]) + subdevice_type = get_subdevice_type( + "/rest/appliance/vmon/service/{service}/restart" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/rest/appliance/vmon/service/{service}/restart" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "restart") + + +async def _start(params, session): + _in_query_parameters = PAYLOAD_FORMAT["start"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["start"]) + subdevice_type = get_subdevice_type("/rest/appliance/vmon/service/{service}/start") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/rest/appliance/vmon/service/{service}/start" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "start") + + +async def _stop(params, session): + _in_query_parameters = PAYLOAD_FORMAT["stop"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["stop"]) + subdevice_type = get_subdevice_type("/rest/appliance/vmon/service/{service}/stop") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/rest/appliance/vmon/service/{service}/stop" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "stop") + + +async def _update(params, session): + payload = prepare_payload(params, PAYLOAD_FORMAT["update"]) + _url = ( + "https://{vcenter_hostname}" "/rest/appliance/vmon/service/{service}" + ).format(**params) + async with session.get(_url, **session_timeout(params)) as resp: + _json = await resp.json() + if "value" in _json: + value = _json["value"] + else: # 7.0.2 and greater + value = _json + for k, v in value.items(): + if k in payload: + if isinstance(payload[k], dict) and isinstance(v, dict): + to_delete = True + for _k in list(payload[k].keys()): + if payload[k][_k] != v.get(_k): + to_delete = False + if to_delete: + del payload[k] + elif payload[k] == v: + del payload[k] + elif payload[k] == {}: + del payload[k] + + if payload == {} or payload == {"spec": {}}: + # Nothing has changed + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + _json["id"] = params.get("service") + return await update_changed_flag(_json, resp.status, "get") + async with session.patch(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # e.g: content_configuration + if not _json and resp.status == 204: + async with session.get(_url, **session_timeout(params)) as resp_get: + _json_get = await resp_get.json() + if _json_get: + _json = _json_get + + _json["id"] = params.get("service") + return await update_changed_flag(_json, resp.status, "update") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_vmon_service_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_vmon_service_info.py new file mode 100644 index 00000000..130892c5 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/appliance_vmon_service_info.py @@ -0,0 +1,605 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: appliance_vmon_service_info +short_description: Returns the state of a service. +description: Returns the state of a service. +options: + service: + description: + - identifier of the service whose state is being queried. + - The parameter must be the id of a resource returned by M(vmware.vmware_rest.appliance_vmon_service). + Required with I(state=['get']) + type: str + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Get information about a VMON service + vmware.vmware_rest.appliance_vmon_service_info: + service: vpxd + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get information about a VMON service +value: + description: Get information about a VMON service + returned: On success + sample: + - key: analytics + value: + description_key: cis.analytics.ServiceDescription + health: HEALTHY + health_messages: [] + name_key: cis.analytics.ServiceName + startup_type: AUTOMATIC + state: STARTED + - key: applmgmt + value: + description_key: cis.applmgmt.ServiceDescription + health: HEALTHY + health_messages: [] + name_key: cis.applmgmt.ServiceName + startup_type: AUTOMATIC + state: STARTED + - key: certificateauthority + value: + description_key: cis.certificateauthority.ServiceDescription + health: HEALTHY + health_messages: + - args: + - GREEN + default_message: Health is GREEN + id: certificateathority.health.statuscode + name_key: cis.certificateauthority.ServiceName + startup_type: AUTOMATIC + state: STARTED + - key: certificatemanagement + value: + description_key: cis.certificatemanagement.ServiceDescription + health: HEALTHY + health_messages: + - args: + - GREEN + default_message: Health is GREEN + id: certificatemanagement.health.statuscode + name_key: cis.certificatemanagement.ServiceName + startup_type: AUTOMATIC + state: STARTED + - key: cis-license + value: + description_key: cis.cis-license.ServiceDescription + health: HEALTHY + health_messages: + - args: [] + default_message: The License Service is operational. + id: cis.license.health.ok + name_key: cis.cis-license.ServiceName + startup_type: AUTOMATIC + state: STARTED + - key: content-library + value: + description_key: cis.content-library.ServiceDescription + health: HEALTHY + health_messages: + - args: [] + default_message: Database server connection is GREEN. + id: com.vmware.vdcs.vsphere-cs-lib.db_health_green + name_key: cis.content-library.ServiceName + startup_type: AUTOMATIC + state: STARTED + - key: eam + value: + description_key: cis.eam.ServiceDescription + health: HEALTHY + health_messages: + - args: [] + default_message: '' + id: cis.eam.statusOK + name_key: cis.eam.ServiceName + startup_type: AUTOMATIC + state: STARTED + - key: envoy + value: + description_key: cis.envoy.ServiceDescription + health: HEALTHY + health_messages: [] + name_key: cis.envoy.ServiceName + startup_type: AUTOMATIC + state: STARTED + - key: hvc + value: + description_key: cis.hvc.ServiceDescription + health: HEALTHY + health_messages: + - args: + - GREEN + default_message: Health is GREEN + id: hvc.health.statuscode + name_key: cis.hvc.ServiceName + startup_type: AUTOMATIC + state: STARTED + - key: imagebuilder + value: + description_key: cis.imagebuilder.ServiceDescription + name_key: cis.imagebuilder.ServiceName + startup_type: MANUAL + state: STOPPED + - key: infraprofile + value: + description_key: cis.infraprofile.ServiceDescription + health: HEALTHY + health_messages: + - args: + - GREEN + default_message: Health is GREEN + id: infraprofile.health.statuscode + name_key: cis.infraprofile.ServiceName + startup_type: AUTOMATIC + state: STARTED + - key: lookupsvc + value: + description_key: cis.lookupsvc.ServiceDescription + health: HEALTHY + health_messages: [] + name_key: cis.lookupsvc.ServiceName + startup_type: AUTOMATIC + state: STARTED + - key: netdumper + value: + description_key: cis.netdumper.ServiceDescription + name_key: cis.netdumper.ServiceName + startup_type: MANUAL + state: STOPPED + - key: observability-vapi + value: + description_key: cis.observability-vapi.ServiceDescription + health: HEALTHY + health_messages: + - args: + - GREEN + default_message: Health is GREEN + id: observability.health.statuscode + name_key: cis.observability-vapi.ServiceName + startup_type: AUTOMATIC + state: STARTED + - key: perfcharts + value: + description_key: cis.perfcharts.ServiceDescription + health: HEALTHY + health_messages: + - args: [] + default_message: health.statsReoptInitalizer.green + id: health.statsReoptInitalizer.green + name_key: cis.perfcharts.ServiceName + startup_type: AUTOMATIC + state: STARTED + - key: pschealth + value: + description_key: cis.pschealth.ServiceDescription + health: HEALTHY + health_messages: [] + name_key: cis.pschealth.ServiceName + startup_type: AUTOMATIC + state: STARTED + - key: rbd + value: + description_key: cis.rbd.ServiceDescription + name_key: cis.rbd.ServiceName + startup_type: MANUAL + state: STOPPED + - key: rhttpproxy + value: + description_key: cis.rhttpproxy.ServiceDescription + health: HEALTHY + health_messages: [] + name_key: cis.rhttpproxy.ServiceName + startup_type: AUTOMATIC + state: STARTED + - key: sca + value: + description_key: cis.sca.ServiceDescription + health: HEALTHY + health_messages: [] + name_key: cis.sca.ServiceName + startup_type: AUTOMATIC + state: STARTED + - key: sps + value: + description_key: cis.sps.ServiceDescription + health: HEALTHY + health_messages: [] + name_key: cis.sps.ServiceName + startup_type: AUTOMATIC + state: STARTED + - key: statsmonitor + value: + description_key: cis.statsmonitor.ServiceDescription + health: HEALTHY + health_messages: + - args: [] + default_message: Appliance monitoring service is healthy. + id: com.vmware.applmgmt.mon.health.healthy + name_key: cis.statsmonitor.ServiceName + startup_type: AUTOMATIC + state: STARTED + - key: sts + value: + description_key: cis.sts.ServiceDescription + health: HEALTHY + health_messages: [] + name_key: cis.sts.ServiceName + startup_type: AUTOMATIC + state: STARTED + - key: topologysvc + value: + description_key: cis.topologysvc.ServiceDescription + health: HEALTHY + health_messages: + - args: + - GREEN + default_message: Health is GREEN + id: topologysvc.health.statuscode + name_key: cis.topologysvc.ServiceName + startup_type: AUTOMATIC + state: STARTED + - key: trustmanagement + value: + description_key: cis.trustmanagement.ServiceDescription + health: HEALTHY + health_messages: + - args: + - GREEN + default_message: Health is GREEN + id: trustmanagement.health.statuscode + name_key: cis.trustmanagement.ServiceName + startup_type: AUTOMATIC + state: STARTED + - key: updatemgr + value: + description_key: cis.updatemgr.ServiceDescription + health: HEALTHY + health_messages: [] + name_key: cis.updatemgr.ServiceName + startup_type: AUTOMATIC + state: STARTED + - key: vapi-endpoint + value: + description_key: cis.vapi-endpoint.ServiceDescription + health: HEALTHY + health_messages: + - args: + - 2022-06-23T22:40:32UTC + - 2022-06-23T22:40:32UTC + default_message: Configuration health status is created between 2022-06-23T22:40:32UTC + and 2022-06-23T22:40:32UTC. + id: com.vmware.vapi.endpoint.healthStatusProducedTimes + name_key: cis.vapi-endpoint.ServiceName + startup_type: AUTOMATIC + state: STARTED + - key: vcha + value: + description_key: cis.vcha.ServiceDescription + name_key: cis.vcha.ServiceName + startup_type: DISABLED + state: STOPPED + - key: vlcm + value: + description_key: cis.vlcm.ServiceDescription + health: HEALTHY + health_messages: [] + name_key: cis.vlcm.ServiceName + startup_type: AUTOMATIC + state: STARTED + - key: vmcam + value: + description_key: cis.vmcam.ServiceDescription + name_key: cis.vmcam.ServiceName + startup_type: MANUAL + state: STOPPED + - key: vmonapi + value: + description_key: cis.vmonapi.ServiceDescription + health: HEALTHY + health_messages: [] + name_key: cis.vmonapi.ServiceName + startup_type: AUTOMATIC + state: STARTED + - key: vmware-postgres-archiver + value: + description_key: cis.vmware-postgres-archiver.ServiceDescription + health: HEALTHY + health_messages: + - args: [] + default_message: VMware Archiver service is healthy. + id: cis.vmware-postgres-archiver.health.healthy + name_key: cis.vmware-postgres-archiver.ServiceName + startup_type: AUTOMATIC + state: STARTED + - key: vmware-vpostgres + value: + description_key: cis.vmware-vpostgres.ServiceDescription + health: HEALTHY + health_messages: + - args: [] + default_message: Service vmware-vpostgres is healthy. + id: cis.vmware-vpostgres.health.healthy + name_key: cis.vmware-vpostgres.ServiceName + startup_type: AUTOMATIC + state: STARTED + - key: vpxd + value: + description_key: cis.vpxd.ServiceDescription + health: HEALTHY + health_messages: + - args: + - vCenter Server + - GREEN + default_message: '{0} health is {1}' + id: vc.health.statuscode + - args: + - VirtualCenter Database + - GREEN + default_message: '{0} health is {1}' + id: vc.health.statuscode + name_key: cis.vpxd.ServiceName + startup_type: AUTOMATIC + state: STARTED + - key: vpxd-svcs + value: + description_key: cis.vpxd-svcs.ServiceDescription + health: HEALTHY + health_messages: + - args: [] + default_message: Tagging service is in a healthy state + id: cis.tagging.health.status + name_key: cis.vpxd-svcs.ServiceName + startup_type: AUTOMATIC + state: STARTED + - key: vsan-health + value: + description_key: cis.vsan-health.ServiceDescription + health: HEALTHY + health_messages: [] + name_key: cis.vsan-health.ServiceName + startup_type: AUTOMATIC + state: STARTED + - key: vsm + value: + description_key: cis.vsm.ServiceDescription + health: HEALTHY + health_messages: [] + name_key: cis.vsm.ServiceName + startup_type: AUTOMATIC + state: STARTED + - key: vsphere-ui + value: + description_key: cis.vsphere-ui.ServiceDescription + health: HEALTHY + health_messages: [] + name_key: cis.vsphere-ui.ServiceName + startup_type: AUTOMATIC + state: STARTED + - key: vstats + value: + description_key: cis.vstats.ServiceDescription + health: HEALTHY + health_messages: [] + name_key: cis.vstats.ServiceName + startup_type: AUTOMATIC + state: STARTED + - key: vtsdb + value: + description_key: cis.vtsdb.ServiceDescription + health: HEALTHY + health_messages: + - args: [] + default_message: Service vtsdb is healthy. + id: cis.vtsdb.health.healthy + name_key: cis.vtsdb.ServiceName + startup_type: AUTOMATIC + state: STARTED + - key: wcp + value: + description_key: cis.wcp.ServiceDescription + health: HEALTHY + health_messages: [] + name_key: cis.wcp.ServiceName + startup_type: AUTOMATIC + state: STARTED + type: list +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"service": "service"}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["service"] = {"type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/rest/appliance/vmon/service").format( + **params + ) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ("https://{vcenter_hostname}" "/rest/appliance/vmon/service").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/content_configuration.py b/ansible_collections/vmware/vmware_rest/plugins/modules/content_configuration.py new file mode 100644 index 00000000..769caedb --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/content_configuration.py @@ -0,0 +1,325 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: content_configuration +short_description: Updates the configuration +description: Updates the configuration. The update is incremental. Any {@term field} + in the {@link ConfigurationModel} {@term structure} that is {@term unset} will not + be modified. Note that this update {@term operation} doesn't guarantee an atomic + change of all the properties. In the case of a system crash or failure, some of + the properties could be left unchanged while others may be updated. +options: + automatic_sync_enabled: + description: + - 'Whether automatic synchronization is enabled. When automatic synchronization + is enabled, the Content Library Service will automatically synchronize all subscribed + libraries on a daily basis. Subscribed libraries with the C(subscription_info.automaticSyncEnabled) + flag turned on will be synchronized every hour between {@link #automaticSyncStartHour} + and {@link #automaticSyncStopHour}.' + type: bool + automatic_sync_start_hour: + description: + - The hour at which the automatic synchronization will start. This value is between + 0 (midnight) and 23 inclusive. + type: int + automatic_sync_stop_hour: + description: + - The hour at which the automatic synchronization will stop. Any active synchronization + operation will continue to run, however no new synchronization operations will + be triggered after the stop hour. This value is between 0 (midnight) and 23 + inclusive. + type: int + maximum_concurrent_item_syncs: + description: + - The maximum allowed number of library items to synchronize concurrently from + remote libraries. This must be a positive number. The service may not be able + to guarantee the requested concurrency if there is no available capacity. This + setting is global across all subscribed libraries. + type: int + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - present + default: present + description: [] + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Turn on the autmatic syncrhronization + vmware.vmware_rest.content_configuration: + automatic_sync_enabled: true +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Turn on the autmatic syncrhronization +id: + description: moid of the resource + returned: On success + sample: null + type: dict +value: + description: Turn on the autmatic syncrhronization + returned: On success + sample: + automatic_sync_enabled: 1 + automatic_sync_start_hour: 20 + automatic_sync_stop_hour: 7 + maximum_concurrent_item_syncs: 5 + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "update": { + "query": {}, + "body": { + "automatic_sync_enabled": "automatic_sync_enabled", + "automatic_sync_start_hour": "automatic_sync_start_hour", + "automatic_sync_stop_hour": "automatic_sync_stop_hour", + "maximum_concurrent_item_syncs": "maximum_concurrent_item_syncs", + }, + "path": {}, + } +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["automatic_sync_enabled"] = {"type": "bool"} + argument_spec["automatic_sync_start_hour"] = {"type": "int"} + argument_spec["automatic_sync_stop_hour"] = {"type": "int"} + argument_spec["maximum_concurrent_item_syncs"] = {"type": "int"} + argument_spec["state"] = { + "type": "str", + "choices": ["present"], + "default": "present", + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/content/configuration").format(**params) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _update(params, session): + payload = prepare_payload(params, PAYLOAD_FORMAT["update"]) + _url = ("https://{vcenter_hostname}" "/api/content/configuration").format(**params) + async with session.get(_url, **session_timeout(params)) as resp: + _json = await resp.json() + if "value" in _json: + value = _json["value"] + else: # 7.0.2 and greater + value = _json + for k, v in value.items(): + if k in payload: + if isinstance(payload[k], dict) and isinstance(v, dict): + to_delete = True + for _k in list(payload[k].keys()): + if payload[k][_k] != v.get(_k): + to_delete = False + if to_delete: + del payload[k] + elif payload[k] == v: + del payload[k] + elif payload[k] == {}: + del payload[k] + + if payload == {} or payload == {"spec": {}}: + # Nothing has changed + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + _json["id"] = params.get("None") + return await update_changed_flag(_json, resp.status, "get") + async with session.patch(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # e.g: content_configuration + if not _json and resp.status == 204: + async with session.get(_url, **session_timeout(params)) as resp_get: + _json_get = await resp_get.json() + if _json_get: + _json = _json_get + + _json["id"] = params.get("None") + return await update_changed_flag(_json, resp.status, "update") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/content_configuration_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/content_configuration_info.py new file mode 100644 index 00000000..8eaa3b5d --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/content_configuration_info.py @@ -0,0 +1,217 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: content_configuration_info +short_description: Retrieves the current configuration values. +description: Retrieves the current configuration values. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Get the vSphere content syncrhronization configuration + vmware.vmware_rest.content_configuration_info: + register: current_content_configuration +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get the vSphere content syncrhronization configuration +value: + description: Get the vSphere content syncrhronization configuration + returned: On success + sample: + automatic_sync_enabled: 1 + automatic_sync_start_hour: 20 + automatic_sync_stop_hour: 7 + maximum_concurrent_item_syncs: 5 + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/content/configuration").format(**params) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ("https://{vcenter_hostname}" "/api/content/configuration").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/content_library_item_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/content_library_item_info.py new file mode 100644 index 00000000..c60752f2 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/content_library_item_info.py @@ -0,0 +1,312 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: content_library_item_info +short_description: Returns the {@link ItemModel} with the given identifier. +description: Returns the {@link ItemModel} with the given identifier. +options: + library_id: + description: + - Identifier of the library whose items should be returned. Required with I(state=['list']) + type: str + library_item_id: + description: + - Identifier of the library item to return. Required with I(state=['get']) + type: str + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Create a content library pointing on a NFS share + vmware.vmware_rest.content_locallibrary: + name: my_library_on_nfs + description: automated + publish_info: + published: true + authentication_method: NONE + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + state: present + register: nfs_lib + +- name: Get the list of items of the NFS library + vmware.vmware_rest.content_library_item_info: + library_id: '{{ nfs_lib.id }}' + register: lib_items + +- name: Get the list of items of the NFS library + vmware.vmware_rest.content_library_item_info: + library_id: '{{ nfs_lib.id }}' + register: result + +- name: Create a new local content library + vmware.vmware_rest.content_locallibrary: + name: local_library_001 + description: automated + publish_info: + published: true + authentication_method: NONE + storage_backings: + - datastore_id: "{{ lookup('vmware.vmware_rest.datastore_moid', '/my_dc/datastore/rw_datastore')\ + \ }}" + type: DATASTORE + state: present + register: ds_lib + +- name: Get the (empty) list of items of the library + vmware.vmware_rest.content_library_item_info: + library_id: '{{ ds_lib.id }}' + register: result + +- name: Create subscribed library + vmware.vmware_rest.content_subscribedlibrary: + name: sub_lib + subscription_info: + subscription_url: '{{ nfs_lib.value.publish_info.publish_url }}' + authentication_method: NONE + automatic_sync_enabled: false + on_demand: true + storage_backings: + - datastore_id: "{{ lookup('vmware.vmware_rest.datastore_moid', '/my_dc/datastore/rw_datastore')\ + \ }}" + type: DATASTORE + register: sub_lib + +- name: Ensure the OVF is here + vmware.vmware_rest.content_library_item_info: + library_id: '{{ sub_lib.id }}' + register: result +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Ensure the OVF is here +value: + description: Ensure the OVF is here + returned: On success + sample: + - cached: 0 + content_version: '2' + creation_time: '2022-06-23T22:38:30.512Z' + description: an OVF example + id: 75e373ac-69d2-48dc-9d26-9caa8a87d5f8 + last_modified_time: '2022-06-23T22:38:30.833Z' + last_sync_time: '2022-06-23T22:38:30.832Z' + library_id: 41bd5c47-e658-4876-bab2-03758f25a3e9 + metadata_version: '1' + name: my_vm + security_compliance: 1 + size: 0 + source_id: e6042f94-40ae-47b8-89cc-a2f668db4a45 + type: ovf + version: '1' + type: list +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"library_item_id": "library_item_id"}}, + "list": {"query": {"library_id": "library_id"}, "body": {}, "path": {}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["library_id"] = {"type": "str"} + argument_spec["library_item_id"] = {"type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_list_and_get_module.j2 +def build_url(params): + if params.get("library_item_id"): + _in_query_parameters = PAYLOAD_FORMAT["get"]["query"].keys() + return ( + ("https://{vcenter_hostname}" "/api/content/library/item/").format(**params) + + params["library_item_id"] + + gen_args(params, _in_query_parameters) + ) + _in_query_parameters = PAYLOAD_FORMAT["list"]["query"].keys() + return ("https://{vcenter_hostname}" "/api/content/library/item").format( + **params + ) + gen_args(params, _in_query_parameters) + + +async def entry_point(module, session): + url = build_url(module.params) + async with session.get(url, **session_timeout(module.params)) as resp: + _json = await resp.json() + + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + + if module.params.get("library_item_id"): + _json["id"] = module.params.get("library_item_id") + elif module.params.get("label"): # TODO extend the list of filter + _json = await exists(module.params, session, url) + elif ( + isinstance(_json["value"], list) + and len(_json["value"]) > 0 + and isinstance(_json["value"][0], str) + ): + # this is a list of id, we fetch the details + full_device_list = await build_full_device_list(session, url, _json) + _json = {"value": [i["value"] for i in full_device_list]} + + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/content_locallibrary.py b/ansible_collections/vmware/vmware_rest/plugins/modules/content_locallibrary.py new file mode 100644 index 00000000..9c229ff4 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/content_locallibrary.py @@ -0,0 +1,1325 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: content_locallibrary +short_description: Creates a new local library. +description: Creates a new local library. +options: + client_token: + description: + - 'A unique token generated on the client for each creation request. The token + should be a universally unique identifier (UUID), for example: C(b8a2a2e3-2314-43cd-a871-6ede0f429751). + This token can be used to guarantee idempotent creation.' + type: str + creation_time: + description: + - The date and time when this library was created. + type: str + description: + description: + - A human-readable description for this library. + type: str + id: + description: + - An identifier which uniquely identifies this C(library_model). + type: str + last_modified_time: + description: + - The date and time when this library was last updated. This field is updated + automatically when the library properties are changed. This field is not affected + by adding, removing, or modifying a library item or its content within the library. + Tagging the library or syncing the subscribed library does not alter this field. + type: str + last_sync_time: + description: + - The date and time when this library was last synchronized. This field applies + only to subscribed libraries. It is updated every time a synchronization is + triggered on the library. The value is not set for a local library. + type: str + library_id: + description: + - Identifier of the local library to delete. Required with I(state=['absent', + 'present', 'publish']) + type: str + name: + description: + - The name of the library. A Library is identified by a human-readable name. Library + names cannot be undefined or an empty string. Names do not have to be unique. + type: str + optimization_info: + description: + - Defines various optimizations and optimization parameters applied to this library. + - 'Valid attributes are:' + - ' - C(optimize_remote_publishing) (bool): If set to C(True) then library would + be optimized for remote publishing. Turn it on if remote publishing is dominant + use case for this library. Remote publishing means here that publisher and subscribers + are not the part of the same C(vcenter) SSO domain. Any optimizations could + be done as result of turning on this optimization during library creation. For + example, library content could be stored in different format but optimizations + are not limited to just storage format. Note, that value of this toggle could + be set only during creation of the library and you would need to migrate your + library in case you need to change this value (optimize the library for different + use case). ([''present''])' + type: dict + publish_info: + description: + - Defines how this library is published so that it can be subscribed to by a remote + subscribed library. The C(publish_info) defines where and how the metadata for + this local library is accessible. A local library is only published publically + if C(publish_info.published) is C(True). + - 'Valid attributes are:' + - ' - C(authentication_method) (str): The C(authentication_method) indicates how + a subscribed library should authenticate to the published library endpoint. + ([''present''])' + - ' - Accepted values:' + - ' - BASIC' + - ' - NONE' + - ' - C(published) (bool): Whether the local library is published. ([''present''])' + - ' - C(publish_url) (str): The URL to which the library metadata is published + by the Content Library Service. This value can be used to set the C(subscription_info.subscriptionurl) + property when creating a subscribed library. ([''present''])' + - ' - C(user_name) (str): The username to require for authentication. ([''present''])' + - ' - C(password) (str): The new password to require for authentication. ([''present''])' + - ' - C(current_password) (str): The current password to verify. This field is + available starting in vSphere 6.7. ([''present''])' + - ' - C(persist_json_enabled) (bool): Whether library and library item metadata + are persisted in the storage backing as JSON files. This flag only applies if + the local library is published. Enabling JSON persistence allows you to synchronize + a subscribed library manually instead of over HTTP. You copy the local library + content and metadata to another storage backing manually and then create a subscribed + library referencing the location of the library JSON file in the C(subscription_info.subscriptionurl). + When the subscribed library''s storage backing matches the subscription URL, + files do not need to be copied to the subscribed library. For a library backed + by a datastore, the library JSON file will be stored at the path contentlib-{library_id}/lib.json + on the datastore. For a library backed by a remote file system, the library + JSON file will be stored at {library_id}/lib.json in the remote file system + path. ([''present''])' + type: dict + server_guid: + description: + - The unique identifier of the vCenter server where the library exists. + type: str + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - absent + - present + - publish + default: present + description: [] + type: str + storage_backings: + description: + - The list of default storage backings which are available for this library. A + storage backing defines a default storage location which can be used to store + files for library items in this library. Some library items, for instance, virtual + machine template items, support files that may be distributed across various + storage backings. One or more item files may or may not be located on the default + storage backing. Multiple default storage locations are not currently supported + but may become supported in future releases. + - 'Valid attributes are:' + - ' - C(type) (str): The C(type) specifies the type of the storage backing. ([''present''])' + - ' - Accepted values:' + - ' - DATASTORE' + - ' - OTHER' + - ' - C(datastore_id) (str): Identifier of the datastore used to store the content + in the library. ([''present''])' + - ' - C(storage_uri) (str): URI identifying the location used to store the content + in the library. The following URI formats are supported: vSphere 6.5 <ul> <li>nfs://server/path?version=4 + (for vCenter Server Appliance only) - Specifies an NFS Version 4 server.</li> + <li>nfs://server/path (for vCenter Server Appliance only) - Specifies an NFS + Version 3 server. The nfs://server:/path format is also supported.</li> <li>smb://server/path + - Specifies an SMB server or Windows share.</li> </ul> vSphere 6.0 Update 1 + <ul> <li>nfs://server:/path (for vCenter Server Appliance only)</li> <li>file://unc-server/path + (for vCenter Server for Windows only)</li> <li>file:///mount/point (for vCenter + Server Appliance only) - Local file URIs are supported only when the path is + a local mount point for an NFS file system. Use of file URIs is strongly discouraged. + Instead, use an NFS URI to specify the remote file system.</li> </ul> vSphere + 6.0 <ul> <li>nfs://server:/path (for vCenter Server Appliance only)</li> <li>file://unc-server/path + (for vCenter Server for Windows only)</li> <li>file:///path - Local file URIs + are supported but strongly discouraged because it may interfere with the performance + of vCenter Server.</li> </ul> ([''present''])' + elements: dict + type: list + subscription_info: + description: + - Defines the subscription behavior for this Library. The C(subscription_info) + defines how this subscribed library synchronizes to a remote source. Setting + the value will determine the remote source to which the library synchronizes, + and how. Changing the subscription will result in synchronizing to a new source. + If the new source differs from the old one, the old library items and data will + be lost. Setting C(subscription_info.automaticSyncEnabled) to false will halt + subscription but will not remove existing cached data. + - 'Valid attributes are:' + - ' - C(authentication_method) (str): Indicate how the subscribed library should + authenticate with the published library endpoint. ([''present''])' + - ' - Accepted values:' + - ' - BASIC' + - ' - NONE' + - ' - C(automatic_sync_enabled) (bool): Whether the library should participate + in automatic library synchronization. In order for automatic synchronization + to happen, the global C(configuration_model.automatic_sync_enabled) option must + also be true. The subscription is still active even when automatic synchronization + is turned off, but synchronization is only activated with an explicit call to + M(vmware.vmware_rest.content_subscribedlibrary) with C(state=sync) or M(vmware.vmware_rest.content_library_item) + with C(state=sync). In other words, manual synchronization is still available + even when automatic synchronization is disabled. ([''present''])' + - ' - C(on_demand) (bool): Indicates whether a library item''s content will be + synchronized only on demand. If this is set to C(True), then the library item''s + metadata will be synchronized but the item''s content (its files) will not be + synchronized. The Content Library Service will synchronize the content upon + request only. This can cause the first use of the content to have a noticeable + delay. Items without synchronized content can be forcefully synchronized in + advance using the M(vmware.vmware_rest.content_library_item) with C(state=sync) + call with C(force_sync_content) set to true. Once content has been synchronized, + the content can removed with the M(vmware.vmware_rest.content_library_item) + with C(state=sync) call. If this value is set to C(False), all content will + be synchronized in advance. ([''present''])' + - ' - C(password) (str): The password to use when authenticating. The password + must be set when using a password-based authentication method; empty strings + are not allowed. ([''present''])' + - ' - C(ssl_thumbprint) (str): An optional SHA-1 hash of the SSL certificate for + the remote endpoint. If this value is defined the SSL certificate will be verified + by comparing it to the SSL thumbprint. The SSL certificate must verify against + the thumbprint. When specified, the standard certificate chain validation behavior + is not used. The certificate chain is validated normally if this value is not + set. ([''present''])' + - ' - C(subscription_url) (str): The URL of the endpoint where the metadata for + the remotely published library is being served. This URL can be the C(publish_info.publish_url) + of the published library (for example, https://server/path/lib.json). If the + source content comes from a published library with C(publish_info.persist_json_enabled), + the subscription URL can be a URL pointing to the library JSON file on a datastore + or remote file system. The supported formats are: vSphere 6.5 <ul> <li>ds:///vmfs/volumes/{uuid}/mylibrary/lib.json + (for datastore)</li> <li>nfs://server/path/mylibrary/lib.json (for NFSv3 server + on vCenter Server Appliance)</li> <li>nfs://server/path/mylibrary/lib.json?version=4 + (for NFSv4 server on vCenter Server Appliance) </li> <li>smb://server/path/mylibrary/lib.json + (for SMB server)</li> </ul> vSphere 6.0 <ul> <li>file://server/mylibrary/lib.json + (for UNC server on vCenter Server for Windows)</li> <li>file:///path/mylibrary/lib.json + (for local file system)</li> </ul> When you specify a DS subscription URL, the + datastore must be on the same vCenter Server as the subscribed library. When + you specify an NFS or SMB subscription URL, the C(storage_backings.storage_uri) + of the subscribed library must be on the same remote file server and should + share a common parent path with the subscription URL. ([''present''])' + - ' - C(user_name) (str): The username to use when authenticating. The username + must be set when using a password-based authentication method. Empty strings + are allowed for usernames. ([''present''])' + - ' - C(source_info) (dict): Information about the source published library. This + field will be set for a subscribed library which is associated with a subscription + of the published library. ([''present''])' + - ' - Accepted keys:' + - ' - source_library (string): Identifier of the published library.' + - ' - subscription (string): Identifier of the subscription associated with + the subscribed library.' + type: dict + subscriptions: + description: + - The list of subscriptions to publish this library to. + - 'Valid attributes are:' + - ' - C(subscription) (str): Identifier of the subscription associated with the + subscribed library. ([''publish''])' + - ' This key is required with [''publish''].' + elements: dict + type: list + type: + choices: + - LOCAL + - SUBSCRIBED + description: + - The C(library_type) defines the type of a Library. The type of a library can + be used to determine which additional services can be performed with a library. + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + version: + description: + - A version number which is updated on metadata changes. This value allows clients + to detect concurrent updates and prevent accidental clobbering of data. This + value represents a number which is incremented every time library properties, + such as name or description, are changed. It is not incremented by changes to + a library item within the library, including adding or removing items. It is + also not affected by tagging the library. + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Build a list of local libraries + vmware.vmware_rest.content_locallibrary_info: + register: result + retries: 100 + delay: 3 + until: result is not failed + +- name: Delete all the local libraries + vmware.vmware_rest.content_locallibrary: + library_id: '{{ item.id }}' + state: absent + with_items: '{{ result.value }}' + +- name: Create a content library pointing on a NFS share + vmware.vmware_rest.content_locallibrary: + name: my_library_on_nfs + description: automated + publish_info: + published: true + authentication_method: NONE + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + state: present + register: nfs_lib + +- name: Create some more content libraries + vmware.vmware_rest.content_locallibrary: + name: my_library_on_nfs_{{ item }} + description: automated + publish_info: + published: true + authentication_method: NONE + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + state: present + with_sequence: 0-10 + +- name: Create a new local content library + vmware.vmware_rest.content_locallibrary: + name: local_library_001 + description: automated + publish_info: + published: true + authentication_method: NONE + storage_backings: + - datastore_id: "{{ lookup('vmware.vmware_rest.datastore_moid', '/my_dc/datastore/rw_datastore')\ + \ }}" + type: DATASTORE + state: present + register: ds_lib + +- name: Create a content library based on a DataStore + vmware.vmware_rest.content_locallibrary: + name: my_library_on_datastore + description: automated + publish_info: + published: true + authentication_method: NONE + storage_backings: + - datastore_id: "{{ lookup('vmware.vmware_rest.datastore_moid', '/my_dc/datastore/local')\ + \ }}" + type: DATASTORE + state: present + register: ds_lib +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Create some more content libraries +msg: + description: Create some more content libraries + returned: On success + sample: All items completed + type: str +results: + description: Create some more content libraries + returned: On success + sample: + - _ansible_item_label: '0' + _ansible_no_log: null + ansible_loop_var: item + changed: 1 + failed: 0 + id: 99517bfa-7f2c-4e01-83e5-ed1bbb13c3e6 + invocation: + module_args: + client_token: null + creation_time: null + description: automated + id: null + last_modified_time: null + last_sync_time: null + library_id: null + name: my_library_on_nfs_0 + optimization_info: null + publish_info: + authentication_method: NONE + published: 1 + server_guid: null + session_timeout: null + state: present + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + subscription_info: null + subscriptions: null + type: null + vcenter_hostname: vcenter.test + vcenter_password: VALUE_SPECIFIED_IN_NO_LOG_PARAMETER + vcenter_rest_log_file: null + vcenter_username: administrator@vsphere.local + vcenter_validate_certs: 0 + version: null + item: '0' + value: + creation_time: '2022-06-23T22:35:20.801Z' + description: automated + id: 99517bfa-7f2c-4e01-83e5-ed1bbb13c3e6 + last_modified_time: '2022-06-23T22:35:20.801Z' + name: my_library_on_nfs_0 + publish_info: + authentication_method: NONE + persist_json_enabled: 0 + publish_url: https://vcenter.test:443/cls/vcsp/lib/99517bfa-7f2c-4e01-83e5-ed1bbb13c3e6/lib.json + published: 1 + user_name: vcsp + server_guid: b138c531-cd80-43f5-842d-657d9ddc98f8 + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + type: LOCAL + version: '2' + - _ansible_item_label: '1' + _ansible_no_log: null + ansible_loop_var: item + changed: 1 + failed: 0 + id: 0926be51-049a-476b-8537-e4b3d0a572a9 + invocation: + module_args: + client_token: null + creation_time: null + description: automated + id: null + last_modified_time: null + last_sync_time: null + library_id: null + name: my_library_on_nfs_1 + optimization_info: null + publish_info: + authentication_method: NONE + published: 1 + server_guid: null + session_timeout: null + state: present + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + subscription_info: null + subscriptions: null + type: null + vcenter_hostname: vcenter.test + vcenter_password: VALUE_SPECIFIED_IN_NO_LOG_PARAMETER + vcenter_rest_log_file: null + vcenter_username: administrator@vsphere.local + vcenter_validate_certs: 0 + version: null + item: '1' + value: + creation_time: '2022-06-23T22:35:21.697Z' + description: automated + id: 0926be51-049a-476b-8537-e4b3d0a572a9 + last_modified_time: '2022-06-23T22:35:21.697Z' + name: my_library_on_nfs_1 + publish_info: + authentication_method: NONE + persist_json_enabled: 0 + publish_url: https://vcenter.test:443/cls/vcsp/lib/0926be51-049a-476b-8537-e4b3d0a572a9/lib.json + published: 1 + user_name: vcsp + server_guid: b138c531-cd80-43f5-842d-657d9ddc98f8 + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + type: LOCAL + version: '2' + - _ansible_item_label: '2' + _ansible_no_log: null + ansible_loop_var: item + changed: 1 + failed: 0 + id: 7c970cd1-1526-4903-8295-64e28ecc6bad + invocation: + module_args: + client_token: null + creation_time: null + description: automated + id: null + last_modified_time: null + last_sync_time: null + library_id: null + name: my_library_on_nfs_2 + optimization_info: null + publish_info: + authentication_method: NONE + published: 1 + server_guid: null + session_timeout: null + state: present + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + subscription_info: null + subscriptions: null + type: null + vcenter_hostname: vcenter.test + vcenter_password: VALUE_SPECIFIED_IN_NO_LOG_PARAMETER + vcenter_rest_log_file: null + vcenter_username: administrator@vsphere.local + vcenter_validate_certs: 0 + version: null + item: '2' + value: + creation_time: '2022-06-23T22:35:22.620Z' + description: automated + id: 7c970cd1-1526-4903-8295-64e28ecc6bad + last_modified_time: '2022-06-23T22:35:22.620Z' + name: my_library_on_nfs_2 + publish_info: + authentication_method: NONE + persist_json_enabled: 0 + publish_url: https://vcenter.test:443/cls/vcsp/lib/7c970cd1-1526-4903-8295-64e28ecc6bad/lib.json + published: 1 + user_name: vcsp + server_guid: b138c531-cd80-43f5-842d-657d9ddc98f8 + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + type: LOCAL + version: '2' + - _ansible_item_label: '3' + _ansible_no_log: null + ansible_loop_var: item + changed: 1 + failed: 0 + id: 53a679e5-a7dc-4d50-ad6e-759f697b6143 + invocation: + module_args: + client_token: null + creation_time: null + description: automated + id: null + last_modified_time: null + last_sync_time: null + library_id: null + name: my_library_on_nfs_3 + optimization_info: null + publish_info: + authentication_method: NONE + published: 1 + server_guid: null + session_timeout: null + state: present + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + subscription_info: null + subscriptions: null + type: null + vcenter_hostname: vcenter.test + vcenter_password: VALUE_SPECIFIED_IN_NO_LOG_PARAMETER + vcenter_rest_log_file: null + vcenter_username: administrator@vsphere.local + vcenter_validate_certs: 0 + version: null + item: '3' + value: + creation_time: '2022-06-23T22:35:23.573Z' + description: automated + id: 53a679e5-a7dc-4d50-ad6e-759f697b6143 + last_modified_time: '2022-06-23T22:35:23.573Z' + name: my_library_on_nfs_3 + publish_info: + authentication_method: NONE + persist_json_enabled: 0 + publish_url: https://vcenter.test:443/cls/vcsp/lib/53a679e5-a7dc-4d50-ad6e-759f697b6143/lib.json + published: 1 + user_name: vcsp + server_guid: b138c531-cd80-43f5-842d-657d9ddc98f8 + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + type: LOCAL + version: '2' + - _ansible_item_label: '4' + _ansible_no_log: null + ansible_loop_var: item + changed: 1 + failed: 0 + id: b8380086-243a-400d-9a9f-8259f83d0148 + invocation: + module_args: + client_token: null + creation_time: null + description: automated + id: null + last_modified_time: null + last_sync_time: null + library_id: null + name: my_library_on_nfs_4 + optimization_info: null + publish_info: + authentication_method: NONE + published: 1 + server_guid: null + session_timeout: null + state: present + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + subscription_info: null + subscriptions: null + type: null + vcenter_hostname: vcenter.test + vcenter_password: VALUE_SPECIFIED_IN_NO_LOG_PARAMETER + vcenter_rest_log_file: null + vcenter_username: administrator@vsphere.local + vcenter_validate_certs: 0 + version: null + item: '4' + value: + creation_time: '2022-06-23T22:35:24.545Z' + description: automated + id: b8380086-243a-400d-9a9f-8259f83d0148 + last_modified_time: '2022-06-23T22:35:24.545Z' + name: my_library_on_nfs_4 + publish_info: + authentication_method: NONE + persist_json_enabled: 0 + publish_url: https://vcenter.test:443/cls/vcsp/lib/b8380086-243a-400d-9a9f-8259f83d0148/lib.json + published: 1 + user_name: vcsp + server_guid: b138c531-cd80-43f5-842d-657d9ddc98f8 + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + type: LOCAL + version: '2' + - _ansible_item_label: '5' + _ansible_no_log: null + ansible_loop_var: item + changed: 1 + failed: 0 + id: 1bad9ede-140b-4c62-bc6b-df506eb27292 + invocation: + module_args: + client_token: null + creation_time: null + description: automated + id: null + last_modified_time: null + last_sync_time: null + library_id: null + name: my_library_on_nfs_5 + optimization_info: null + publish_info: + authentication_method: NONE + published: 1 + server_guid: null + session_timeout: null + state: present + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + subscription_info: null + subscriptions: null + type: null + vcenter_hostname: vcenter.test + vcenter_password: VALUE_SPECIFIED_IN_NO_LOG_PARAMETER + vcenter_rest_log_file: null + vcenter_username: administrator@vsphere.local + vcenter_validate_certs: 0 + version: null + item: '5' + value: + creation_time: '2022-06-23T22:35:25.464Z' + description: automated + id: 1bad9ede-140b-4c62-bc6b-df506eb27292 + last_modified_time: '2022-06-23T22:35:25.464Z' + name: my_library_on_nfs_5 + publish_info: + authentication_method: NONE + persist_json_enabled: 0 + publish_url: https://vcenter.test:443/cls/vcsp/lib/1bad9ede-140b-4c62-bc6b-df506eb27292/lib.json + published: 1 + user_name: vcsp + server_guid: b138c531-cd80-43f5-842d-657d9ddc98f8 + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + type: LOCAL + version: '2' + - _ansible_item_label: '6' + _ansible_no_log: null + ansible_loop_var: item + changed: 1 + failed: 0 + id: a2d5c986-e376-4648-95f1-661efff3f851 + invocation: + module_args: + client_token: null + creation_time: null + description: automated + id: null + last_modified_time: null + last_sync_time: null + library_id: null + name: my_library_on_nfs_6 + optimization_info: null + publish_info: + authentication_method: NONE + published: 1 + server_guid: null + session_timeout: null + state: present + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + subscription_info: null + subscriptions: null + type: null + vcenter_hostname: vcenter.test + vcenter_password: VALUE_SPECIFIED_IN_NO_LOG_PARAMETER + vcenter_rest_log_file: null + vcenter_username: administrator@vsphere.local + vcenter_validate_certs: 0 + version: null + item: '6' + value: + creation_time: '2022-06-23T22:35:26.405Z' + description: automated + id: a2d5c986-e376-4648-95f1-661efff3f851 + last_modified_time: '2022-06-23T22:35:26.405Z' + name: my_library_on_nfs_6 + publish_info: + authentication_method: NONE + persist_json_enabled: 0 + publish_url: https://vcenter.test:443/cls/vcsp/lib/a2d5c986-e376-4648-95f1-661efff3f851/lib.json + published: 1 + user_name: vcsp + server_guid: b138c531-cd80-43f5-842d-657d9ddc98f8 + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + type: LOCAL + version: '2' + - _ansible_item_label: '7' + _ansible_no_log: null + ansible_loop_var: item + changed: 1 + failed: 0 + id: 45f33229-1232-4d7d-9cb3-69d7888bbb07 + invocation: + module_args: + client_token: null + creation_time: null + description: automated + id: null + last_modified_time: null + last_sync_time: null + library_id: null + name: my_library_on_nfs_7 + optimization_info: null + publish_info: + authentication_method: NONE + published: 1 + server_guid: null + session_timeout: null + state: present + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + subscription_info: null + subscriptions: null + type: null + vcenter_hostname: vcenter.test + vcenter_password: VALUE_SPECIFIED_IN_NO_LOG_PARAMETER + vcenter_rest_log_file: null + vcenter_username: administrator@vsphere.local + vcenter_validate_certs: 0 + version: null + item: '7' + value: + creation_time: '2022-06-23T22:35:27.357Z' + description: automated + id: 45f33229-1232-4d7d-9cb3-69d7888bbb07 + last_modified_time: '2022-06-23T22:35:27.357Z' + name: my_library_on_nfs_7 + publish_info: + authentication_method: NONE + persist_json_enabled: 0 + publish_url: https://vcenter.test:443/cls/vcsp/lib/45f33229-1232-4d7d-9cb3-69d7888bbb07/lib.json + published: 1 + user_name: vcsp + server_guid: b138c531-cd80-43f5-842d-657d9ddc98f8 + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + type: LOCAL + version: '2' + - _ansible_item_label: '8' + _ansible_no_log: null + ansible_loop_var: item + changed: 1 + failed: 0 + id: 8723c432-c706-4dfb-9f56-dadd3b95f299 + invocation: + module_args: + client_token: null + creation_time: null + description: automated + id: null + last_modified_time: null + last_sync_time: null + library_id: null + name: my_library_on_nfs_8 + optimization_info: null + publish_info: + authentication_method: NONE + published: 1 + server_guid: null + session_timeout: null + state: present + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + subscription_info: null + subscriptions: null + type: null + vcenter_hostname: vcenter.test + vcenter_password: VALUE_SPECIFIED_IN_NO_LOG_PARAMETER + vcenter_rest_log_file: null + vcenter_username: administrator@vsphere.local + vcenter_validate_certs: 0 + version: null + item: '8' + value: + creation_time: '2022-06-23T22:35:28.377Z' + description: automated + id: 8723c432-c706-4dfb-9f56-dadd3b95f299 + last_modified_time: '2022-06-23T22:35:28.377Z' + name: my_library_on_nfs_8 + publish_info: + authentication_method: NONE + persist_json_enabled: 0 + publish_url: https://vcenter.test:443/cls/vcsp/lib/8723c432-c706-4dfb-9f56-dadd3b95f299/lib.json + published: 1 + user_name: vcsp + server_guid: b138c531-cd80-43f5-842d-657d9ddc98f8 + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + type: LOCAL + version: '2' + - _ansible_item_label: '9' + _ansible_no_log: null + ansible_loop_var: item + changed: 1 + failed: 0 + id: bae6e392-12e7-4868-b18f-f487307bf752 + invocation: + module_args: + client_token: null + creation_time: null + description: automated + id: null + last_modified_time: null + last_sync_time: null + library_id: null + name: my_library_on_nfs_9 + optimization_info: null + publish_info: + authentication_method: NONE + published: 1 + server_guid: null + session_timeout: null + state: present + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + subscription_info: null + subscriptions: null + type: null + vcenter_hostname: vcenter.test + vcenter_password: VALUE_SPECIFIED_IN_NO_LOG_PARAMETER + vcenter_rest_log_file: null + vcenter_username: administrator@vsphere.local + vcenter_validate_certs: 0 + version: null + item: '9' + value: + creation_time: '2022-06-23T22:35:29.397Z' + description: automated + id: bae6e392-12e7-4868-b18f-f487307bf752 + last_modified_time: '2022-06-23T22:35:29.397Z' + name: my_library_on_nfs_9 + publish_info: + authentication_method: NONE + persist_json_enabled: 0 + publish_url: https://vcenter.test:443/cls/vcsp/lib/bae6e392-12e7-4868-b18f-f487307bf752/lib.json + published: 1 + user_name: vcsp + server_guid: b138c531-cd80-43f5-842d-657d9ddc98f8 + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + type: LOCAL + version: '2' + - _ansible_item_label: '10' + _ansible_no_log: null + ansible_loop_var: item + changed: 1 + failed: 0 + id: 61ea41a8-9443-4a64-9181-f9a046012197 + invocation: + module_args: + client_token: null + creation_time: null + description: automated + id: null + last_modified_time: null + last_sync_time: null + library_id: null + name: my_library_on_nfs_10 + optimization_info: null + publish_info: + authentication_method: NONE + published: 1 + server_guid: null + session_timeout: null + state: present + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + subscription_info: null + subscriptions: null + type: null + vcenter_hostname: vcenter.test + vcenter_password: VALUE_SPECIFIED_IN_NO_LOG_PARAMETER + vcenter_rest_log_file: null + vcenter_username: administrator@vsphere.local + vcenter_validate_certs: 0 + version: null + item: '10' + value: + creation_time: '2022-06-23T22:35:30.412Z' + description: automated + id: 61ea41a8-9443-4a64-9181-f9a046012197 + last_modified_time: '2022-06-23T22:35:30.412Z' + name: my_library_on_nfs_10 + publish_info: + authentication_method: NONE + persist_json_enabled: 0 + publish_url: https://vcenter.test:443/cls/vcsp/lib/61ea41a8-9443-4a64-9181-f9a046012197/lib.json + published: 1 + user_name: vcsp + server_guid: b138c531-cd80-43f5-842d-657d9ddc98f8 + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + type: LOCAL + version: '2' + type: list +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "delete": {"query": {}, "body": {}, "path": {"library_id": "library_id"}}, + "create": { + "query": {"client_token": "client_token"}, + "body": { + "creation_time": "creation_time", + "description": "description", + "id": "id", + "last_modified_time": "last_modified_time", + "last_sync_time": "last_sync_time", + "name": "name", + "optimization_info": "optimization_info", + "publish_info": "publish_info", + "server_guid": "server_guid", + "storage_backings": "storage_backings", + "subscription_info": "subscription_info", + "type": "type", + "version": "version", + }, + "path": {}, + }, + "update": { + "query": {}, + "body": { + "creation_time": "creation_time", + "description": "description", + "id": "id", + "last_modified_time": "last_modified_time", + "last_sync_time": "last_sync_time", + "name": "name", + "optimization_info": "optimization_info", + "publish_info": "publish_info", + "server_guid": "server_guid", + "storage_backings": "storage_backings", + "subscription_info": "subscription_info", + "type": "type", + "version": "version", + }, + "path": {"library_id": "library_id"}, + }, + "publish": { + "query": {}, + "body": {"subscriptions": "subscriptions"}, + "path": {"library_id": "library_id"}, + }, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["client_token"] = {"no_log": True, "type": "str"} + argument_spec["creation_time"] = {"type": "str"} + argument_spec["description"] = {"type": "str"} + argument_spec["id"] = {"type": "str"} + argument_spec["last_modified_time"] = {"type": "str"} + argument_spec["last_sync_time"] = {"type": "str"} + argument_spec["library_id"] = {"type": "str"} + argument_spec["name"] = {"type": "str"} + argument_spec["optimization_info"] = {"type": "dict"} + argument_spec["publish_info"] = {"type": "dict"} + argument_spec["server_guid"] = {"type": "str"} + argument_spec["state"] = { + "type": "str", + "choices": ["absent", "present", "publish"], + "default": "present", + } + argument_spec["storage_backings"] = {"type": "list", "elements": "dict"} + argument_spec["subscription_info"] = {"type": "dict"} + argument_spec["subscriptions"] = {"type": "list", "elements": "dict"} + argument_spec["type"] = {"type": "str", "choices": ["LOCAL", "SUBSCRIBED"]} + argument_spec["version"] = {"type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/content/local-library").format(**params) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _create(params, session): + + lookup_url = per_id_url = build_url(params) + uniquity_keys = ["name"] + comp_func = None + + _json = None + + if params["library_id"]: + _json = await get_device_info(session, build_url(params), params["library_id"]) + + if not _json and (uniquity_keys or comp_func): + _json = await exists( + params, + session, + url=lookup_url, + uniquity_keys=uniquity_keys, + per_id_url=per_id_url, + comp_func=comp_func, + ) + + if _json: + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + if "_update" in globals(): + params["library_id"] = _json["id"] + return await globals()["_update"](params, session) + + return await update_changed_flag(_json, 200, "get") + + payload = prepare_payload(params, PAYLOAD_FORMAT["create"]) + _url = ("https://{vcenter_hostname}" "/api/content/local-library").format(**params) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + if resp.status == 500: + text = await resp.text() + raise EmbeddedModuleFailure( + f"Request has failed: status={resp.status}, {text}" + ) + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + + if (resp.status in [200, 201]) and "error" not in _json: + if isinstance(_json, str): # 7.0.2 and greater + _id = _json # TODO: fetch the object + elif isinstance(_json, dict) and "value" not in _json: + _id = list(_json["value"].values())[0] + elif isinstance(_json, dict) and "value" in _json: + _id = _json["value"] + _json_device_info = await get_device_info(session, _url, _id) + if _json_device_info: + _json = _json_device_info + + return await update_changed_flag(_json, resp.status, "create") + + +async def _delete(params, session): + _in_query_parameters = PAYLOAD_FORMAT["delete"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["delete"]) + subdevice_type = get_subdevice_type("/api/content/local-library/{library_id}") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" "/api/content/local-library/{library_id}" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.delete(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "delete") + + +async def _publish(params, session): + _in_query_parameters = PAYLOAD_FORMAT["publish"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["publish"]) + subdevice_type = get_subdevice_type( + "/api/content/local-library/{library_id}?action=publish" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/content/local-library/{library_id}?action=publish" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "publish") + + +async def _update(params, session): + payload = prepare_payload(params, PAYLOAD_FORMAT["update"]) + _url = ( + "https://{vcenter_hostname}" "/api/content/local-library/{library_id}" + ).format(**params) + async with session.get(_url, **session_timeout(params)) as resp: + _json = await resp.json() + if "value" in _json: + value = _json["value"] + else: # 7.0.2 and greater + value = _json + for k, v in value.items(): + if k in payload: + if isinstance(payload[k], dict) and isinstance(v, dict): + to_delete = True + for _k in list(payload[k].keys()): + if payload[k][_k] != v.get(_k): + to_delete = False + if to_delete: + del payload[k] + elif payload[k] == v: + del payload[k] + elif payload[k] == {}: + del payload[k] + + if payload == {} or payload == {"spec": {}}: + # Nothing has changed + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + _json["id"] = params.get("library_id") + return await update_changed_flag(_json, resp.status, "get") + async with session.patch(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # e.g: content_configuration + if not _json and resp.status == 204: + async with session.get(_url, **session_timeout(params)) as resp_get: + _json_get = await resp_get.json() + if _json_get: + _json = _json_get + + _json["id"] = params.get("library_id") + return await update_changed_flag(_json, resp.status, "update") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/content_locallibrary_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/content_locallibrary_info.py new file mode 100644 index 00000000..2df54d1f --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/content_locallibrary_info.py @@ -0,0 +1,472 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: content_locallibrary_info +short_description: Returns a given local library. +description: Returns a given local library. +options: + library_id: + description: + - Identifier of the local library to return. Required with I(state=['get']) + type: str + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Build a list of local libraries + vmware.vmware_rest.content_locallibrary_info: + register: result + retries: 100 + delay: 3 + until: result is not failed + +- name: List Local Content Library + vmware.vmware_rest.content_locallibrary_info: + register: my_content_library + +- name: List all Local Content Library + vmware.vmware_rest.content_locallibrary_info: + register: all_content_libraries + +- name: Create a new local content library + vmware.vmware_rest.content_locallibrary: + name: local_library_001 + description: automated + publish_info: + published: true + authentication_method: NONE + storage_backings: + - datastore_id: "{{ lookup('vmware.vmware_rest.datastore_moid', '/my_dc/datastore/rw_datastore')\ + \ }}" + type: DATASTORE + state: present + register: ds_lib + +- name: Retrieve the local content library information based upon id check mode + vmware.vmware_rest.content_locallibrary_info: + library_id: '{{ ds_lib.id }}' + register: result + check_mode: true +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: List all Local Content Library +value: + description: List all Local Content Library + returned: On success + sample: + - creation_time: '2022-06-23T22:35:23.573Z' + description: automated + id: 53a679e5-a7dc-4d50-ad6e-759f697b6143 + last_modified_time: '2022-06-23T22:35:23.573Z' + name: my_library_on_nfs_3 + publish_info: + authentication_method: NONE + persist_json_enabled: 0 + publish_url: https://vcenter.test:443/cls/vcsp/lib/53a679e5-a7dc-4d50-ad6e-759f697b6143/lib.json + published: 1 + user_name: vcsp + server_guid: b138c531-cd80-43f5-842d-657d9ddc98f8 + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + type: LOCAL + version: '2' + - creation_time: '2022-06-23T22:35:24.545Z' + description: automated + id: b8380086-243a-400d-9a9f-8259f83d0148 + last_modified_time: '2022-06-23T22:35:24.545Z' + name: my_library_on_nfs_4 + publish_info: + authentication_method: NONE + persist_json_enabled: 0 + publish_url: https://vcenter.test:443/cls/vcsp/lib/b8380086-243a-400d-9a9f-8259f83d0148/lib.json + published: 1 + user_name: vcsp + server_guid: b138c531-cd80-43f5-842d-657d9ddc98f8 + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + type: LOCAL + version: '2' + - creation_time: '2022-06-23T22:35:25.464Z' + description: automated + id: 1bad9ede-140b-4c62-bc6b-df506eb27292 + last_modified_time: '2022-06-23T22:35:25.464Z' + name: my_library_on_nfs_5 + publish_info: + authentication_method: NONE + persist_json_enabled: 0 + publish_url: https://vcenter.test:443/cls/vcsp/lib/1bad9ede-140b-4c62-bc6b-df506eb27292/lib.json + published: 1 + user_name: vcsp + server_guid: b138c531-cd80-43f5-842d-657d9ddc98f8 + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + type: LOCAL + version: '2' + - creation_time: '2022-06-23T22:35:26.405Z' + description: automated + id: a2d5c986-e376-4648-95f1-661efff3f851 + last_modified_time: '2022-06-23T22:35:26.405Z' + name: my_library_on_nfs_6 + publish_info: + authentication_method: NONE + persist_json_enabled: 0 + publish_url: https://vcenter.test:443/cls/vcsp/lib/a2d5c986-e376-4648-95f1-661efff3f851/lib.json + published: 1 + user_name: vcsp + server_guid: b138c531-cd80-43f5-842d-657d9ddc98f8 + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + type: LOCAL + version: '2' + - creation_time: '2022-06-23T22:35:27.357Z' + description: automated + id: 45f33229-1232-4d7d-9cb3-69d7888bbb07 + last_modified_time: '2022-06-23T22:35:27.357Z' + name: my_library_on_nfs_7 + publish_info: + authentication_method: NONE + persist_json_enabled: 0 + publish_url: https://vcenter.test:443/cls/vcsp/lib/45f33229-1232-4d7d-9cb3-69d7888bbb07/lib.json + published: 1 + user_name: vcsp + server_guid: b138c531-cd80-43f5-842d-657d9ddc98f8 + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + type: LOCAL + version: '2' + - creation_time: '2022-06-23T22:35:28.377Z' + description: automated + id: 8723c432-c706-4dfb-9f56-dadd3b95f299 + last_modified_time: '2022-06-23T22:35:28.377Z' + name: my_library_on_nfs_8 + publish_info: + authentication_method: NONE + persist_json_enabled: 0 + publish_url: https://vcenter.test:443/cls/vcsp/lib/8723c432-c706-4dfb-9f56-dadd3b95f299/lib.json + published: 1 + user_name: vcsp + server_guid: b138c531-cd80-43f5-842d-657d9ddc98f8 + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + type: LOCAL + version: '2' + - creation_time: '2022-06-23T22:35:29.397Z' + description: automated + id: bae6e392-12e7-4868-b18f-f487307bf752 + last_modified_time: '2022-06-23T22:35:29.397Z' + name: my_library_on_nfs_9 + publish_info: + authentication_method: NONE + persist_json_enabled: 0 + publish_url: https://vcenter.test:443/cls/vcsp/lib/bae6e392-12e7-4868-b18f-f487307bf752/lib.json + published: 1 + user_name: vcsp + server_guid: b138c531-cd80-43f5-842d-657d9ddc98f8 + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + type: LOCAL + version: '2' + - creation_time: '2022-06-23T22:35:30.412Z' + description: automated + id: 61ea41a8-9443-4a64-9181-f9a046012197 + last_modified_time: '2022-06-23T22:35:30.412Z' + name: my_library_on_nfs_10 + publish_info: + authentication_method: NONE + persist_json_enabled: 0 + publish_url: https://vcenter.test:443/cls/vcsp/lib/61ea41a8-9443-4a64-9181-f9a046012197/lib.json + published: 1 + user_name: vcsp + server_guid: b138c531-cd80-43f5-842d-657d9ddc98f8 + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + type: LOCAL + version: '2' + - creation_time: '2022-06-23T22:35:19.438Z' + description: automated + id: c9b8f7da-d5ac-4076-86b9-39ee107d7da3 + last_modified_time: '2022-06-23T22:35:19.438Z' + name: my_library_on_nfs + publish_info: + authentication_method: NONE + persist_json_enabled: 0 + publish_url: https://vcenter.test:443/cls/vcsp/lib/c9b8f7da-d5ac-4076-86b9-39ee107d7da3/lib.json + published: 1 + user_name: vcsp + server_guid: b138c531-cd80-43f5-842d-657d9ddc98f8 + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + type: LOCAL + version: '2' + - creation_time: '2022-06-23T22:35:20.801Z' + description: automated + id: 99517bfa-7f2c-4e01-83e5-ed1bbb13c3e6 + last_modified_time: '2022-06-23T22:35:20.801Z' + name: my_library_on_nfs_0 + publish_info: + authentication_method: NONE + persist_json_enabled: 0 + publish_url: https://vcenter.test:443/cls/vcsp/lib/99517bfa-7f2c-4e01-83e5-ed1bbb13c3e6/lib.json + published: 1 + user_name: vcsp + server_guid: b138c531-cd80-43f5-842d-657d9ddc98f8 + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + type: LOCAL + version: '2' + - creation_time: '2022-06-23T22:35:21.697Z' + description: automated + id: 0926be51-049a-476b-8537-e4b3d0a572a9 + last_modified_time: '2022-06-23T22:35:21.697Z' + name: my_library_on_nfs_1 + publish_info: + authentication_method: NONE + persist_json_enabled: 0 + publish_url: https://vcenter.test:443/cls/vcsp/lib/0926be51-049a-476b-8537-e4b3d0a572a9/lib.json + published: 1 + user_name: vcsp + server_guid: b138c531-cd80-43f5-842d-657d9ddc98f8 + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + type: LOCAL + version: '2' + - creation_time: '2022-06-23T22:35:22.620Z' + description: automated + id: 7c970cd1-1526-4903-8295-64e28ecc6bad + last_modified_time: '2022-06-23T22:35:22.620Z' + name: my_library_on_nfs_2 + publish_info: + authentication_method: NONE + persist_json_enabled: 0 + publish_url: https://vcenter.test:443/cls/vcsp/lib/7c970cd1-1526-4903-8295-64e28ecc6bad/lib.json + published: 1 + user_name: vcsp + server_guid: b138c531-cd80-43f5-842d-657d9ddc98f8 + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + type: LOCAL + version: '2' + type: list +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"library_id": "library_id"}}, + "list": {"query": {}, "body": {}, "path": {}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["library_id"] = {"type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_list_and_get_module.j2 +def build_url(params): + if params.get("library_id"): + _in_query_parameters = PAYLOAD_FORMAT["get"]["query"].keys() + return ( + ("https://{vcenter_hostname}" "/api/content/local-library/").format( + **params + ) + + params["library_id"] + + gen_args(params, _in_query_parameters) + ) + _in_query_parameters = PAYLOAD_FORMAT["list"]["query"].keys() + return ("https://{vcenter_hostname}" "/api/content/local-library").format( + **params + ) + gen_args(params, _in_query_parameters) + + +async def entry_point(module, session): + url = build_url(module.params) + async with session.get(url, **session_timeout(module.params)) as resp: + _json = await resp.json() + + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + + if module.params.get("library_id"): + _json["id"] = module.params.get("library_id") + elif module.params.get("label"): # TODO extend the list of filter + _json = await exists(module.params, session, url) + elif ( + isinstance(_json["value"], list) + and len(_json["value"]) > 0 + and isinstance(_json["value"][0], str) + ): + # this is a list of id, we fetch the details + full_device_list = await build_full_device_list(session, url, _json) + _json = {"value": [i["value"] for i in full_device_list]} + + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/content_subscribedlibrary.py b/ansible_collections/vmware/vmware_rest/plugins/modules/content_subscribedlibrary.py new file mode 100644 index 00000000..72082a3d --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/content_subscribedlibrary.py @@ -0,0 +1,846 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: content_subscribedlibrary +short_description: Creates a new subscribed library +description: Creates a new subscribed library. <p> Once created, the subscribed library + will be empty. If the {@link LibraryModel#subscriptionInfo} property is set, the + Content Library Service will attempt to synchronize to the remote source. This is + an asynchronous operation so the content of the published library may not immediately + appear. +options: + client_token: + description: + - 'Unique token generated on the client for each creation request. The token should + be a universally unique identifier (UUID), for example: C(b8a2a2e3-2314-43cd-a871-6ede0f429751). + This token can be used to guarantee idempotent creation.' + type: str + creation_time: + description: + - The date and time when this library was created. + type: str + description: + description: + - A human-readable description for this library. + type: str + id: + description: + - An identifier which uniquely identifies this C(library_model). + type: str + last_modified_time: + description: + - The date and time when this library was last updated. This field is updated + automatically when the library properties are changed. This field is not affected + by adding, removing, or modifying a library item or its content within the library. + Tagging the library or syncing the subscribed library does not alter this field. + type: str + last_sync_time: + description: + - The date and time when this library was last synchronized. This field applies + only to subscribed libraries. It is updated every time a synchronization is + triggered on the library. The value is not set for a local library. + type: str + library_id: + description: + - Identifier of the subscribed library whose content should be evicted. Required + with I(state=['absent', 'evict', 'present', 'sync']) + type: str + name: + description: + - The name of the library. A Library is identified by a human-readable name. Library + names cannot be undefined or an empty string. Names do not have to be unique. + type: str + optimization_info: + description: + - Defines various optimizations and optimization parameters applied to this library. + - 'Valid attributes are:' + - ' - C(optimize_remote_publishing) (bool): If set to C(True) then library would + be optimized for remote publishing. Turn it on if remote publishing is dominant + use case for this library. Remote publishing means here that publisher and subscribers + are not the part of the same C(vcenter) SSO domain. Any optimizations could + be done as result of turning on this optimization during library creation. For + example, library content could be stored in different format but optimizations + are not limited to just storage format. Note, that value of this toggle could + be set only during creation of the library and you would need to migrate your + library in case you need to change this value (optimize the library for different + use case). ([''present''])' + type: dict + publish_info: + description: + - Defines how this library is published so that it can be subscribed to by a remote + subscribed library. The C(publish_info) defines where and how the metadata for + this local library is accessible. A local library is only published publically + if C(publish_info.published) is C(True). + - 'Valid attributes are:' + - ' - C(authentication_method) (str): The C(authentication_method) indicates how + a subscribed library should authenticate to the published library endpoint. + ([''present''])' + - ' - Accepted values:' + - ' - BASIC' + - ' - NONE' + - ' - C(published) (bool): Whether the local library is published. ([''present''])' + - ' - C(publish_url) (str): The URL to which the library metadata is published + by the Content Library Service. This value can be used to set the C(subscription_info.subscriptionurl) + property when creating a subscribed library. ([''present''])' + - ' - C(user_name) (str): The username to require for authentication. ([''present''])' + - ' - C(password) (str): The new password to require for authentication. ([''present''])' + - ' - C(current_password) (str): The current password to verify. This field is + available starting in vSphere 6.7. ([''present''])' + - ' - C(persist_json_enabled) (bool): Whether library and library item metadata + are persisted in the storage backing as JSON files. This flag only applies if + the local library is published. Enabling JSON persistence allows you to synchronize + a subscribed library manually instead of over HTTP. You copy the local library + content and metadata to another storage backing manually and then create a subscribed + library referencing the location of the library JSON file in the C(subscription_info.subscriptionurl). + When the subscribed library''s storage backing matches the subscription URL, + files do not need to be copied to the subscribed library. For a library backed + by a datastore, the library JSON file will be stored at the path contentlib-{library_id}/lib.json + on the datastore. For a library backed by a remote file system, the library + JSON file will be stored at {library_id}/lib.json in the remote file system + path. ([''present''])' + type: dict + server_guid: + description: + - The unique identifier of the vCenter server where the library exists. + type: str + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - absent + - evict + - present + - probe + - sync + default: present + description: [] + type: str + storage_backings: + description: + - The list of default storage backings which are available for this library. A + storage backing defines a default storage location which can be used to store + files for library items in this library. Some library items, for instance, virtual + machine template items, support files that may be distributed across various + storage backings. One or more item files may or may not be located on the default + storage backing. Multiple default storage locations are not currently supported + but may become supported in future releases. + - 'Valid attributes are:' + - ' - C(type) (str): The C(type) specifies the type of the storage backing. ([''present''])' + - ' - Accepted values:' + - ' - DATASTORE' + - ' - OTHER' + - ' - C(datastore_id) (str): Identifier of the datastore used to store the content + in the library. ([''present''])' + - ' - C(storage_uri) (str): URI identifying the location used to store the content + in the library. The following URI formats are supported: vSphere 6.5 <ul> <li>nfs://server/path?version=4 + (for vCenter Server Appliance only) - Specifies an NFS Version 4 server.</li> + <li>nfs://server/path (for vCenter Server Appliance only) - Specifies an NFS + Version 3 server. The nfs://server:/path format is also supported.</li> <li>smb://server/path + - Specifies an SMB server or Windows share.</li> </ul> vSphere 6.0 Update 1 + <ul> <li>nfs://server:/path (for vCenter Server Appliance only)</li> <li>file://unc-server/path + (for vCenter Server for Windows only)</li> <li>file:///mount/point (for vCenter + Server Appliance only) - Local file URIs are supported only when the path is + a local mount point for an NFS file system. Use of file URIs is strongly discouraged. + Instead, use an NFS URI to specify the remote file system.</li> </ul> vSphere + 6.0 <ul> <li>nfs://server:/path (for vCenter Server Appliance only)</li> <li>file://unc-server/path + (for vCenter Server for Windows only)</li> <li>file:///path - Local file URIs + are supported but strongly discouraged because it may interfere with the performance + of vCenter Server.</li> </ul> ([''present''])' + elements: dict + type: list + subscription_info: + description: + - Defines the subscription behavior for this Library. The C(subscription_info) + defines how this subscribed library synchronizes to a remote source. Setting + the value will determine the remote source to which the library synchronizes, + and how. Changing the subscription will result in synchronizing to a new source. + If the new source differs from the old one, the old library items and data will + be lost. Setting C(subscription_info.automaticSyncEnabled) to false will halt + subscription but will not remove existing cached data. + - 'Valid attributes are:' + - ' - C(authentication_method) (str): Indicate how the subscribed library should + authenticate with the published library endpoint. ([''present'', ''probe''])' + - ' - Accepted values:' + - ' - BASIC' + - ' - NONE' + - ' - C(automatic_sync_enabled) (bool): Whether the library should participate + in automatic library synchronization. In order for automatic synchronization + to happen, the global C(configuration_model.automatic_sync_enabled) option must + also be true. The subscription is still active even when automatic synchronization + is turned off, but synchronization is only activated with an explicit call to + M(vmware.vmware_rest.content_subscribedlibrary) with C(state=sync) or M(vmware.vmware_rest.content_library_item) + with C(state=sync). In other words, manual synchronization is still available + even when automatic synchronization is disabled. ([''present'', ''probe''])' + - ' - C(on_demand) (bool): Indicates whether a library item''s content will be + synchronized only on demand. If this is set to C(True), then the library item''s + metadata will be synchronized but the item''s content (its files) will not be + synchronized. The Content Library Service will synchronize the content upon + request only. This can cause the first use of the content to have a noticeable + delay. Items without synchronized content can be forcefully synchronized in + advance using the M(vmware.vmware_rest.content_library_item) with C(state=sync) + call with C(force_sync_content) set to true. Once content has been synchronized, + the content can removed with the M(vmware.vmware_rest.content_library_item) + with C(state=sync) call. If this value is set to C(False), all content will + be synchronized in advance. ([''present'', ''probe''])' + - ' - C(password) (str): The password to use when authenticating. The password + must be set when using a password-based authentication method; empty strings + are not allowed. ([''present'', ''probe''])' + - ' - C(ssl_thumbprint) (str): An optional SHA-1 hash of the SSL certificate for + the remote endpoint. If this value is defined the SSL certificate will be verified + by comparing it to the SSL thumbprint. The SSL certificate must verify against + the thumbprint. When specified, the standard certificate chain validation behavior + is not used. The certificate chain is validated normally if this value is not + set. ([''present'', ''probe''])' + - ' - C(subscription_url) (str): The URL of the endpoint where the metadata for + the remotely published library is being served. This URL can be the C(publish_info.publish_url) + of the published library (for example, https://server/path/lib.json). If the + source content comes from a published library with C(publish_info.persist_json_enabled), + the subscription URL can be a URL pointing to the library JSON file on a datastore + or remote file system. The supported formats are: vSphere 6.5 <ul> <li>ds:///vmfs/volumes/{uuid}/mylibrary/lib.json + (for datastore)</li> <li>nfs://server/path/mylibrary/lib.json (for NFSv3 server + on vCenter Server Appliance)</li> <li>nfs://server/path/mylibrary/lib.json?version=4 + (for NFSv4 server on vCenter Server Appliance) </li> <li>smb://server/path/mylibrary/lib.json + (for SMB server)</li> </ul> vSphere 6.0 <ul> <li>file://server/mylibrary/lib.json + (for UNC server on vCenter Server for Windows)</li> <li>file:///path/mylibrary/lib.json + (for local file system)</li> </ul> When you specify a DS subscription URL, the + datastore must be on the same vCenter Server as the subscribed library. When + you specify an NFS or SMB subscription URL, the C(storage_backings.storage_uri) + of the subscribed library must be on the same remote file server and should + share a common parent path with the subscription URL. ([''present'', ''probe''])' + - ' - C(user_name) (str): The username to use when authenticating. The username + must be set when using a password-based authentication method. Empty strings + are allowed for usernames. ([''present'', ''probe''])' + - ' - C(source_info) (dict): Information about the source published library. This + field will be set for a subscribed library which is associated with a subscription + of the published library. ([''present'', ''probe''])' + - ' - Accepted keys:' + - ' - source_library (string): Identifier of the published library.' + - ' - subscription (string): Identifier of the subscription associated with + the subscribed library.' + type: dict + type: + choices: + - LOCAL + - SUBSCRIBED + description: + - The C(library_type) defines the type of a Library. The type of a library can + be used to determine which additional services can be performed with a library. + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + version: + description: + - A version number which is updated on metadata changes. This value allows clients + to detect concurrent updates and prevent accidental clobbering of data. This + value represents a number which is incremented every time library properties, + such as name or description, are changed. It is not incremented by changes to + a library item within the library, including adding or removing items. It is + also not affected by tagging the library. + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Build a list of subscribed libraries + vmware.vmware_rest.content_subscribedlibrary_info: + register: result + +- name: Delete all the subscribed libraries + vmware.vmware_rest.content_subscribedlibrary: + library_id: '{{ item.id }}' + state: absent + with_items: '{{ result.value }}' + +- name: Create a content library pointing on a NFS share + vmware.vmware_rest.content_locallibrary: + name: my_library_on_nfs + description: automated + publish_info: + published: true + authentication_method: NONE + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + state: present + register: nfs_lib + +- name: Create subscribed library + vmware.vmware_rest.content_subscribedlibrary: + name: sub_lib + subscription_info: + subscription_url: '{{ nfs_lib.value.publish_info.publish_url }}' + authentication_method: NONE + automatic_sync_enabled: false + on_demand: true + storage_backings: + - datastore_id: "{{ lookup('vmware.vmware_rest.datastore_moid', '/my_dc/datastore/rw_datastore')\ + \ }}" + type: DATASTORE + register: sub_lib + +- name: Create subscribed library (again) + vmware.vmware_rest.content_subscribedlibrary: + name: sub_lib + subscription_info: + subscription_url: '{{ nfs_lib.value.publish_info.publish_url }}' + authentication_method: NONE + automatic_sync_enabled: false + on_demand: true + storage_backings: + - datastore_id: "{{ lookup('vmware.vmware_rest.datastore_moid', '/my_dc/datastore/rw_datastore')\ + \ }}" + type: DATASTORE + register: result + +- name: Clean up the cache + vmware.vmware_rest.content_subscribedlibrary: + name: sub_lib + library_id: '{{ sub_lib.id }}' + state: evict + +- name: Trigger a library sync + vmware.vmware_rest.content_subscribedlibrary: + name: sub_lib + library_id: '{{ sub_lib.id }}' + state: sync +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Delete all the subscribed libraries +msg: + description: Delete all the subscribed libraries + returned: On success + sample: All items completed + type: str +results: + description: Delete all the subscribed libraries + returned: On success + sample: + - _ansible_item_label: + creation_time: '2022-06-23T22:38:29.995Z' + description: '' + id: 41bd5c47-e658-4876-bab2-03758f25a3e9 + last_modified_time: '2022-06-23T22:38:29.995Z' + last_sync_time: '2022-06-23T22:38:32.305Z' + name: sub_lib + server_guid: b138c531-cd80-43f5-842d-657d9ddc98f8 + storage_backings: + - datastore_id: datastore-1200 + type: DATASTORE + subscription_info: + authentication_method: NONE + automatic_sync_enabled: 0 + on_demand: 1 + subscription_url: https://vcenter.test:443/cls/vcsp/lib/c9b8f7da-d5ac-4076-86b9-39ee107d7da3/lib.json + type: SUBSCRIBED + version: '4' + _ansible_no_log: null + ansible_loop_var: item + changed: 1 + failed: 0 + invocation: + module_args: + client_token: null + creation_time: null + description: null + id: null + last_modified_time: null + last_sync_time: null + library_id: 41bd5c47-e658-4876-bab2-03758f25a3e9 + name: null + optimization_info: null + publish_info: null + server_guid: null + session_timeout: null + state: absent + storage_backings: null + subscription_info: null + type: null + vcenter_hostname: vcenter.test + vcenter_password: VALUE_SPECIFIED_IN_NO_LOG_PARAMETER + vcenter_rest_log_file: null + vcenter_username: administrator@vsphere.local + vcenter_validate_certs: 0 + version: null + item: + creation_time: '2022-06-23T22:38:29.995Z' + description: '' + id: 41bd5c47-e658-4876-bab2-03758f25a3e9 + last_modified_time: '2022-06-23T22:38:29.995Z' + last_sync_time: '2022-06-23T22:38:32.305Z' + name: sub_lib + server_guid: b138c531-cd80-43f5-842d-657d9ddc98f8 + storage_backings: + - datastore_id: datastore-1200 + type: DATASTORE + subscription_info: + authentication_method: NONE + automatic_sync_enabled: 0 + on_demand: 1 + subscription_url: https://vcenter.test:443/cls/vcsp/lib/c9b8f7da-d5ac-4076-86b9-39ee107d7da3/lib.json + type: SUBSCRIBED + version: '4' + value: {} + type: list +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "evict": {"query": {}, "body": {}, "path": {"library_id": "library_id"}}, + "probe": { + "query": {}, + "body": {"subscription_info": "subscription_info"}, + "path": {}, + }, + "sync": {"query": {}, "body": {}, "path": {"library_id": "library_id"}}, + "update": { + "query": {}, + "body": { + "creation_time": "creation_time", + "description": "description", + "id": "id", + "last_modified_time": "last_modified_time", + "last_sync_time": "last_sync_time", + "name": "name", + "optimization_info": "optimization_info", + "publish_info": "publish_info", + "server_guid": "server_guid", + "storage_backings": "storage_backings", + "subscription_info": "subscription_info", + "type": "type", + "version": "version", + }, + "path": {"library_id": "library_id"}, + }, + "create": { + "query": {"client_token": "client_token"}, + "body": { + "creation_time": "creation_time", + "description": "description", + "id": "id", + "last_modified_time": "last_modified_time", + "last_sync_time": "last_sync_time", + "name": "name", + "optimization_info": "optimization_info", + "publish_info": "publish_info", + "server_guid": "server_guid", + "storage_backings": "storage_backings", + "subscription_info": "subscription_info", + "type": "type", + "version": "version", + }, + "path": {}, + }, + "delete": {"query": {}, "body": {}, "path": {"library_id": "library_id"}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["client_token"] = {"no_log": True, "type": "str"} + argument_spec["creation_time"] = {"type": "str"} + argument_spec["description"] = {"type": "str"} + argument_spec["id"] = {"type": "str"} + argument_spec["last_modified_time"] = {"type": "str"} + argument_spec["last_sync_time"] = {"type": "str"} + argument_spec["library_id"] = {"type": "str"} + argument_spec["name"] = {"type": "str"} + argument_spec["optimization_info"] = {"type": "dict"} + argument_spec["publish_info"] = {"type": "dict"} + argument_spec["server_guid"] = {"type": "str"} + argument_spec["state"] = { + "type": "str", + "choices": ["absent", "evict", "present", "probe", "sync"], + "default": "present", + } + argument_spec["storage_backings"] = {"type": "list", "elements": "dict"} + argument_spec["subscription_info"] = {"type": "dict"} + argument_spec["type"] = {"type": "str", "choices": ["LOCAL", "SUBSCRIBED"]} + argument_spec["version"] = {"type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/content/subscribed-library").format( + **params + ) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _create(params, session): + + lookup_url = per_id_url = build_url(params) + uniquity_keys = ["name"] + comp_func = None + + _json = None + + if params["library_id"]: + _json = await get_device_info(session, build_url(params), params["library_id"]) + + if not _json and (uniquity_keys or comp_func): + _json = await exists( + params, + session, + url=lookup_url, + uniquity_keys=uniquity_keys, + per_id_url=per_id_url, + comp_func=comp_func, + ) + + if _json: + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + if "_update" in globals(): + params["library_id"] = _json["id"] + return await globals()["_update"](params, session) + + return await update_changed_flag(_json, 200, "get") + + payload = prepare_payload(params, PAYLOAD_FORMAT["create"]) + _url = ("https://{vcenter_hostname}" "/api/content/subscribed-library").format( + **params + ) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + if resp.status == 500: + text = await resp.text() + raise EmbeddedModuleFailure( + f"Request has failed: status={resp.status}, {text}" + ) + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + + if (resp.status in [200, 201]) and "error" not in _json: + if isinstance(_json, str): # 7.0.2 and greater + _id = _json # TODO: fetch the object + elif isinstance(_json, dict) and "value" not in _json: + _id = list(_json["value"].values())[0] + elif isinstance(_json, dict) and "value" in _json: + _id = _json["value"] + _json_device_info = await get_device_info(session, _url, _id) + if _json_device_info: + _json = _json_device_info + + return await update_changed_flag(_json, resp.status, "create") + + +async def _delete(params, session): + _in_query_parameters = PAYLOAD_FORMAT["delete"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["delete"]) + subdevice_type = get_subdevice_type("/api/content/subscribed-library/{library_id}") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" "/api/content/subscribed-library/{library_id}" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.delete(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "delete") + + +async def _evict(params, session): + _in_query_parameters = PAYLOAD_FORMAT["evict"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["evict"]) + subdevice_type = get_subdevice_type( + "/api/content/subscribed-library/{library_id}?action=evict" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/content/subscribed-library/{library_id}?action=evict" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "evict") + + +async def _probe(params, session): + _in_query_parameters = PAYLOAD_FORMAT["probe"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["probe"]) + subdevice_type = get_subdevice_type("/api/content/subscribed-library?action=probe") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/content/subscribed-library?action=probe" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "probe") + + +async def _sync(params, session): + _in_query_parameters = PAYLOAD_FORMAT["sync"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["sync"]) + subdevice_type = get_subdevice_type( + "/api/content/subscribed-library/{library_id}?action=sync" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/content/subscribed-library/{library_id}?action=sync" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "sync") + + +async def _update(params, session): + payload = prepare_payload(params, PAYLOAD_FORMAT["update"]) + _url = ( + "https://{vcenter_hostname}" "/api/content/subscribed-library/{library_id}" + ).format(**params) + async with session.get(_url, **session_timeout(params)) as resp: + _json = await resp.json() + if "value" in _json: + value = _json["value"] + else: # 7.0.2 and greater + value = _json + for k, v in value.items(): + if k in payload: + if isinstance(payload[k], dict) and isinstance(v, dict): + to_delete = True + for _k in list(payload[k].keys()): + if payload[k][_k] != v.get(_k): + to_delete = False + if to_delete: + del payload[k] + elif payload[k] == v: + del payload[k] + elif payload[k] == {}: + del payload[k] + + if payload == {} or payload == {"spec": {}}: + # Nothing has changed + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + _json["id"] = params.get("library_id") + return await update_changed_flag(_json, resp.status, "get") + async with session.patch(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # e.g: content_configuration + if not _json and resp.status == 204: + async with session.get(_url, **session_timeout(params)) as resp_get: + _json_get = await resp_get.json() + if _json_get: + _json = _json_get + + _json["id"] = params.get("library_id") + return await update_changed_flag(_json, resp.status, "update") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/content_subscribedlibrary_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/content_subscribedlibrary_info.py new file mode 100644 index 00000000..96201792 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/content_subscribedlibrary_info.py @@ -0,0 +1,258 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: content_subscribedlibrary_info +short_description: Returns a given subscribed library. +description: Returns a given subscribed library. +options: + library_id: + description: + - Identifier of the subscribed library to return. Required with I(state=['get']) + type: str + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Build a list of subscribed libraries + vmware.vmware_rest.content_subscribedlibrary_info: + register: result + +- name: List Subscribed Content Library + vmware.vmware_rest.content_subscribedlibrary_info: + register: my_content_library +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: List Subscribed Content Library +value: + description: List Subscribed Content Library + returned: On success + sample: + - creation_time: '2022-06-23T22:38:29.995Z' + description: '' + id: 41bd5c47-e658-4876-bab2-03758f25a3e9 + last_modified_time: '2022-06-23T22:38:29.995Z' + last_sync_time: '2022-06-23T22:38:32.305Z' + name: sub_lib + server_guid: b138c531-cd80-43f5-842d-657d9ddc98f8 + storage_backings: + - datastore_id: datastore-1200 + type: DATASTORE + subscription_info: + authentication_method: NONE + automatic_sync_enabled: 0 + on_demand: 1 + subscription_url: https://vcenter.test:443/cls/vcsp/lib/c9b8f7da-d5ac-4076-86b9-39ee107d7da3/lib.json + type: SUBSCRIBED + version: '4' + type: list +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"library_id": "library_id"}}, + "list": {"query": {}, "body": {}, "path": {}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["library_id"] = {"type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_list_and_get_module.j2 +def build_url(params): + if params.get("library_id"): + _in_query_parameters = PAYLOAD_FORMAT["get"]["query"].keys() + return ( + ("https://{vcenter_hostname}" "/api/content/subscribed-library/").format( + **params + ) + + params["library_id"] + + gen_args(params, _in_query_parameters) + ) + _in_query_parameters = PAYLOAD_FORMAT["list"]["query"].keys() + return ("https://{vcenter_hostname}" "/api/content/subscribed-library").format( + **params + ) + gen_args(params, _in_query_parameters) + + +async def entry_point(module, session): + url = build_url(module.params) + async with session.get(url, **session_timeout(module.params)) as resp: + _json = await resp.json() + + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + + if module.params.get("library_id"): + _json["id"] = module.params.get("library_id") + elif module.params.get("label"): # TODO extend the list of filter + _json = await exists(module.params, session, url) + elif ( + isinstance(_json["value"], list) + and len(_json["value"]) > 0 + and isinstance(_json["value"][0], str) + ): + # this is a list of id, we fetch the details + full_device_list = await build_full_device_list(session, url, _json) + _json = {"value": [i["value"] for i in full_device_list]} + + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_cluster_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_cluster_info.py new file mode 100644 index 00000000..edf99861 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_cluster_info.py @@ -0,0 +1,306 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_cluster_info +short_description: Retrieves information about the cluster corresponding to {@param.name + cluster}. +description: Retrieves information about the cluster corresponding to {@param.name + cluster}. +options: + cluster: + description: + - Identifier of the cluster. Required with I(state=['get']) + type: str + clusters: + description: + - Identifiers of clusters that can match the filter. + elements: str + type: list + datacenters: + aliases: + - filter_datacenters + description: + - Datacenters that must contain the cluster for the cluster to match the filter. + elements: str + type: list + folders: + aliases: + - filter_folders + description: + - Folders that must contain the cluster for the cluster to match the filter. + elements: str + type: list + names: + aliases: + - filter_names + description: + - Names that clusters must have to match the filter (see {@link Info#name}). + elements: str + type: list + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Build a list of all the clusters + vmware.vmware_rest.vcenter_cluster_info: + register: all_the_clusters + +- name: Retrieve details about the first cluster + vmware.vmware_rest.vcenter_cluster_info: + cluster: '{{ all_the_clusters.value[0].cluster }}' + register: my_cluster_info + +- name: get all the clusters called my_cluster + vmware.vmware_rest.vcenter_cluster_info: + filter_names: + - my_cluster + register: my_cluster +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Retrieve details about the first cluster +id: + description: moid of the resource + returned: On success + sample: domain-c1140 + type: str +value: + description: Retrieve details about the first cluster + returned: On success + sample: + name: my_cluster + resource_pool: resgroup-1141 + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"cluster": "cluster"}}, + "list": { + "query": { + "clusters": "clusters", + "datacenters": "datacenters", + "folders": "folders", + "names": "names", + }, + "body": {}, + "path": {}, + }, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["cluster"] = {"type": "str"} + argument_spec["clusters"] = {"type": "list", "elements": "str"} + argument_spec["datacenters"] = { + "aliases": ["filter_datacenters"], + "type": "list", + "elements": "str", + } + argument_spec["folders"] = { + "aliases": ["filter_folders"], + "type": "list", + "elements": "str", + } + argument_spec["names"] = { + "aliases": ["filter_names"], + "type": "list", + "elements": "str", + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_list_and_get_module.j2 +def build_url(params): + if params.get("cluster"): + _in_query_parameters = PAYLOAD_FORMAT["get"]["query"].keys() + return ( + ("https://{vcenter_hostname}" "/api/vcenter/cluster/").format(**params) + + params["cluster"] + + gen_args(params, _in_query_parameters) + ) + _in_query_parameters = PAYLOAD_FORMAT["list"]["query"].keys() + return ("https://{vcenter_hostname}" "/api/vcenter/cluster").format( + **params + ) + gen_args(params, _in_query_parameters) + + +async def entry_point(module, session): + url = build_url(module.params) + async with session.get(url, **session_timeout(module.params)) as resp: + _json = await resp.json() + + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + + if module.params.get("cluster"): + _json["id"] = module.params.get("cluster") + elif module.params.get("label"): # TODO extend the list of filter + _json = await exists(module.params, session, url) + elif ( + isinstance(_json["value"], list) + and len(_json["value"]) > 0 + and isinstance(_json["value"][0], str) + ): + # this is a list of id, we fetch the details + full_device_list = await build_full_device_list(session, url, _json) + _json = {"value": [i["value"] for i in full_device_list]} + + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_datacenter.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_datacenter.py new file mode 100644 index 00000000..0a0c9bfa --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_datacenter.py @@ -0,0 +1,388 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_datacenter +short_description: Create a new datacenter in the vCenter inventory +description: Create a new datacenter in the vCenter inventory +options: + datacenter: + description: + - Identifier of the datacenter to be deleted. Required with I(state=['absent']) + type: str + folder: + description: + - Datacenter folder in which the new datacenter should be created. + type: str + force: + description: + - If true, delete the datacenter even if it is not empty. + type: bool + name: + description: + - The name of the datacenter to be created. Required with I(state=['present']) + type: str + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - absent + - present + default: present + description: [] + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Get a list of all the datacenters + register: existing_datacenters + vmware.vmware_rest.vcenter_datacenter_info: + +- name: Force delete the existing DC + vmware.vmware_rest.vcenter_datacenter: + state: absent + datacenter: '{{ item.datacenter }}' + force: true + with_items: '{{ existing_datacenters.value }}' + until: + - _result is not failed + retries: 7 + +- name: Create datacenter my_dc + vmware.vmware_rest.vcenter_datacenter: + name: my_dc + folder: '{{ my_datacenter_folder.folder }}' +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Force delete the existing DC +msg: + description: Force delete the existing DC + returned: On success + sample: All items completed + type: str +results: + description: Force delete the existing DC + returned: On success + sample: + - _ansible_item_label: + datacenter: datacenter-1107 + name: my_dc + _ansible_no_log: null + ansible_loop_var: item + attempts: 1 + changed: 1 + failed: 0 + invocation: + module_args: + datacenter: datacenter-1107 + folder: null + force: 1 + name: null + session_timeout: null + state: absent + vcenter_hostname: vcenter.test + vcenter_password: VALUE_SPECIFIED_IN_NO_LOG_PARAMETER + vcenter_rest_log_file: null + vcenter_username: administrator@vsphere.local + vcenter_validate_certs: 0 + item: + datacenter: datacenter-1107 + name: my_dc + value: {} + type: list +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "create": {"query": {}, "body": {"folder": "folder", "name": "name"}, "path": {}}, + "delete": { + "query": {"force": "force"}, + "body": {}, + "path": {"datacenter": "datacenter"}, + }, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["datacenter"] = {"type": "str"} + argument_spec["folder"] = {"type": "str"} + argument_spec["force"] = {"type": "bool"} + argument_spec["name"] = {"type": "str"} + argument_spec["state"] = { + "type": "str", + "choices": ["absent", "present"], + "default": "present", + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/vcenter/datacenter").format(**params) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _create(params, session): + + lookup_url = per_id_url = build_url(params) + uniquity_keys = ["datacenter"] + comp_func = None + + async def lookup_with_filters(params, session, url): + # e.g: for the datacenter resources + if "folder" not in params: + return + if "name" not in params: + return + async with session.get( + f"{url}?names={params['name']}&folders={params['folder']}" + ) as resp: + _json = await resp.json() + if isinstance(_json, list) and len(_json) == 1: + return await get_device_info(session, url, _json[0]["datacenter"]) + + _json = None + + if params["datacenter"]: + _json = await get_device_info(session, build_url(params), params["datacenter"]) + + if not _json and (uniquity_keys or comp_func): + _json = await exists( + params, + session, + url=lookup_url, + uniquity_keys=uniquity_keys, + per_id_url=per_id_url, + comp_func=comp_func, + ) + + if not _json: + _json = await lookup_with_filters(params, session, build_url(params)) + + if _json: + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + if "_update" in globals(): + params["datacenter"] = _json["id"] + return await globals()["_update"](params, session) + + return await update_changed_flag(_json, 200, "get") + + payload = prepare_payload(params, PAYLOAD_FORMAT["create"]) + _url = ("https://{vcenter_hostname}" "/api/vcenter/datacenter").format(**params) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + if resp.status == 500: + text = await resp.text() + raise EmbeddedModuleFailure( + f"Request has failed: status={resp.status}, {text}" + ) + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + + if (resp.status in [200, 201]) and "error" not in _json: + if isinstance(_json, str): # 7.0.2 and greater + _id = _json # TODO: fetch the object + elif isinstance(_json, dict) and "value" not in _json: + _id = list(_json["value"].values())[0] + elif isinstance(_json, dict) and "value" in _json: + _id = _json["value"] + _json_device_info = await get_device_info(session, _url, _id) + if _json_device_info: + _json = _json_device_info + + return await update_changed_flag(_json, resp.status, "create") + + +async def _delete(params, session): + _in_query_parameters = PAYLOAD_FORMAT["delete"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["delete"]) + subdevice_type = get_subdevice_type("/api/vcenter/datacenter/{datacenter}") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ("https://{vcenter_hostname}" "/api/vcenter/datacenter/{datacenter}").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.delete(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "delete") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_datacenter_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_datacenter_info.py new file mode 100644 index 00000000..9e519c82 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_datacenter_info.py @@ -0,0 +1,283 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_datacenter_info +short_description: Retrieves information about the datacenter corresponding to {@param.name + datacenter}. +description: Retrieves information about the datacenter corresponding to {@param.name + datacenter}. +options: + datacenter: + description: + - Identifier of the datacenter. Required with I(state=['get']) + type: str + datacenters: + aliases: + - filter_datacenters + description: + - Identifiers of datacenters that can match the filter. + elements: str + type: list + folders: + aliases: + - filter_folders + description: + - Folders that must contain the datacenters for the datacenter to match the filter. + elements: str + type: list + names: + aliases: + - filter_names + description: + - Names that datacenters must have to match the filter (see {@link Info#name}). + elements: str + type: list + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Get a list of all the datacenters + register: existing_datacenters + vmware.vmware_rest.vcenter_datacenter_info: + +- name: collect a list of the datacenters + vmware.vmware_rest.vcenter_datacenter_info: + register: my_datacenters +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: collect a list of the datacenters +value: + description: collect a list of the datacenters + returned: On success + sample: + - datacenter: datacenter-1135 + name: my_dc + type: list +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"datacenter": "datacenter"}}, + "list": { + "query": {"datacenters": "datacenters", "folders": "folders", "names": "names"}, + "body": {}, + "path": {}, + }, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["datacenter"] = {"type": "str"} + argument_spec["datacenters"] = { + "aliases": ["filter_datacenters"], + "type": "list", + "elements": "str", + } + argument_spec["folders"] = { + "aliases": ["filter_folders"], + "type": "list", + "elements": "str", + } + argument_spec["names"] = { + "aliases": ["filter_names"], + "type": "list", + "elements": "str", + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_list_and_get_module.j2 +def build_url(params): + if params.get("datacenter"): + _in_query_parameters = PAYLOAD_FORMAT["get"]["query"].keys() + return ( + ("https://{vcenter_hostname}" "/api/vcenter/datacenter/").format(**params) + + params["datacenter"] + + gen_args(params, _in_query_parameters) + ) + _in_query_parameters = PAYLOAD_FORMAT["list"]["query"].keys() + return ("https://{vcenter_hostname}" "/api/vcenter/datacenter").format( + **params + ) + gen_args(params, _in_query_parameters) + + +async def entry_point(module, session): + url = build_url(module.params) + async with session.get(url, **session_timeout(module.params)) as resp: + _json = await resp.json() + + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + + if module.params.get("datacenter"): + _json["id"] = module.params.get("datacenter") + elif module.params.get("label"): # TODO extend the list of filter + _json = await exists(module.params, session, url) + elif ( + isinstance(_json["value"], list) + and len(_json["value"]) > 0 + and isinstance(_json["value"][0], str) + ): + # this is a list of id, we fetch the details + full_device_list = await build_full_device_list(session, url, _json) + _json = {"value": [i["value"] for i in full_device_list]} + + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_datastore_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_datastore_info.py new file mode 100644 index 00000000..f3bbc8a3 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_datastore_info.py @@ -0,0 +1,316 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_datastore_info +short_description: Retrieves information about the datastore indicated by {@param.name + datastore}. +description: Retrieves information about the datastore indicated by {@param.name datastore}. +options: + datacenters: + aliases: + - filter_datacenters + description: + - Datacenters that must contain the datastore for the datastore to match the filter. + elements: str + type: list + datastore: + description: + - Identifier of the datastore for which information should be retrieved. Required + with I(state=['get']) + type: str + datastores: + description: + - Identifiers of datastores that can match the filter. + elements: str + type: list + folders: + aliases: + - filter_folders + description: + - Folders that must contain the datastore for the datastore to match the filter. + elements: str + type: list + names: + aliases: + - filter_names + description: + - Names that datastores must have to match the filter (see {@link Info#name}). + elements: str + type: list + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + types: + aliases: + - filter_types + description: + - Types that datastores must have to match the filter (see {@link Summary#type}). + elements: str + type: list + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Build a list of all the datastores + vmware.vmware_rest.vcenter_datastore_info: + register: all_the_datastores +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Build a list of all the datastores +value: + description: Build a list of all the datastores + returned: On success + sample: + - capacity: 42314215424 + datastore: datastore-1148 + free_space: 40296542208 + name: ro_datastore + type: NFS + - capacity: 42314215424 + datastore: datastore-1149 + free_space: 40296542208 + name: rw_datastore + type: NFS + - capacity: 11542724608 + datastore: datastore-1150 + free_space: 9069133824 + name: local + type: VMFS + type: list +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"datastore": "datastore"}}, + "list": { + "query": { + "datacenters": "datacenters", + "datastores": "datastores", + "folders": "folders", + "names": "names", + "types": "types", + }, + "body": {}, + "path": {}, + }, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["datacenters"] = { + "aliases": ["filter_datacenters"], + "type": "list", + "elements": "str", + } + argument_spec["datastore"] = {"type": "str"} + argument_spec["datastores"] = {"type": "list", "elements": "str"} + argument_spec["folders"] = { + "aliases": ["filter_folders"], + "type": "list", + "elements": "str", + } + argument_spec["names"] = { + "aliases": ["filter_names"], + "type": "list", + "elements": "str", + } + argument_spec["types"] = { + "aliases": ["filter_types"], + "type": "list", + "elements": "str", + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_list_and_get_module.j2 +def build_url(params): + if params.get("datastore"): + _in_query_parameters = PAYLOAD_FORMAT["get"]["query"].keys() + return ( + ("https://{vcenter_hostname}" "/api/vcenter/datastore/").format(**params) + + params["datastore"] + + gen_args(params, _in_query_parameters) + ) + _in_query_parameters = PAYLOAD_FORMAT["list"]["query"].keys() + return ("https://{vcenter_hostname}" "/api/vcenter/datastore").format( + **params + ) + gen_args(params, _in_query_parameters) + + +async def entry_point(module, session): + url = build_url(module.params) + async with session.get(url, **session_timeout(module.params)) as resp: + _json = await resp.json() + + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + + if module.params.get("datastore"): + _json["id"] = module.params.get("datastore") + elif module.params.get("label"): # TODO extend the list of filter + _json = await exists(module.params, session, url) + elif ( + isinstance(_json["value"], list) + and len(_json["value"]) > 0 + and isinstance(_json["value"][0], str) + ): + # this is a list of id, we fetch the details + full_device_list = await build_full_device_list(session, url, _json) + _json = {"value": [i["value"] for i in full_device_list]} + + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_folder_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_folder_info.py new file mode 100644 index 00000000..460bba5a --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_folder_info.py @@ -0,0 +1,296 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_folder_info +short_description: Returns information about at most 1000 visible (subject to permission + checks) folders in vCenter matching the {@link FilterSpec}. +description: Returns information about at most 1000 visible (subject to permission + checks) folders in vCenter matching the {@link FilterSpec}. +options: + datacenters: + aliases: + - filter_datacenters + description: + - Datacenters that must contain the folder for the folder to match the filter. + elements: str + type: list + folders: + aliases: + - filter_folders + description: + - Identifiers of folders that can match the filter. + elements: str + type: list + names: + aliases: + - filter_names + description: + - Names that folders must have to match the filter (see {@link Summary#name}). + elements: str + type: list + parent_folders: + description: + - Folders that must contain the folder for the folder to match the filter. + elements: str + type: list + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + type: + aliases: + - filter_type + choices: + - DATACENTER + - DATASTORE + - HOST + - NETWORK + - VIRTUAL_MACHINE + description: + - The C(type) defines the type of a vCenter Server folder. The type of a folder + determines what what kinds of children can be contained in the folder. + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Build a list of all the folders + vmware.vmware_rest.vcenter_folder_info: + register: my_folders + +- name: Build a list of all the folders with the type VIRTUAL_MACHINE and called vm + vmware.vmware_rest.vcenter_folder_info: + filter_type: VIRTUAL_MACHINE + filter_names: + - vm + register: my_folders + +- name: Build a list of the folders, with a filter + vmware.vmware_rest.vcenter_folder_info: + filter_type: DATASTORE +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Build a list of all the folders with the type VIRTUAL_MACHINE and called vm +value: + description: Build a list of all the folders with the type VIRTUAL_MACHINE and called + vm + returned: On success + sample: + - folder: group-v1136 + name: vm + type: VIRTUAL_MACHINE + type: list +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "list": { + "query": { + "datacenters": "datacenters", + "folders": "folders", + "names": "names", + "parent_folders": "parent_folders", + "type": "type", + }, + "body": {}, + "path": {}, + } +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["datacenters"] = { + "aliases": ["filter_datacenters"], + "type": "list", + "elements": "str", + } + argument_spec["folders"] = { + "aliases": ["filter_folders"], + "type": "list", + "elements": "str", + } + argument_spec["names"] = { + "aliases": ["filter_names"], + "type": "list", + "elements": "str", + } + argument_spec["parent_folders"] = {"type": "list", "elements": "str"} + argument_spec["type"] = { + "aliases": ["filter_type"], + "type": "str", + "choices": ["DATACENTER", "DATASTORE", "HOST", "NETWORK", "VIRTUAL_MACHINE"], + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_list_and_get_module.j2 +def build_url(params): + _in_query_parameters = PAYLOAD_FORMAT["list"]["query"].keys() + return ("https://{vcenter_hostname}" "/api/vcenter/folder").format( + **params + ) + gen_args(params, _in_query_parameters) + + +async def entry_point(module, session): + url = build_url(module.params) + async with session.get(url, **session_timeout(module.params)) as resp: + _json = await resp.json() + + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_host.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_host.py new file mode 100644 index 00000000..7ec62eda --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_host.py @@ -0,0 +1,453 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_host +short_description: Add a new standalone host in the vCenter inventory +description: Add a new standalone host in the vCenter inventory. The newly connected + host will be in connected state. The vCenter Server will verify the SSL certificate + before adding the host to its inventory. In the case where the SSL certificate cannot + be verified because the Certificate Authority is not recognized or the certificate + is self signed, the vCenter Server will fall back to thumbprint verification mode + as defined by {@link CreateSpec.ThumbprintVerification}. +options: + folder: + description: + - Host and cluster folder in which the new standalone host should be created. + type: str + force_add: + description: + - Whether host should be added to the vCenter Server even if it is being managed + by another vCenter Server. The original vCenterServer loses connection to the + host. + type: bool + host: + description: + - Identifier of the host to be disconnected. Required with I(state=['absent', + 'connect', 'disconnect']) + type: str + hostname: + description: + - The IP address or DNS resolvable name of the host. Required with I(state=['present']) + type: str + password: + description: + - The password for the administrator account on the host. Required with I(state=['present']) + type: str + port: + description: + - The port of the host. + type: int + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - absent + - connect + - disconnect + - present + default: present + description: [] + type: str + thumbprint: + description: + - 'The thumbprint of the SSL certificate, which the host is expected to have. + The thumbprint is always computed using the SHA1 hash and is the string representation + of that hash in the format: xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx + where, ''x'' represents a hexadecimal digit.' + type: str + thumbprint_verification: + choices: + - NONE + - THUMBPRINT + description: + - The C(thumbprint_verification) defines the thumbprint verification schemes for + a host's SSL certificate. Required with I(state=['present']) + type: str + user_name: + description: + - The administrator account on the host. Required with I(state=['present']) + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Connect the host(s) + vmware.vmware_rest.vcenter_host: + hostname: "{{ lookup('env', 'ESXI1_HOSTNAME') }}" + user_name: "{{ lookup('env', 'ESXI1_USERNAME') }}" + password: "{{ lookup('env', 'ESXI1_PASSWORD') }}" + thumbprint_verification: NONE + folder: '{{ my_host_folder.folder }}' +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Connect the host(s) +value: + description: Connect the host(s) + returned: On success + sample: host-1147 + type: str +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "create": { + "query": {}, + "body": { + "folder": "folder", + "force_add": "force_add", + "hostname": "hostname", + "password": "password", + "port": "port", + "thumbprint": "thumbprint", + "thumbprint_verification": "thumbprint_verification", + "user_name": "user_name", + }, + "path": {}, + }, + "disconnect": {"query": {}, "body": {}, "path": {"host": "host"}}, + "delete": {"query": {}, "body": {}, "path": {"host": "host"}}, + "connect": {"query": {}, "body": {}, "path": {"host": "host"}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["folder"] = {"type": "str"} + argument_spec["force_add"] = {"type": "bool"} + argument_spec["host"] = {"type": "str"} + argument_spec["hostname"] = {"type": "str"} + argument_spec["password"] = {"no_log": True, "type": "str"} + argument_spec["port"] = {"type": "int"} + argument_spec["state"] = { + "type": "str", + "choices": ["absent", "connect", "disconnect", "present"], + "default": "present", + } + argument_spec["thumbprint"] = {"type": "str"} + argument_spec["thumbprint_verification"] = { + "type": "str", + "choices": ["NONE", "THUMBPRINT"], + } + argument_spec["user_name"] = {"no_log": True, "type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/vcenter/host").format(**params) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _connect(params, session): + _in_query_parameters = PAYLOAD_FORMAT["connect"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["connect"]) + subdevice_type = get_subdevice_type("/api/vcenter/host/{host}?action=connect") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/vcenter/host/{host}?action=connect" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "connect") + + +async def _create(params, session): + + lookup_url = per_id_url = build_url(params) + uniquity_keys = ["host"] + comp_func = None + + async def lookup_with_filters(params, session, url): + # e.g: for the datacenter resources + if "folder" not in params: + return + if "name" not in params: + return + async with session.get( + f"{url}?names={params['name']}&folders={params['folder']}" + ) as resp: + _json = await resp.json() + if isinstance(_json, list) and len(_json) == 1: + return await get_device_info(session, url, _json[0]["host"]) + + _json = None + + if params["host"]: + _json = await get_device_info(session, build_url(params), params["host"]) + + if not _json and (uniquity_keys or comp_func): + _json = await exists( + params, + session, + url=lookup_url, + uniquity_keys=uniquity_keys, + per_id_url=per_id_url, + comp_func=comp_func, + ) + + if not _json: + _json = await lookup_with_filters(params, session, build_url(params)) + + if _json: + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + if "_update" in globals(): + params["host"] = _json["id"] + return await globals()["_update"](params, session) + + return await update_changed_flag(_json, 200, "get") + + payload = prepare_payload(params, PAYLOAD_FORMAT["create"]) + _url = ("https://{vcenter_hostname}" "/api/vcenter/host").format(**params) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + if resp.status == 500: + text = await resp.text() + raise EmbeddedModuleFailure( + f"Request has failed: status={resp.status}, {text}" + ) + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + + if (resp.status in [200, 201]) and "error" not in _json: + if isinstance(_json, str): # 7.0.2 and greater + _id = _json # TODO: fetch the object + elif isinstance(_json, dict) and "value" not in _json: + _id = list(_json["value"].values())[0] + elif isinstance(_json, dict) and "value" in _json: + _id = _json["value"] + _json_device_info = await get_device_info(session, _url, _id) + if _json_device_info: + _json = _json_device_info + + return await update_changed_flag(_json, resp.status, "create") + + +async def _delete(params, session): + _in_query_parameters = PAYLOAD_FORMAT["delete"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["delete"]) + subdevice_type = get_subdevice_type("/api/vcenter/host/{host}") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ("https://{vcenter_hostname}" "/api/vcenter/host/{host}").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.delete(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "delete") + + +async def _disconnect(params, session): + _in_query_parameters = PAYLOAD_FORMAT["disconnect"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["disconnect"]) + subdevice_type = get_subdevice_type("/api/vcenter/host/{host}?action=disconnect") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/vcenter/host/{host}?action=disconnect" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "disconnect") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_host_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_host_info.py new file mode 100644 index 00000000..f017a8c7 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_host_info.py @@ -0,0 +1,307 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_host_info +short_description: Returns information about at most 2500 visible (subject to permission + checks) hosts in vCenter matching the {@link FilterSpec}. +description: Returns information about at most 2500 visible (subject to permission + checks) hosts in vCenter matching the {@link FilterSpec}. +options: + clusters: + description: + - Clusters that must contain the hosts for the hosts to match the filter. + elements: str + type: list + connection_states: + description: + - Connection states that a host must be in to match the filter (see {@link Summary#connectionState}. + elements: str + type: list + datacenters: + aliases: + - filter_datacenters + description: + - Datacenters that must contain the hosts for the hosts to match the filter. + elements: str + type: list + folders: + aliases: + - filter_folders + description: + - Folders that must contain the hosts for the hosts to match the filter. + elements: str + type: list + hosts: + description: + - Identifiers of hosts that can match the filter. + elements: str + type: list + names: + aliases: + - filter_names + description: + - Names that hosts must have to match the filter (see {@link Summary#name}). + elements: str + type: list + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + standalone: + description: + - If true, only hosts that are not part of a cluster can match the filter, and + if false, only hosts that are are part of a cluster can match the filter. + type: bool + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Get a list of the hosts + vmware.vmware_rest.vcenter_host_info: + register: my_hosts +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get a list of the hosts +value: + description: Get a list of the hosts + returned: On success + sample: + - connection_state: CONNECTED + host: host-1147 + name: esxi1.test + power_state: POWERED_ON + type: list +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "list": { + "query": { + "clusters": "clusters", + "connection_states": "connection_states", + "datacenters": "datacenters", + "folders": "folders", + "hosts": "hosts", + "names": "names", + "standalone": "standalone", + }, + "body": {}, + "path": {}, + } +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["clusters"] = {"type": "list", "elements": "str"} + argument_spec["connection_states"] = {"type": "list", "elements": "str"} + argument_spec["datacenters"] = { + "aliases": ["filter_datacenters"], + "type": "list", + "elements": "str", + } + argument_spec["folders"] = { + "aliases": ["filter_folders"], + "type": "list", + "elements": "str", + } + argument_spec["hosts"] = {"type": "list", "elements": "str"} + argument_spec["names"] = { + "aliases": ["filter_names"], + "type": "list", + "elements": "str", + } + argument_spec["standalone"] = {"type": "bool"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_list_and_get_module.j2 +def build_url(params): + if params.get("host"): + _in_query_parameters = PAYLOAD_FORMAT["get"]["query"].keys() + return ( + ("https://{vcenter_hostname}" "/api/vcenter/host/").format(**params) + + params["host"] + + gen_args(params, _in_query_parameters) + ) + _in_query_parameters = PAYLOAD_FORMAT["list"]["query"].keys() + return ("https://{vcenter_hostname}" "/api/vcenter/host").format( + **params + ) + gen_args(params, _in_query_parameters) + + +async def entry_point(module, session): + url = build_url(module.params) + async with session.get(url, **session_timeout(module.params)) as resp: + _json = await resp.json() + + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + + if module.params.get("host"): + _json["id"] = module.params.get("host") + elif module.params.get("label"): # TODO extend the list of filter + _json = await exists(module.params, session, url) + elif ( + isinstance(_json["value"], list) + and len(_json["value"]) > 0 + and isinstance(_json["value"][0], str) + ): + # this is a list of id, we fetch the details + full_device_list = await build_full_device_list(session, url, _json) + _json = {"value": [i["value"] for i in full_device_list]} + + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_network_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_network_info.py new file mode 100644 index 00000000..45e6482e --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_network_info.py @@ -0,0 +1,298 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_network_info +short_description: Returns information about at most 1000 visible (subject to permission + checks) networks in vCenter matching the {@link FilterSpec}. +description: Returns information about at most 1000 visible (subject to permission + checks) networks in vCenter matching the {@link FilterSpec}. +options: + datacenters: + aliases: + - filter_datacenters + description: + - Datacenters that must contain the network for the network to match the filter. + elements: str + type: list + folders: + aliases: + - filter_folders + description: + - Folders that must contain the network for the network to match the filter. + elements: str + type: list + names: + aliases: + - filter_names + description: + - Names that networks must have to match the filter (see {@link Summary#name}). + elements: str + type: list + networks: + description: + - Identifiers of networks that can match the filter. + elements: str + type: list + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + types: + aliases: + - filter_types + description: + - Types that networks must have to match the filter (see {@link Summary#type}). + elements: str + type: list + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Get the dvswitch called my-portgroup + vmware.vmware_rest.vcenter_network_info: + filter_types: DISTRIBUTED_PORTGROUP + filter_names: my-portrgoup + register: my_portgroup + +- name: Get a list of the networks + vmware.vmware_rest.vcenter_network_info: + register: my_network_value + +- name: Get a list of the networks with a filter + vmware.vmware_rest.vcenter_network_info: + filter_types: STANDARD_PORTGROUP + register: my_standard_portgroup_value +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get a list of the networks +value: + description: Get a list of the networks + returned: On success + sample: + - name: dvswitch1-DVUplinks-1154 + network: dvportgroup-1155 + type: DISTRIBUTED_PORTGROUP + - name: my-portrgoup + network: dvportgroup-1157 + type: DISTRIBUTED_PORTGROUP + - name: VM Network + network: network-1151 + type: STANDARD_PORTGROUP + - name: second_vswitch + network: network-1152 + type: STANDARD_PORTGROUP + type: list +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "list": { + "query": { + "datacenters": "datacenters", + "folders": "folders", + "names": "names", + "networks": "networks", + "types": "types", + }, + "body": {}, + "path": {}, + } +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["datacenters"] = { + "aliases": ["filter_datacenters"], + "type": "list", + "elements": "str", + } + argument_spec["folders"] = { + "aliases": ["filter_folders"], + "type": "list", + "elements": "str", + } + argument_spec["names"] = { + "aliases": ["filter_names"], + "type": "list", + "elements": "str", + } + argument_spec["networks"] = {"type": "list", "elements": "str"} + argument_spec["types"] = { + "aliases": ["filter_types"], + "type": "list", + "elements": "str", + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_list_and_get_module.j2 +def build_url(params): + _in_query_parameters = PAYLOAD_FORMAT["list"]["query"].keys() + return ("https://{vcenter_hostname}" "/api/vcenter/network").format( + **params + ) + gen_args(params, _in_query_parameters) + + +async def entry_point(module, session): + url = build_url(module.params) + async with session.get(url, **session_timeout(module.params)) as resp: + _json = await resp.json() + + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_ovf_libraryitem.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_ovf_libraryitem.py new file mode 100644 index 00000000..721c2653 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_ovf_libraryitem.py @@ -0,0 +1,551 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_ovf_libraryitem +short_description: Creates a library item in content library from a virtual machine + or virtual appliance +description: Creates a library item in content library from a virtual machine or virtual + appliance. <p> This {@term operation} creates a library item in content library + whose content is an OVF package derived from a source virtual machine or virtual + appliance, using the supplied create specification. The OVF package may be stored + as in a newly created library item or in an in an existing library item. For an + existing library item whose content is updated by this {@term operation}, the original + content is overwritten. Meta data such as name and description is not updated for + the exisitng library item. </p> +options: + client_token: + description: + - Client-generated token used to retry a request if the client fails to get a + response from the server. If the original request succeeded, the result of that + request will be returned, otherwise the operation will be retried. + type: str + create_spec: + description: + - Information used to create the OVF package from the source virtual machine or + virtual appliance. Required with I(state=['present']) + - 'Valid attributes are:' + - ' - C(name) (str): Name to use in the OVF descriptor stored in the library item. + ([''present''])' + - ' - C(description) (str): Description to use in the OVF descriptor stored in + the library item. ([''present''])' + - ' - C(flags) (list): Flags to use for OVF package creation. The supported flags + can be obtained using {@link ExportFlag#list}. ([''present''])' + type: dict + deployment_spec: + description: + - Specification of how the OVF package should be deployed to the target. Required + with I(state=['deploy']) + - 'Valid attributes are:' + - ' - C(name) (str): Name assigned to the deployed target virtual machine or virtual + appliance. ([''deploy''])' + - ' - C(annotation) (str): Annotation assigned to the deployed target virtual + machine or virtual appliance. ([''deploy''])' + - ' - C(accept_all_EULA) (bool): Whether to accept all End User License Agreements. + ([''deploy''])' + - ' This key is required with [''deploy''].' + - ' - C(network_mappings) (dict): Specification of the target network to use for + sections of type ovf:NetworkSection in the OVF descriptor. The key in the {@term + map} is the section identifier of the ovf:NetworkSection section in the OVF + descriptor and the value is the target network to be used for deployment. ([''deploy''])' + - ' - C(storage_mappings) (dict): Specification of the target storage to use for + sections of type vmw:StorageGroupSection in the OVF descriptor. The key in the + {@term map} is the section identifier of the ovf:StorageGroupSection section + in the OVF descriptor and the value is the target storage specification to be + used for deployment. ([''deploy''])' + - ' - C(storage_provisioning) (str): The C(disk_provisioning_type) defines the + virtual disk provisioning types that can be set for a disk on the target platform. + ([''deploy''])' + - ' - Accepted values:' + - ' - eagerZeroedThick' + - ' - thick' + - ' - thin' + - ' - C(storage_profile_id) (str): Default storage profile to use for all sections + of type vmw:StorageSection in the OVF descriptor. ([''deploy''])' + - ' - C(locale) (str): The locale to use for parsing the OVF descriptor. ([''deploy''])' + - ' - C(flags) (list): Flags to be use for deployment. The supported flag values + can be obtained using {@link ImportFlag#list}. ([''deploy''])' + - ' - C(additional_parameters) (list): Additional OVF parameters that may be needed + for the deployment. Additional OVF parameters may be required by the OVF descriptor + of the OVF package in the library item. Examples of OVF parameters that can + be specified through this field include, but are not limited to: <ul> <li>{@link + DeploymentOptionParams}</li> <li>{@link ExtraConfigParams}</li> <li>{@link IpAllocationParams}</li> + <li>{@link PropertyParams}</li> <li>{@link ScaleOutParams}</li> <li>{@link VcenterExtensionParams}</li> + </ul> ([''deploy''])' + - ' - C(default_datastore_id) (str): Default datastore to use for all sections + of type vmw:StorageSection in the OVF descriptor. ([''deploy''])' + type: dict + ovf_library_item_id: + description: + - Identifier of the content library item containing the OVF package to be deployed. + Required with I(state=['deploy', 'filter']) + type: str + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + source: + description: + - Identifier of the virtual machine or virtual appliance to use as the source. + Required with I(state=['present']) + - 'Valid attributes are:' + - ' - C(type) (str): Type of the deployable resource. ([''present''])' + - ' This key is required with [''present''].' + - ' - C(id) (str): Identifier of the deployable resource. ([''present''])' + - ' This key is required with [''present''].' + type: dict + state: + choices: + - deploy + - filter + - present + default: present + description: [] + type: str + target: + description: + - Specification of the target content library and library item. This parameter + is mandatory. + - 'Valid attributes are:' + - ' - C(library_id) (str): Identifier of the library in which a new library item + should be created. This field is not used if the C(#library_item_id) field is + specified. ([''present''])' + - ' - C(library_item_id) (str): Identifier of the library item that should be + should be updated. ([''present''])' + - ' - C(resource_pool_id) (str): Identifier of the resource pool to which the + virtual machine or virtual appliance should be attached. ([''deploy'', ''filter''])' + - ' This key is required with [''deploy'', ''filter''].' + - ' - C(host_id) (str): Identifier of the target host on which the virtual machine + or virtual appliance will run. The target host must be a member of the cluster + that contains the resource pool identified by {@link #resourcePoolId}. ([''deploy'', + ''filter''])' + - ' - C(folder_id) (str): Identifier of the vCenter folder that should contain + the virtual machine or virtual appliance. The folder must be virtual machine + folder. ([''deploy'', ''filter''])' + required: true + type: dict + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Create a VM + vmware.vmware_rest.vcenter_vm: + placement: + cluster: "{{ lookup('vmware.vmware_rest.cluster_moid', '/my_dc/host/my_cluster')\ + \ }}" + datastore: "{{ lookup('vmware.vmware_rest.datastore_moid', '/my_dc/datastore/rw_datastore')\ + \ }}" + folder: "{{ lookup('vmware.vmware_rest.folder_moid', '/my_dc/vm') }}" + resource_pool: "{{ lookup('vmware.vmware_rest.resource_pool_moid', '/my_dc/host/my_cluster/Resources')\ + \ }}" + name: test_vm1 + guest_OS: DEBIAN_8_64 + hardware_version: VMX_11 + memory: + hot_add_enabled: true + size_MiB: 1024 + register: my_vm + +- name: Create a content library pointing on a NFS share + vmware.vmware_rest.content_locallibrary: + name: my_library_on_nfs + description: automated + publish_info: + published: true + authentication_method: NONE + storage_backings: + - storage_uri: nfs://datastore.test/srv/share/content-library + type: OTHER + state: present + register: nfs_lib + +- name: Export the VM as an OVF on the library + vmware.vmware_rest.vcenter_ovf_libraryitem: + session_timeout: 2900 + source: + type: VirtualMachine + id: '{{ my_vm.id }}' + target: + library_id: '{{ nfs_lib.id }}' + create_spec: + name: my_vm + description: an OVF example + flags: [] + state: present + register: ovf_item + +- name: Create a new VM from the OVF + vmware.vmware_rest.vcenter_ovf_libraryitem: + session_timeout: 2900 + ovf_library_item_id: '{{ (lib_items.value|selectattr("name", "equalto", "my_vm")|first).id + }}' + state: deploy + target: + resource_pool_id: "{{ lookup('vmware.vmware_rest.resource_pool_moid', '/my_dc/host/my_cluster/Resources')\ + \ }}" + deployment_spec: + name: my_vm_from_ovf + accept_all_EULA: true + storage_provisioning: thin + +- name: Create a new VM from the OVF and specify the host and folder + vmware.vmware_rest.vcenter_ovf_libraryitem: + session_timeout: 2900 + ovf_library_item_id: '{{ (lib_items.value|selectattr("name", "equalto", "my_vm")|first).id + }}' + state: deploy + target: + resource_pool_id: "{{ lookup('vmware.vmware_rest.resource_pool_moid', '/my_dc/host/my_cluster/Resources')\ + \ }}" + folder_id: "{{ lookup('vmware.vmware_rest.folder_moid', '/my_dc/vm') }}" + host_id: "{{ lookup('vmware.vmware_rest.host_moid', '/my_dc/host/my_cluster/esxi1.test/test_vm1')\ + \ }}" + deployment_spec: + name: my_vm_from_ovf_on_a_host + accept_all_EULA: true + storage_provisioning: thin +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Create a new VM from the OVF and specify the host and folder +value: + description: Create a new VM from the OVF and specify the host and folder + returned: On success + sample: + error: + errors: [] + information: [] + warnings: [] + resource_id: + id: vm-1211 + type: VirtualMachine + succeeded: 1 + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "deploy": { + "query": {"client_token": "client_token"}, + "body": {"deployment_spec": "deployment_spec", "target": "target"}, + "path": {"ovf_library_item_id": "ovf_library_item_id"}, + }, + "create": { + "query": {"client_token": "client_token"}, + "body": {"create_spec": "create_spec", "source": "source", "target": "target"}, + "path": {}, + }, + "filter": { + "query": {}, + "body": {"target": "target"}, + "path": {"ovf_library_item_id": "ovf_library_item_id"}, + }, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["client_token"] = {"no_log": True, "type": "str"} + argument_spec["create_spec"] = {"type": "dict"} + argument_spec["deployment_spec"] = {"type": "dict"} + argument_spec["ovf_library_item_id"] = {"type": "str"} + argument_spec["source"] = {"type": "dict"} + argument_spec["state"] = { + "type": "str", + "choices": ["deploy", "filter", "present"], + "default": "present", + } + argument_spec["target"] = {"required": True, "type": "dict"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/vcenter/ovf/library-item").format( + **params + ) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _create(params, session): + + library_id = ( + params["target"]["library_id"] if "library_id" in params["target"] else None + ) + lookup_url = f"https://{params['vcenter_hostname']}/api/content/library/item?library_id={library_id}" + per_id_url = "https://{vcenter_hostname}/api/content/library/item".format(**params) + uniquity_keys = None + + def comp_func(device): + return device["value"]["name"] == params["create_spec"].get("name") + + _json = None + + if not _json and (uniquity_keys or comp_func): + _json = await exists( + params, + session, + url=lookup_url, + uniquity_keys=uniquity_keys, + per_id_url=per_id_url, + comp_func=comp_func, + ) + + if _json: + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + if "_update" in globals(): + params["None"] = _json["id"] + return await globals()["_update"](params, session) + + return await update_changed_flag(_json, 200, "get") + + payload = prepare_payload(params, PAYLOAD_FORMAT["create"]) + _url = ("https://{vcenter_hostname}" "/api/vcenter/ovf/library-item").format( + **params + ) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + if resp.status == 500: + text = await resp.text() + raise EmbeddedModuleFailure( + f"Request has failed: status={resp.status}, {text}" + ) + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + + if (resp.status in [200, 201]) and "error" not in _json: + if isinstance(_json, str): # 7.0.2 and greater + _id = _json # TODO: fetch the object + elif isinstance(_json, dict) and "value" not in _json: + _id = list(_json["value"].values())[0] + elif isinstance(_json, dict) and "value" in _json: + _id = _json["value"] + _json_device_info = await get_device_info(session, _url, _id) + if _json_device_info: + _json = _json_device_info + + return await update_changed_flag(_json, resp.status, "create") + + +async def _deploy(params, session): + _in_query_parameters = PAYLOAD_FORMAT["deploy"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["deploy"]) + subdevice_type = get_subdevice_type( + "/api/vcenter/ovf/library-item/{ovf_library_item_id}?action=deploy" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/vcenter/ovf/library-item/{ovf_library_item_id}?action=deploy" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "deploy") + + +async def _filter(params, session): + _in_query_parameters = PAYLOAD_FORMAT["filter"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["filter"]) + subdevice_type = get_subdevice_type( + "/api/vcenter/ovf/library-item/{ovf_library_item_id}?action=filter" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/vcenter/ovf/library-item/{ovf_library_item_id}?action=filter" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "filter") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_resourcepool.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_resourcepool.py new file mode 100644 index 00000000..dd670de0 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_resourcepool.py @@ -0,0 +1,536 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_resourcepool +short_description: Creates a resource pool. +description: Creates a resource pool. +options: + cpu_allocation: + description: + - Resource allocation for CPU. + - 'Valid attributes are:' + - ' - C(reservation) (int): Amount of resource that is guaranteed available to + a resource pool. Reserved resources are not wasted if they are not used. If + the utilization is less than the reservation, the resources can be utilized + by other running virtual machines. Units are MB fo memory, and MHz for CPU. + ([''present''])' + - ' - C(expandable_reservation) (bool): In a resource pool with an expandable + reservation, the reservation can grow beyond the specified value, if the parent + resource pool has unreserved resources. A non-expandable reservation is called + a fixed reservation. ([''present''])' + - ' - C(limit) (int): The utilization of a resource pool will not exceed this + limit, even if there are available resources. This is typically used to ensure + a consistent performance of resource pools independent of available resources. + If set to -1, then there is no fixed limit on resource usage (only bounded by + available resources and shares). Units are MB for memory, and MHz for CPU. ([''present''])' + - ' - C(shares) (dict): Shares are used in case of resource contention. ([''present''])' + - ' - Accepted keys:' + - ' - level (string): The C(level) defines the possible values for the allocation + level.' + - 'Accepted value for this field:' + - ' - C(CUSTOM)' + - ' - C(HIGH)' + - ' - C(LOW)' + - ' - C(NORMAL)' + - ' - shares (integer): When {@link #level} is set to CUSTOM, it is the number + of shares allocated. Otherwise, this value is ignored. There is no unit for + this value. It is a relative measure based on the settings for other resource + pools.' + type: dict + memory_allocation: + description: + - Resource allocation for CPU. + - 'Valid attributes are:' + - ' - C(reservation) (int): Amount of resource that is guaranteed available to + a resource pool. Reserved resources are not wasted if they are not used. If + the utilization is less than the reservation, the resources can be utilized + by other running virtual machines. Units are MB fo memory, and MHz for CPU. + ([''present''])' + - ' - C(expandable_reservation) (bool): In a resource pool with an expandable + reservation, the reservation can grow beyond the specified value, if the parent + resource pool has unreserved resources. A non-expandable reservation is called + a fixed reservation. ([''present''])' + - ' - C(limit) (int): The utilization of a resource pool will not exceed this + limit, even if there are available resources. This is typically used to ensure + a consistent performance of resource pools independent of available resources. + If set to -1, then there is no fixed limit on resource usage (only bounded by + available resources and shares). Units are MB for memory, and MHz for CPU. ([''present''])' + - ' - C(shares) (dict): Shares are used in case of resource contention. ([''present''])' + - ' - Accepted keys:' + - ' - level (string): The C(level) defines the possible values for the allocation + level.' + - 'Accepted value for this field:' + - ' - C(CUSTOM)' + - ' - C(HIGH)' + - ' - C(LOW)' + - ' - C(NORMAL)' + - ' - shares (integer): When {@link #level} is set to CUSTOM, it is the number + of shares allocated. Otherwise, this value is ignored. There is no unit for + this value. It is a relative measure based on the settings for other resource + pools.' + type: dict + name: + description: + - Name of the resource pool. Required with I(state=['present']) + type: str + parent: + description: + - Parent of the created resource pool. Required with I(state=['present']) + type: str + resource_pool: + description: + - Identifier of the resource pool to be deleted. Required with I(state=['absent', + 'present']) + type: str + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - absent + - present + default: present + description: [] + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.3.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Get the existing resource pools + vmware.vmware_rest.vcenter_resourcepool_info: + register: resource_pools + +- name: Create an Ad hoc resource pool + vmware.vmware_rest.vcenter_resourcepool: + name: my_resource_pool + parent: '{{ resource_pools.value[0].resource_pool }}' + cpu_allocation: + expandable_reservation: true + limit: 40 + reservation: 0 + shares: + level: NORMAL + memory_allocation: + expandable_reservation: false + limit: 2000 + reservation: 0 + shares: + level: NORMAL + register: my_resource_pool + +- name: Remove a resource pool + vmware.vmware_rest.vcenter_resourcepool: + resource_pool: '{{ my_resource_pool.id }}' + state: absent + +- name: Create a generic resource pool + vmware.vmware_rest.vcenter_resourcepool: + name: my_resource_pool + parent: '{{ resource_pools.value[0].resource_pool }}' + register: my_resource_pool + +- name: Modify a resource pool + vmware.vmware_rest.vcenter_resourcepool: + resource_pool: '{{ my_resource_pool.id }}' + cpu_allocation: + expandable_reservation: true + limit: -1 + reservation: 0 + shares: + level: NORMAL + memory_allocation: + expandable_reservation: false + limit: 1000 + reservation: 0 + shares: + level: NORMAL +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Create a generic resource pool +id: + description: moid of the resource + returned: On success + sample: resgroup-1143 + type: str +value: + description: Create a generic resource pool + returned: On success + sample: + cpu_allocation: + expandable_reservation: 1 + limit: -1 + reservation: 0 + shares: + level: NORMAL + memory_allocation: + expandable_reservation: 1 + limit: -1 + reservation: 0 + shares: + level: NORMAL + name: my_resource_pool + resource_pools: [] + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "delete": {"query": {}, "body": {}, "path": {"resource_pool": "resource_pool"}}, + "create": { + "query": {}, + "body": { + "cpu_allocation": "cpu_allocation", + "memory_allocation": "memory_allocation", + "name": "name", + "parent": "parent", + }, + "path": {}, + }, + "update": { + "query": {}, + "body": { + "cpu_allocation": "cpu_allocation", + "memory_allocation": "memory_allocation", + "name": "name", + }, + "path": {"resource_pool": "resource_pool"}, + }, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["cpu_allocation"] = {"type": "dict"} + argument_spec["memory_allocation"] = {"type": "dict"} + argument_spec["name"] = {"type": "str"} + argument_spec["parent"] = {"type": "str"} + argument_spec["resource_pool"] = {"type": "str"} + argument_spec["state"] = { + "type": "str", + "choices": ["absent", "present"], + "default": "present", + } + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/vcenter/resource-pool").format(**params) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _create(params, session): + + lookup_url = per_id_url = build_url(params) + uniquity_keys = ["resource_pool"] + comp_func = None + + async def lookup_with_filters(params, session, url): + # e.g: for the datacenter resources + if "folder" not in params: + return + if "name" not in params: + return + async with session.get( + f"{url}?names={params['name']}&folders={params['folder']}" + ) as resp: + _json = await resp.json() + if isinstance(_json, list) and len(_json) == 1: + return await get_device_info(session, url, _json[0]["resource_pool"]) + + _json = None + + if params["resource_pool"]: + _json = await get_device_info( + session, build_url(params), params["resource_pool"] + ) + + if not _json and (uniquity_keys or comp_func): + _json = await exists( + params, + session, + url=lookup_url, + uniquity_keys=uniquity_keys, + per_id_url=per_id_url, + comp_func=comp_func, + ) + + if not _json: + _json = await lookup_with_filters(params, session, build_url(params)) + + if _json: + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + if "_update" in globals(): + params["resource_pool"] = _json["id"] + return await globals()["_update"](params, session) + + return await update_changed_flag(_json, 200, "get") + + payload = prepare_payload(params, PAYLOAD_FORMAT["create"]) + _url = ("https://{vcenter_hostname}" "/api/vcenter/resource-pool").format(**params) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + if resp.status == 500: + text = await resp.text() + raise EmbeddedModuleFailure( + f"Request has failed: status={resp.status}, {text}" + ) + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + + if (resp.status in [200, 201]) and "error" not in _json: + if isinstance(_json, str): # 7.0.2 and greater + _id = _json # TODO: fetch the object + elif isinstance(_json, dict) and "value" not in _json: + _id = list(_json["value"].values())[0] + elif isinstance(_json, dict) and "value" in _json: + _id = _json["value"] + _json_device_info = await get_device_info(session, _url, _id) + if _json_device_info: + _json = _json_device_info + + return await update_changed_flag(_json, resp.status, "create") + + +async def _delete(params, session): + _in_query_parameters = PAYLOAD_FORMAT["delete"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["delete"]) + subdevice_type = get_subdevice_type("/api/vcenter/resource-pool/{resource_pool}") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" "/api/vcenter/resource-pool/{resource_pool}" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.delete(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "delete") + + +async def _update(params, session): + payload = prepare_payload(params, PAYLOAD_FORMAT["update"]) + _url = ( + "https://{vcenter_hostname}" "/api/vcenter/resource-pool/{resource_pool}" + ).format(**params) + async with session.get(_url, **session_timeout(params)) as resp: + _json = await resp.json() + if "value" in _json: + value = _json["value"] + else: # 7.0.2 and greater + value = _json + for k, v in value.items(): + if k in payload: + if isinstance(payload[k], dict) and isinstance(v, dict): + to_delete = True + for _k in list(payload[k].keys()): + if payload[k][_k] != v.get(_k): + to_delete = False + if to_delete: + del payload[k] + elif payload[k] == v: + del payload[k] + elif payload[k] == {}: + del payload[k] + + if payload == {} or payload == {"spec": {}}: + # Nothing has changed + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + _json["id"] = params.get("resource_pool") + return await update_changed_flag(_json, resp.status, "get") + async with session.patch(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # e.g: content_configuration + if not _json and resp.status == 204: + async with session.get(_url, **session_timeout(params)) as resp_get: + _json_get = await resp_get.json() + if _json_get: + _json = _json_get + + _json["id"] = params.get("resource_pool") + return await update_changed_flag(_json, resp.status, "update") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_resourcepool_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_resourcepool_info.py new file mode 100644 index 00000000..11b6df5d --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_resourcepool_info.py @@ -0,0 +1,338 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_resourcepool_info +short_description: Retrieves information about the resource pool indicated by {@param.name + resourcePool}. +description: Retrieves information about the resource pool indicated by {@param.name + resourcePool}. +options: + clusters: + description: + - Clusters that must contain the resource pool for the resource pool to match + the filter. + elements: str + type: list + datacenters: + aliases: + - filter_datacenters + description: + - Datacenters that must contain the resource pool for the resource pool to match + the filter. + elements: str + type: list + hosts: + description: + - Hosts that must contain the resource pool for the resource pool to match the + filter. + elements: str + type: list + names: + aliases: + - filter_names + description: + - Names that resource pools must have to match the filter (see {@link Info#name}). + elements: str + type: list + parent_resource_pools: + description: + - Resource pools that must contain the resource pool for the resource pool to + match the filter. + elements: str + type: list + resource_pool: + description: + - Identifier of the resource pool for which information should be retrieved. Required + with I(state=['get']) + type: str + resource_pools: + description: + - Identifiers of resource pools that can match the filter. + elements: str + type: list + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.3.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Get the existing resource pools + vmware.vmware_rest.vcenter_resourcepool_info: + register: resource_pools + +- name: Get the existing resource pool + vmware.vmware_rest.vcenter_resourcepool_info: + resource_pool: '{{ resource_pools.value[0].resource_pool }}' + register: my_resource_pool + +- name: Create a generic resource pool + vmware.vmware_rest.vcenter_resourcepool: + name: my_resource_pool + parent: '{{ resource_pools.value[0].resource_pool }}' + register: my_resource_pool + +- name: Read details from a specific resource pool + vmware.vmware_rest.vcenter_resourcepool_info: + resource_pool: '{{ my_resource_pool.id }}' + register: my_resource_pool +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Read details from a specific resource pool +id: + description: moid of the resource + returned: On success + sample: resgroup-1143 + type: str +value: + description: Read details from a specific resource pool + returned: On success + sample: + cpu_allocation: + expandable_reservation: 1 + limit: -1 + reservation: 0 + shares: + level: NORMAL + memory_allocation: + expandable_reservation: 0 + limit: 1000 + reservation: 0 + shares: + level: NORMAL + name: my_resource_pool + resource_pools: [] + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"resource_pool": "resource_pool"}}, + "list": { + "query": { + "clusters": "clusters", + "datacenters": "datacenters", + "hosts": "hosts", + "names": "names", + "parent_resource_pools": "parent_resource_pools", + "resource_pools": "resource_pools", + }, + "body": {}, + "path": {}, + }, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["clusters"] = {"type": "list", "elements": "str"} + argument_spec["datacenters"] = { + "aliases": ["filter_datacenters"], + "type": "list", + "elements": "str", + } + argument_spec["hosts"] = {"type": "list", "elements": "str"} + argument_spec["names"] = { + "aliases": ["filter_names"], + "type": "list", + "elements": "str", + } + argument_spec["parent_resource_pools"] = {"type": "list", "elements": "str"} + argument_spec["resource_pool"] = {"type": "str"} + argument_spec["resource_pools"] = {"type": "list", "elements": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_list_and_get_module.j2 +def build_url(params): + if params.get("resource_pool"): + _in_query_parameters = PAYLOAD_FORMAT["get"]["query"].keys() + return ( + ("https://{vcenter_hostname}" "/api/vcenter/resource-pool/").format( + **params + ) + + params["resource_pool"] + + gen_args(params, _in_query_parameters) + ) + _in_query_parameters = PAYLOAD_FORMAT["list"]["query"].keys() + return ("https://{vcenter_hostname}" "/api/vcenter/resource-pool").format( + **params + ) + gen_args(params, _in_query_parameters) + + +async def entry_point(module, session): + url = build_url(module.params) + async with session.get(url, **session_timeout(module.params)) as resp: + _json = await resp.json() + + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + + if module.params.get("resource_pool"): + _json["id"] = module.params.get("resource_pool") + elif module.params.get("label"): # TODO extend the list of filter + _json = await exists(module.params, session, url) + elif ( + isinstance(_json["value"], list) + and len(_json["value"]) > 0 + and isinstance(_json["value"][0], str) + ): + # this is a list of id, we fetch the details + full_device_list = await build_full_device_list(session, url, _json) + _json = {"value": [i["value"] for i in full_device_list]} + + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_storage_policies_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_storage_policies_info.py new file mode 100644 index 00000000..3ab2c253 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_storage_policies_info.py @@ -0,0 +1,254 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_storage_policies_info +short_description: Returns information about at most 1024 visible (subject to permission + checks) storage solicies availabe in vCenter +description: Returns information about at most 1024 visible (subject to permission + checks) storage solicies availabe in vCenter. These storage policies can be used + for provisioning virtual machines or disks. +options: + policies: + description: + - Identifiers of storage policies that can match the filter. + elements: str + type: list + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.3.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: List existing storage policies + vmware.vmware_rest.vcenter_storage_policies_info: + register: storage_policies +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: List existing storage policies +value: + description: List existing storage policies + returned: On success + sample: + - description: Management Storage policy used for VMC large cluster + name: Management Storage Policy - Large + policy: cd8f7c94-3e11-67fc-17f5-4e96d91a5beb + - description: Allow the datastore to determine the best placement strategy for + storage objects + name: VVol No Requirements Policy + policy: f4e5bade-15a2-4805-bf8e-52318c4ce443 + - description: Management Storage policy used for smaller VMC Stretched Cluster + configuration. + name: Management Storage Policy - Stretched Lite + policy: d109de24-c966-428f-8da2-d281e6671e35 + - description: Sample storage policy for VMware's VM and virtual disk encryption + name: VM Encryption Policy + policy: 4d5f673c-536f-11e6-beb8-9e71128cae77 + - description: Management Storage policy used for encrypting VM + name: Management Storage policy - Encryption + policy: b1263970-8662-69e2-adc6-fa8ae01abecc + - description: Management Storage policy used for VMC single node cluster + name: Management Storage Policy - Single Node + policy: a9423670-7455-11e8-adc0-fa7ae01bbebc + - description: Storage policy used as default for Host-local PMem datastores + name: Host-local PMem Default Storage Policy + policy: c268da1b-b343-49f7-a468-b1deeb7078e0 + - description: Storage policy used as default for vSAN datastores + name: vSAN Default Storage Policy + policy: aa6d5a82-1c88-45da-85d3-3d74b91a5bad + - description: Management Storage policy used for VMC regular cluster + name: Management Storage Policy - Regular + policy: bb7e6b13-2d99-46eb-96e4-3d85c91a5bde + - description: Management Storage policy used for VMC regular cluster which requires + THIN provisioning + name: Management Storage policy - Thin + policy: b6423670-8552-66e8-adc1-fa6ae01abeac + - description: Management Storage policy used for VMC stretched cluster + name: Management Storage Policy - Stretched + policy: f31f2442-8247-4517-87c2-8d69d7a6c696 + type: list +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "list": {"query": {"policies": "policies"}, "body": {}, "path": {}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["policies"] = {"type": "list", "elements": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_list_and_get_module.j2 +def build_url(params): + _in_query_parameters = PAYLOAD_FORMAT["list"]["query"].keys() + return ("https://{vcenter_hostname}" "/api/vcenter/storage/policies").format( + **params + ) + gen_args(params, _in_query_parameters) + + +async def entry_point(module, session): + url = build_url(module.params) + async with session.get(url, **session_timeout(module.params)) as resp: + _json = await resp.json() + + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm.py new file mode 100644 index 00000000..cf29a255 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm.py @@ -0,0 +1,1826 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm +short_description: Creates a virtual machine. +description: Creates a virtual machine. +options: + bios_uuid: + description: + - 128-bit SMBIOS UUID of a virtual machine represented as a hexadecimal string + in "12345678-abcd-1234-cdef-123456789abc" format. + type: str + boot: + description: + - Boot configuration. + - 'Valid attributes are:' + - ' - C(type) (str): The C(type) defines the valid firmware types for a virtual + machine. ([''present''])' + - ' - Accepted values:' + - ' - BIOS' + - ' - EFI' + - ' - C(efi_legacy_boot) (bool): Flag indicating whether to use EFI legacy boot + mode. ([''present''])' + - ' - C(network_protocol) (str): The C(network_protocol) defines the valid network + boot protocols supported when booting a virtual machine with {@link Type#EFI} + firmware over the network. ([''present''])' + - ' - Accepted values:' + - ' - IPV4' + - ' - IPV6' + - ' - C(delay) (int): Delay in milliseconds before beginning the firmware boot + process when the virtual machine is powered on. This delay may be used to provide + a time window for users to connect to the virtual machine console and enter + BIOS setup mode. ([''present''])' + - ' - C(retry) (bool): Flag indicating whether the virtual machine should automatically + retry the boot process after a failure. ([''present''])' + - ' - C(retry_delay) (int): Delay in milliseconds before retrying the boot process + after a failure; applicable only when {@link Info#retry} is true. ([''present''])' + - ' - C(enter_setup_mode) (bool): Flag indicating whether the firmware boot process + should automatically enter setup mode the next time the virtual machine boots. Note + that this flag will automatically be reset to false once the virtual machine + enters setup mode. ([''present''])' + type: dict + boot_devices: + description: + - Boot device configuration. + - 'Valid attributes are:' + - ' - C(type) (str): The C(type) defines the valid device types that may be used + as bootable devices. ([''present''])' + - ' This key is required with [''present''].' + - ' - Accepted values:' + - ' - CDROM' + - ' - DISK' + - ' - ETHERNET' + - ' - FLOPPY' + elements: dict + type: list + cdroms: + description: + - List of CD-ROMs. + - 'Valid attributes are:' + - ' - C(type) (str): The C(host_bus_adapter_type) defines the valid types of host + bus adapters that may be used for attaching a Cdrom to a virtual machine. ([''present''])' + - ' - Accepted values:' + - ' - IDE' + - ' - SATA' + - ' - C(ide) (dict): Address for attaching the device to a virtual IDE adapter. + ([''present''])' + - ' - Accepted keys:' + - ' - primary (boolean): Flag specifying whether the device should be attached + to the primary or secondary IDE adapter of the virtual machine.' + - ' - master (boolean): Flag specifying whether the device should be the master + or slave device on the IDE adapter.' + - ' - C(sata) (dict): Address for attaching the device to a virtual SATA adapter. + ([''present''])' + - ' - Accepted keys:' + - ' - bus (integer): Bus number of the adapter to which the device should + be attached.' + - ' - unit (integer): Unit number of the device.' + - ' - C(backing) (dict): Physical resource backing for the virtual CD-ROM device. + ([''present''])' + - ' - Accepted keys:' + - ' - type (string): The C(backing_type) defines the valid backing types for + a virtual CD-ROM device.' + - 'Accepted value for this field:' + - ' - C(CLIENT_DEVICE)' + - ' - C(HOST_DEVICE)' + - ' - C(ISO_FILE)' + - ' - iso_file (string): Path of the image file that should be used as the + virtual CD-ROM device backing.' + - ' - host_device (string): Name of the device that should be used as the + virtual CD-ROM device backing.' + - ' - device_access_type (string): The C(device_access_type) defines the valid + device access types for a physical device packing of a virtual CD-ROM device.' + - 'Accepted value for this field:' + - ' - C(EMULATION)' + - ' - C(PASSTHRU)' + - ' - C(PASSTHRU_EXCLUSIVE)' + - ' - C(start_connected) (bool): Flag indicating whether the virtual device should + be connected whenever the virtual machine is powered on. ([''present''])' + - ' - C(allow_guest_control) (bool): Flag indicating whether the guest can connect + and disconnect the device. ([''present''])' + elements: dict + type: list + cpu: + description: + - CPU configuration. + - 'Valid attributes are:' + - ' - C(count) (int): New number of CPU cores. The number of CPU cores in the + virtual machine must be a multiple of the number of cores per socket. The supported + range of CPU counts is constrained by the configured guest operating system + and virtual hardware version of the virtual machine. If the virtual machine + is running, the number of CPU cores may only be increased if {@link Info#hotAddEnabled} + is true, and may only be decreased if {@link Info#hotRemoveEnabled} is true. + ([''present''])' + - ' - C(cores_per_socket) (int): New number of CPU cores per socket. The number + of CPU cores in the virtual machine must be a multiple of the number of cores + per socket. ([''present''])' + - ' - C(hot_add_enabled) (bool): Flag indicating whether adding CPUs while the + virtual machine is running is enabled. This field may only be modified if the + virtual machine is powered off. ([''present''])' + - ' - C(hot_remove_enabled) (bool): Flag indicating whether removing CPUs while + the virtual machine is running is enabled. This field may only be modified if + the virtual machine is powered off. ([''present''])' + type: dict + datastore: + description: + - Identifier of the datastore on which the virtual machine's configuration state + is stored. + type: str + datastore_path: + description: + - Datastore path for the virtual machine's configuration file in the format "[datastore + name] path". For example "[storage1] Test-VM/Test-VM.vmx". + type: str + disconnect_all_nics: + description: + - Indicates whether all NICs on the destination virtual machine should be disconnected + from the newtwork + type: bool + disks: + description: + - Individual disk relocation map. + - 'Valid attributes are:' + - ' - C(type) (str): The C(host_bus_adapter_type) defines the valid types of host + bus adapters that may be used for attaching a virtual storage device to a virtual + machine. ([''present''])' + - ' - Accepted values:' + - ' - IDE' + - ' - SATA' + - ' - SCSI' + - ' - C(ide) (dict): Address for attaching the device to a virtual IDE adapter. + ([''present''])' + - ' - Accepted keys:' + - ' - primary (boolean): Flag specifying whether the device should be attached + to the primary or secondary IDE adapter of the virtual machine.' + - ' - master (boolean): Flag specifying whether the device should be the master + or slave device on the IDE adapter.' + - ' - C(scsi) (dict): Address for attaching the device to a virtual SCSI adapter. + ([''present''])' + - ' - Accepted keys:' + - ' - bus (integer): Bus number of the adapter to which the device should + be attached.' + - ' - unit (integer): Unit number of the device.' + - ' - C(sata) (dict): Address for attaching the device to a virtual SATA adapter. + ([''present''])' + - ' - Accepted keys:' + - ' - bus (integer): Bus number of the adapter to which the device should + be attached.' + - ' - unit (integer): Unit number of the device.' + - ' - C(backing) (dict): Existing physical resource backing for the virtual disk. + Exactly one of C(#backing) or C(#new_vmdk) must be specified. ([''present''])' + - ' - Accepted keys:' + - ' - type (string): The C(backing_type) defines the valid backing types for + a virtual disk.' + - 'Accepted value for this field:' + - ' - C(VMDK_FILE)' + - ' - vmdk_file (string): Path of the VMDK file backing the virtual disk.' + - ' - C(new_vmdk) (dict): Specification for creating a new VMDK backing for the + virtual disk. Exactly one of C(#backing) or C(#new_vmdk) must be specified. + ([''present''])' + - ' - Accepted keys:' + - ' - name (string): Base name of the VMDK file. The name should not include + the ''.vmdk'' file extension.' + - ' - capacity (integer): Capacity of the virtual disk backing in bytes.' + - ' - storage_policy (object): The C(storage_policy_spec) {@term structure} + contains information about the storage policy that is to be associated the with + VMDK file.' + elements: dict + type: list + disks_to_remove: + description: + - Set of Disks to Remove. + elements: str + type: list + disks_to_update: + description: + - Map of Disks to Update. + type: dict + floppies: + description: + - List of floppy drives. + - 'Valid attributes are:' + - ' - C(backing) (dict): Physical resource backing for the virtual floppy drive. + ([''present''])' + - ' - Accepted keys:' + - ' - type (string): The C(backing_type) defines the valid backing types for + a virtual floppy drive.' + - 'Accepted value for this field:' + - ' - C(CLIENT_DEVICE)' + - ' - C(HOST_DEVICE)' + - ' - C(IMAGE_FILE)' + - ' - image_file (string): Path of the image file that should be used as the + virtual floppy drive backing.' + - ' - host_device (string): Name of the device that should be used as the + virtual floppy drive backing.' + - ' - C(start_connected) (bool): Flag indicating whether the virtual device should + be connected whenever the virtual machine is powered on. ([''present''])' + - ' - C(allow_guest_control) (bool): Flag indicating whether the guest can connect + and disconnect the device. ([''present''])' + elements: dict + type: list + guest_OS: + choices: + - AMAZONLINUX2_64 + - AMAZONLINUX3_64 + - ASIANUX_3 + - ASIANUX_3_64 + - ASIANUX_4 + - ASIANUX_4_64 + - ASIANUX_5_64 + - ASIANUX_7_64 + - ASIANUX_8_64 + - ASIANUX_9_64 + - CENTOS + - CENTOS_6 + - CENTOS_64 + - CENTOS_6_64 + - CENTOS_7 + - CENTOS_7_64 + - CENTOS_8_64 + - CENTOS_9_64 + - COREOS_64 + - CRXPOD_1 + - DARWIN + - DARWIN_10 + - DARWIN_10_64 + - DARWIN_11 + - DARWIN_11_64 + - DARWIN_12_64 + - DARWIN_13_64 + - DARWIN_14_64 + - DARWIN_15_64 + - DARWIN_16_64 + - DARWIN_17_64 + - DARWIN_18_64 + - DARWIN_19_64 + - DARWIN_20_64 + - DARWIN_21_64 + - DARWIN_64 + - DEBIAN_10 + - DEBIAN_10_64 + - DEBIAN_11 + - DEBIAN_11_64 + - DEBIAN_4 + - DEBIAN_4_64 + - DEBIAN_5 + - DEBIAN_5_64 + - DEBIAN_6 + - DEBIAN_6_64 + - DEBIAN_7 + - DEBIAN_7_64 + - DEBIAN_8 + - DEBIAN_8_64 + - DEBIAN_9 + - DEBIAN_9_64 + - DOS + - ECOMSTATION + - ECOMSTATION_2 + - FEDORA + - FEDORA_64 + - FREEBSD + - FREEBSD_11 + - FREEBSD_11_64 + - FREEBSD_12 + - FREEBSD_12_64 + - FREEBSD_13 + - FREEBSD_13_64 + - FREEBSD_64 + - GENERIC_LINUX + - MANDRAKE + - MANDRIVA + - MANDRIVA_64 + - NETWARE_4 + - NETWARE_5 + - NETWARE_6 + - NLD_9 + - OES + - OPENSERVER_5 + - OPENSERVER_6 + - OPENSUSE + - OPENSUSE_64 + - ORACLE_LINUX + - ORACLE_LINUX_6 + - ORACLE_LINUX_64 + - ORACLE_LINUX_6_64 + - ORACLE_LINUX_7 + - ORACLE_LINUX_7_64 + - ORACLE_LINUX_8_64 + - ORACLE_LINUX_9_64 + - OS2 + - OTHER + - OTHER_24X_LINUX + - OTHER_24X_LINUX_64 + - OTHER_26X_LINUX + - OTHER_26X_LINUX_64 + - OTHER_3X_LINUX + - OTHER_3X_LINUX_64 + - OTHER_4X_LINUX + - OTHER_4X_LINUX_64 + - OTHER_5X_LINUX + - OTHER_5X_LINUX_64 + - OTHER_64 + - OTHER_LINUX + - OTHER_LINUX_64 + - REDHAT + - RHEL_2 + - RHEL_3 + - RHEL_3_64 + - RHEL_4 + - RHEL_4_64 + - RHEL_5 + - RHEL_5_64 + - RHEL_6 + - RHEL_6_64 + - RHEL_7 + - RHEL_7_64 + - RHEL_8_64 + - RHEL_9_64 + - SJDS + - SLES + - SLES_10 + - SLES_10_64 + - SLES_11 + - SLES_11_64 + - SLES_12 + - SLES_12_64 + - SLES_15_64 + - SLES_16_64 + - SLES_64 + - SOLARIS_10 + - SOLARIS_10_64 + - SOLARIS_11_64 + - SOLARIS_6 + - SOLARIS_7 + - SOLARIS_8 + - SOLARIS_9 + - SUSE + - SUSE_64 + - TURBO_LINUX + - TURBO_LINUX_64 + - UBUNTU + - UBUNTU_64 + - UNIXWARE_7 + - VMKERNEL + - VMKERNEL_5 + - VMKERNEL_6 + - VMKERNEL_65 + - VMKERNEL_7 + - VMWARE_PHOTON_64 + - WINDOWS_7 + - WINDOWS_7_64 + - WINDOWS_7_SERVER_64 + - WINDOWS_8 + - WINDOWS_8_64 + - WINDOWS_8_SERVER_64 + - WINDOWS_9 + - WINDOWS_9_64 + - WINDOWS_9_SERVER_64 + - WINDOWS_HYPERV + - WINDOWS_SERVER_2019 + - WINDOWS_SERVER_2021 + - WIN_2000_ADV_SERV + - WIN_2000_PRO + - WIN_2000_SERV + - WIN_31 + - WIN_95 + - WIN_98 + - WIN_LONGHORN + - WIN_LONGHORN_64 + - WIN_ME + - WIN_NET_BUSINESS + - WIN_NET_DATACENTER + - WIN_NET_DATACENTER_64 + - WIN_NET_ENTERPRISE + - WIN_NET_ENTERPRISE_64 + - WIN_NET_STANDARD + - WIN_NET_STANDARD_64 + - WIN_NET_WEB + - WIN_NT + - WIN_VISTA + - WIN_VISTA_64 + - WIN_XP_HOME + - WIN_XP_PRO + - WIN_XP_PRO_64 + description: + - The C(guest_o_s) defines the valid guest operating system types used for configuring + a virtual machine. Required with I(state=['present']) + type: str + guest_customization_spec: + description: + - Guest customization spec to apply to the virtual machine after the virtual machine + is deployed. + - 'Valid attributes are:' + - ' - C(name) (str): Name of the customization specification. ([''clone''])' + type: dict + hardware_version: + choices: + - VMX_03 + - VMX_04 + - VMX_06 + - VMX_07 + - VMX_08 + - VMX_09 + - VMX_10 + - VMX_11 + - VMX_12 + - VMX_13 + - VMX_14 + - VMX_15 + - VMX_16 + - VMX_17 + - VMX_18 + - VMX_19 + description: + - The C(version) defines the valid virtual hardware versions for a virtual machine. + See https://kb.vmware.com/s/article/1003746 (Virtual machine hardware versions + (1003746)). + type: str + memory: + description: + - Memory configuration. + - 'Valid attributes are:' + - ' - C(size_MiB) (int): New memory size in mebibytes. The supported range of + memory sizes is constrained by the configured guest operating system and virtual + hardware version of the virtual machine. If the virtual machine is running, + this value may only be changed if {@link Info#hotAddEnabled} is true, and the + new memory size must satisfy the constraints specified by {@link Info#hotAddIncrementSizeMiB} + and {@link Info#hotAddLimitMiB}. ([''present''])' + - ' - C(hot_add_enabled) (bool): Flag indicating whether adding memory while the + virtual machine is running should be enabled. Some guest operating systems may + consume more resources or perform less efficiently when they run on hardware + that supports adding memory while the machine is running. This field may only + be modified if the virtual machine is not powered on. ([''present''])' + type: dict + name: + description: + - Name of the new virtual machine. + type: str + nics: + description: + - List of Ethernet adapters. + - 'Valid attributes are:' + - ' - C(type) (str): The C(emulation_type) defines the valid emulation types for + a virtual Ethernet adapter. ([''present''])' + - ' - Accepted values:' + - ' - E1000' + - ' - E1000E' + - ' - PCNET32' + - ' - VMXNET' + - ' - VMXNET2' + - ' - VMXNET3' + - ' - C(upt_compatibility_enabled) (bool): Flag indicating whether Universal Pass-Through + (UPT) compatibility is enabled on this virtual Ethernet adapter. ([''present''])' + - ' - C(mac_type) (str): The C(mac_address_type) defines the valid MAC address + origins for a virtual Ethernet adapter. ([''present''])' + - ' - Accepted values:' + - ' - ASSIGNED' + - ' - GENERATED' + - ' - MANUAL' + - ' - C(mac_address) (str): MAC address. ([''present''])' + - ' - C(pci_slot_number) (int): Address of the virtual Ethernet adapter on the + PCI bus. If the PCI address is invalid, the server will change when it the + VM is started or as the device is hot added. ([''present''])' + - ' - C(wake_on_lan_enabled) (bool): Flag indicating whether wake-on-LAN is enabled + on this virtual Ethernet adapter. ([''present''])' + - ' - C(backing) (dict): Physical resource backing for the virtual Ethernet adapter. + ([''present''])' + - ' - Accepted keys:' + - ' - type (string): The C(backing_type) defines the valid backing types for + a virtual Ethernet adapter.' + - 'Accepted value for this field:' + - ' - C(DISTRIBUTED_PORTGROUP)' + - ' - C(HOST_DEVICE)' + - ' - C(OPAQUE_NETWORK)' + - ' - C(STANDARD_PORTGROUP)' + - ' - network (string): Identifier of the network that backs the virtual Ethernet + adapter.' + - ' - distributed_port (string): Key of the distributed virtual port that + backs the virtual Ethernet adapter. Depending on the type of the Portgroup, + the port may be specified using this field. If the portgroup type is early-binding + (also known as static), a port is assigned when the Ethernet adapter is configured + to use the port. The port may be either automatically or specifically assigned + based on the value of this field. If the portgroup type is ephemeral, the port + is created and assigned to a virtual machine when it is powered on and the Ethernet + adapter is connected. This field cannot be specified as no free ports exist + before use.' + - ' - C(start_connected) (bool): Flag indicating whether the virtual device should + be connected whenever the virtual machine is powered on. ([''present''])' + - ' - C(allow_guest_control) (bool): Flag indicating whether the guest can connect + and disconnect the device. ([''present''])' + elements: dict + type: list + nics_to_update: + description: + - Map of NICs to update. + type: dict + parallel_ports: + description: + - List of parallel ports. + - 'Valid attributes are:' + - ' - C(backing) (dict): Physical resource backing for the virtual parallel port. + ([''present''])' + - ' - Accepted keys:' + - ' - type (string): The C(backing_type) defines the valid backing types for + a virtual parallel port.' + - 'Accepted value for this field:' + - ' - C(FILE)' + - ' - C(HOST_DEVICE)' + - ' - file (string): Path of the file that should be used as the virtual parallel + port backing.' + - ' - host_device (string): Name of the device that should be used as the + virtual parallel port backing.' + - ' - C(start_connected) (bool): Flag indicating whether the virtual device should + be connected whenever the virtual machine is powered on. ([''present''])' + - ' - C(allow_guest_control) (bool): Flag indicating whether the guest can connect + and disconnect the device. ([''present''])' + elements: dict + type: list + parallel_ports_to_update: + description: + - Map of parallel ports to Update. + type: dict + path: + description: + - 'Path to the virtual machine''s configuration file on the datastore corresponding + to {@link #datastore).' + type: str + placement: + description: + - Virtual machine placement information. + - 'Valid attributes are:' + - ' - C(folder) (str): Virtual machine folder into which the virtual machine should + be placed. ([''clone'', ''instant_clone'', ''present'', ''register'', ''relocate''])' + - ' - C(resource_pool) (str): Resource pool into which the virtual machine should + be placed. ([''clone'', ''instant_clone'', ''present'', ''register'', ''relocate''])' + - ' - C(host) (str): Host onto which the virtual machine should be placed. If + C(#host) and C(#resource_pool) are both specified, C(#resource_pool) must belong + to C(#host). If C(#host) and C(#cluster) are both specified, C(#host) must be + a member of C(#cluster). ([''clone'', ''present'', ''register'', ''relocate''])' + - ' - C(cluster) (str): Cluster into which the virtual machine should be placed. + If C(#cluster) and C(#resource_pool) are both specified, C(#resource_pool) must + belong to C(#cluster). If C(#cluster) and C(#host) are both specified, C(#host) + must be a member of C(#cluster). ([''clone'', ''present'', ''register'', ''relocate''])' + - ' - C(datastore) (str): Datastore on which the virtual machine''s configuration + state should be stored. This datastore will also be used for any virtual disks + that are associated with the virtual machine, unless individually overridden. + ([''clone'', ''instant_clone'', ''present'', ''relocate''])' + type: dict + power_on: + description: + - 'Attempt to perform a {@link #powerOn} after clone.' + type: bool + sata_adapters: + description: + - List of SATA adapters. + - 'Valid attributes are:' + - ' - C(type) (str): The C(type) defines the valid emulation types for a virtual + SATA adapter. ([''present''])' + - ' - Accepted values:' + - ' - AHCI' + - ' - C(bus) (int): SATA bus number. ([''present''])' + - ' - C(pci_slot_number) (int): Address of the SATA adapter on the PCI bus. ([''present''])' + elements: dict + type: list + scsi_adapters: + description: + - List of SCSI adapters. + - 'Valid attributes are:' + - ' - C(type) (str): The C(type) defines the valid emulation types for a virtual + SCSI adapter. ([''present''])' + - ' - Accepted values:' + - ' - BUSLOGIC' + - ' - LSILOGIC' + - ' - LSILOGICSAS' + - ' - PVSCSI' + - ' - C(bus) (int): SCSI bus number. ([''present''])' + - ' - C(pci_slot_number) (int): Address of the SCSI adapter on the PCI bus. If + the PCI address is invalid, the server will change it when the VM is started + or as the device is hot added. ([''present''])' + - ' - C(sharing) (str): The C(sharing) defines the valid bus sharing modes for + a virtual SCSI adapter. ([''present''])' + - ' - Accepted values:' + - ' - NONE' + - ' - PHYSICAL' + - ' - VIRTUAL' + elements: dict + type: list + serial_ports: + description: + - List of serial ports. + - 'Valid attributes are:' + - ' - C(yield_on_poll) (bool): CPU yield behavior. If set to true, the virtual + machine will periodically relinquish the processor if its sole task is polling + the virtual serial port. The amount of time it takes to regain the processor + will depend on the degree of other virtual machine activity on the host. ([''present''])' + - ' - C(backing) (dict): Physical resource backing for the virtual serial port. + ([''present''])' + - ' - Accepted keys:' + - ' - type (string): The C(backing_type) defines the valid backing types for + a virtual serial port.' + - 'Accepted value for this field:' + - ' - C(FILE)' + - ' - C(HOST_DEVICE)' + - ' - C(NETWORK_CLIENT)' + - ' - C(NETWORK_SERVER)' + - ' - C(PIPE_CLIENT)' + - ' - C(PIPE_SERVER)' + - ' - file (string): Path of the file backing the virtual serial port.' + - ' - host_device (string): Name of the device backing the virtual serial + port. <p>' + - ' - pipe (string): Name of the pipe backing the virtual serial port.' + - ' - no_rx_loss (boolean): Flag that enables optimized data transfer over + the pipe. When the value is true, the host buffers data to prevent data overrun. This + allows the virtual machine to read all of the data transferred over the pipe + with no data loss.' + - ' - network_location (string): URI specifying the location of the network + service backing the virtual serial port. <ul> <li>If {@link #type} is {@link + BackingType#NETWORK_SERVER}, this field is the location used by clients to connect + to this server. The hostname part of the URI should either be empty or should + specify the address of the host on which the virtual machine is running.</li> + <li>If {@link #type} is {@link BackingType#NETWORK_CLIENT}, this field is the + location used by the virtual machine to connect to the remote server.</li> </ul>' + - ' - proxy (string): Proxy service that provides network access to the network + backing. If set, the virtual machine initiates a connection with the proxy + service and forwards the traffic to the proxy.' + - ' - C(start_connected) (bool): Flag indicating whether the virtual device should + be connected whenever the virtual machine is powered on. ([''present''])' + - ' - C(allow_guest_control) (bool): Flag indicating whether the guest can connect + and disconnect the device. ([''present''])' + elements: dict + type: list + serial_ports_to_update: + description: + - Map of serial ports to Update. + type: dict + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + source: + description: + - Virtual machine to InstantClone from. Required with I(state=['clone', 'instant_clone']) + type: str + state: + choices: + - absent + - clone + - instant_clone + - present + - register + - relocate + - unregister + default: present + description: [] + type: str + storage_policy: + description: + - The C(storage_policy_spec) {@term structure} contains information about the + storage policy that is to be associated with the virtual machine home (which + contains the configuration and log files). Required with I(state=['present']) + - 'Valid attributes are:' + - ' - C(policy) (str): Identifier of the storage policy which should be associated + with the virtual machine. ([''present''])' + - ' This key is required with [''present''].' + type: dict + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Identifier of the virtual machine to be unregistered. Required with I(state=['absent', + 'relocate', 'unregister']) + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Build a list of all the clusters + vmware.vmware_rest.vcenter_cluster_info: + register: all_the_clusters + +- name: Retrieve details about the first cluster + vmware.vmware_rest.vcenter_cluster_info: + cluster: '{{ all_the_clusters.value[0].cluster }}' + register: my_cluster_info + +- name: Create a VM + vmware.vmware_rest.vcenter_vm: + placement: + cluster: '{{ my_cluster_info.id }}' + datastore: "{{ lookup('vmware.vmware_rest.datastore_moid', '/my_dc/datastore/local')\ + \ }}" + folder: '{{ my_virtual_machine_folder.folder }}' + resource_pool: '{{ my_cluster_info.value.resource_pool }}' + name: test_vm1 + guest_OS: DEBIAN_7_64 + hardware_version: VMX_10 + memory: + hot_add_enabled: true + size_MiB: 1024 + register: my_vm + +- name: Collect the list of the existing VM + vmware.vmware_rest.vcenter_vm_info: + register: existing_vms + until: existing_vms is not failed + +- name: Delete some VM + vmware.vmware_rest.vcenter_vm: + state: absent + vm: '{{ item.vm }}' + with_items: '{{ existing_vms.value }}' + when: + - not item.name.startswith("vCLS") + +- name: Create a VM + vmware.vmware_rest.vcenter_vm: + placement: + cluster: "{{ lookup('vmware.vmware_rest.cluster_moid', '/my_dc/host/my_cluster')\ + \ }}" + datastore: "{{ lookup('vmware.vmware_rest.datastore_moid', '/my_dc/datastore/local')\ + \ }}" + folder: "{{ lookup('vmware.vmware_rest.folder_moid', '/my_dc/vm') }}" + resource_pool: "{{ lookup('vmware.vmware_rest.resource_pool_moid', '/my_dc/host/my_cluster/Resources')\ + \ }}" + name: test_vm1 + guest_OS: RHEL_7_64 + hardware_version: VMX_11 + memory: + hot_add_enabled: true + size_MiB: 1024 + disks: + - type: SATA + backing: + type: VMDK_FILE + vmdk_file: '[local] test_vm1/{{ disk_name }}.vmdk' + - type: SATA + new_vmdk: + name: second_disk + capacity: 32000000000 + cdroms: + - type: SATA + sata: + bus: 0 + unit: 2 + nics: + - backing: + type: STANDARD_PORTGROUP + network: "{{ lookup('vmware.vmware_rest.network_moid', '/my_dc/network/VM\ + \ Network') }}" + + register: my_vm + +- name: Create a VM + vmware.vmware_rest.vcenter_vm: + placement: + cluster: "{{ lookup('vmware.vmware_rest.cluster_moid', '/my_dc/host/my_cluster')\ + \ }}" + datastore: "{{ lookup('vmware.vmware_rest.datastore_moid', '/my_dc/datastore/rw_datastore')\ + \ }}" + folder: "{{ lookup('vmware.vmware_rest.folder_moid', '/my_dc/vm') }}" + resource_pool: "{{ lookup('vmware.vmware_rest.resource_pool_moid', '/my_dc/host/my_cluster/Resources')\ + \ }}" + name: test_vm1 + guest_OS: DEBIAN_8_64 + hardware_version: VMX_11 + memory: + hot_add_enabled: true + size_MiB: 1024 + register: my_vm + +- name: Create a content library based on a DataStore + vmware.vmware_rest.content_locallibrary: + name: my_library_on_datastore + description: automated + publish_info: + published: true + authentication_method: NONE + storage_backings: + - datastore_id: "{{ lookup('vmware.vmware_rest.datastore_moid', '/my_dc/datastore/local')\ + \ }}" + type: DATASTORE + state: present + register: ds_lib + +- name: Create a VM template on the library + vmware.vmware_rest.vcenter_vmtemplate_libraryitems: + name: foobar2001 + library: '{{ ds_lib.id }}' + source_vm: '{{ my_vm.id }}' + placement: + cluster: "{{ lookup('vmware.vmware_rest.cluster_moid', '/my_dc/host/my_cluster')\ + \ }}" + folder: "{{ lookup('vmware.vmware_rest.folder_moid', '/my_dc/vm') }}" + resource_pool: "{{ lookup('vmware.vmware_rest.resource_pool_moid', '/my_dc/host/my_cluster/Resources')\ + \ }}" + register: mylib_item + +- name: Deploy a new VM based on the template + vmware.vmware_rest.vcenter_vmtemplate_libraryitems: + name: foobar2002 + library: '{{ ds_lib.id }}' + template_library_item: '{{ mylib_item.id }}' + placement: + cluster: "{{ lookup('vmware.vmware_rest.cluster_moid', '/my_dc/host/my_cluster')\ + \ }}" + folder: "{{ lookup('vmware.vmware_rest.folder_moid', '/my_dc/vm') }}" + resource_pool: "{{ lookup('vmware.vmware_rest.resource_pool_moid', '/my_dc/host/my_cluster/Resources')\ + \ }}" + state: deploy + register: my_new_vm + +- name: Retrieve all the details about the new VM + vmware.vmware_rest.vcenter_vm: + vm: '{{ my_new_vm.value }}' + register: my_new_vm_info + +- name: Create an instant clone of a VM + vmware.vmware_rest.vcenter_vm: + placement: + datastore: "{{ lookup('vmware.vmware_rest.datastore_moid', '/my_dc/datastore/local')\ + \ }}" + folder: "{{ lookup('vmware.vmware_rest.folder_moid', '/my_dc/vm') }}" + resource_pool: "{{ lookup('vmware.vmware_rest.resource_pool_moid', '/my_dc/host/my_cluster/Resources')\ + \ }}" + source: '{{ my_vm.id }}' + name: test_vm2 + state: instant_clone + register: my_instant_clone + +- name: Create a clone of a VM + vmware.vmware_rest.vcenter_vm: + placement: + datastore: "{{ lookup('vmware.vmware_rest.datastore_moid', '/my_dc/datastore/local')\ + \ }}" + folder: "{{ lookup('vmware.vmware_rest.folder_moid', '/my_dc/vm') }}" + resource_pool: "{{ lookup('vmware.vmware_rest.resource_pool_moid', '/my_dc/host/my_cluster/Resources')\ + \ }}" + source: '{{ my_vm.id }}' + name: test_vm3 + state: clone + register: my_clone_vm +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Delete some VM +msg: + description: Delete some VM + returned: On success + sample: All items completed + type: str +results: + description: Delete some VM + returned: On success + sample: + - _ansible_item_label: + cpu_count: 1 + memory_size_MiB: 128 + name: vCLS-a3e9f505-69fc-43d0-beed-c1a43d06184e + power_state: POWERED_OFF + vm: vm-1130 + _ansible_no_log: 0 + ansible_loop_var: item + changed: 0 + item: + cpu_count: 1 + memory_size_MiB: 128 + name: vCLS-a3e9f505-69fc-43d0-beed-c1a43d06184e + power_state: POWERED_OFF + vm: vm-1130 + skip_reason: Conditional result was False + skipped: 1 + - _ansible_item_label: + cpu_count: 1 + memory_size_MiB: 1024 + name: test_vm1 + power_state: POWERED_OFF + vm: vm-1131 + _ansible_no_log: null + ansible_loop_var: item + changed: 1 + failed: 0 + invocation: + module_args: + bios_uuid: null + boot: null + boot_devices: null + cdroms: null + cpu: null + datastore: null + datastore_path: null + disconnect_all_nics: null + disks: null + disks_to_remove: null + disks_to_update: null + floppies: null + guest_OS: null + guest_customization_spec: null + hardware_version: null + memory: null + name: null + nics: null + nics_to_update: null + parallel_ports: null + parallel_ports_to_update: null + path: null + placement: null + power_on: null + sata_adapters: null + scsi_adapters: null + serial_ports: null + serial_ports_to_update: null + session_timeout: null + source: null + state: absent + storage_policy: null + vcenter_hostname: vcenter.test + vcenter_password: VALUE_SPECIFIED_IN_NO_LOG_PARAMETER + vcenter_rest_log_file: null + vcenter_username: administrator@vsphere.local + vcenter_validate_certs: 0 + vm: vm-1131 + item: + cpu_count: 1 + memory_size_MiB: 1024 + name: test_vm1 + power_state: POWERED_OFF + vm: vm-1131 + value: {} + - _ansible_item_label: + cpu_count: 1 + memory_size_MiB: 1024 + name: foobar2002 + power_state: POWERED_OFF + vm: vm-1134 + _ansible_no_log: null + ansible_loop_var: item + changed: 1 + failed: 0 + invocation: + module_args: + bios_uuid: null + boot: null + boot_devices: null + cdroms: null + cpu: null + datastore: null + datastore_path: null + disconnect_all_nics: null + disks: null + disks_to_remove: null + disks_to_update: null + floppies: null + guest_OS: null + guest_customization_spec: null + hardware_version: null + memory: null + name: null + nics: null + nics_to_update: null + parallel_ports: null + parallel_ports_to_update: null + path: null + placement: null + power_on: null + sata_adapters: null + scsi_adapters: null + serial_ports: null + serial_ports_to_update: null + session_timeout: null + source: null + state: absent + storage_policy: null + vcenter_hostname: vcenter.test + vcenter_password: VALUE_SPECIFIED_IN_NO_LOG_PARAMETER + vcenter_rest_log_file: null + vcenter_username: administrator@vsphere.local + vcenter_validate_certs: 0 + vm: vm-1134 + item: + cpu_count: 1 + memory_size_MiB: 1024 + name: foobar2002 + power_state: POWERED_OFF + vm: vm-1134 + value: {} + type: list +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "create": { + "query": {}, + "body": { + "boot": "boot", + "boot_devices": "boot_devices", + "cdroms": "cdroms", + "cpu": "cpu", + "disks": "disks", + "floppies": "floppies", + "guest_OS": "guest_OS", + "hardware_version": "hardware_version", + "memory": "memory", + "name": "name", + "nics": "nics", + "parallel_ports": "parallel_ports", + "placement": "placement", + "sata_adapters": "sata_adapters", + "scsi_adapters": "scsi_adapters", + "serial_ports": "serial_ports", + "storage_policy": "storage_policy", + }, + "path": {}, + }, + "instant_clone": { + "query": {}, + "body": { + "bios_uuid": "bios_uuid", + "disconnect_all_nics": "disconnect_all_nics", + "name": "name", + "nics_to_update": "nics_to_update", + "parallel_ports_to_update": "parallel_ports_to_update", + "placement": "placement", + "serial_ports_to_update": "serial_ports_to_update", + "source": "source", + }, + "path": {}, + }, + "clone": { + "query": {}, + "body": { + "disks_to_remove": "disks_to_remove", + "disks_to_update": "disks_to_update", + "guest_customization_spec": "guest_customization_spec", + "name": "name", + "placement": "placement", + "power_on": "power_on", + "source": "source", + }, + "path": {}, + }, + "unregister": {"query": {}, "body": {}, "path": {"vm": "vm"}}, + "register": { + "query": {}, + "body": { + "datastore": "datastore", + "datastore_path": "datastore_path", + "name": "name", + "path": "path", + "placement": "placement", + }, + "path": {}, + }, + "relocate": { + "query": {}, + "body": {"disks": "disks", "placement": "placement"}, + "path": {"vm": "vm"}, + }, + "delete": {"query": {}, "body": {}, "path": {"vm": "vm"}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["bios_uuid"] = {"type": "str"} + argument_spec["boot"] = {"type": "dict"} + argument_spec["boot_devices"] = {"type": "list", "elements": "dict"} + argument_spec["cdroms"] = {"type": "list", "elements": "dict"} + argument_spec["cpu"] = {"type": "dict"} + argument_spec["datastore"] = {"type": "str"} + argument_spec["datastore_path"] = {"type": "str"} + argument_spec["disconnect_all_nics"] = {"type": "bool"} + argument_spec["disks"] = {"type": "list", "elements": "dict"} + argument_spec["disks_to_remove"] = {"type": "list", "elements": "str"} + argument_spec["disks_to_update"] = {"type": "dict"} + argument_spec["floppies"] = {"type": "list", "elements": "dict"} + argument_spec["guest_OS"] = { + "type": "str", + "choices": [ + "AMAZONLINUX2_64", + "AMAZONLINUX3_64", + "ASIANUX_3", + "ASIANUX_3_64", + "ASIANUX_4", + "ASIANUX_4_64", + "ASIANUX_5_64", + "ASIANUX_7_64", + "ASIANUX_8_64", + "ASIANUX_9_64", + "CENTOS", + "CENTOS_6", + "CENTOS_64", + "CENTOS_6_64", + "CENTOS_7", + "CENTOS_7_64", + "CENTOS_8_64", + "CENTOS_9_64", + "COREOS_64", + "CRXPOD_1", + "DARWIN", + "DARWIN_10", + "DARWIN_10_64", + "DARWIN_11", + "DARWIN_11_64", + "DARWIN_12_64", + "DARWIN_13_64", + "DARWIN_14_64", + "DARWIN_15_64", + "DARWIN_16_64", + "DARWIN_17_64", + "DARWIN_18_64", + "DARWIN_19_64", + "DARWIN_20_64", + "DARWIN_21_64", + "DARWIN_64", + "DEBIAN_10", + "DEBIAN_10_64", + "DEBIAN_11", + "DEBIAN_11_64", + "DEBIAN_4", + "DEBIAN_4_64", + "DEBIAN_5", + "DEBIAN_5_64", + "DEBIAN_6", + "DEBIAN_6_64", + "DEBIAN_7", + "DEBIAN_7_64", + "DEBIAN_8", + "DEBIAN_8_64", + "DEBIAN_9", + "DEBIAN_9_64", + "DOS", + "ECOMSTATION", + "ECOMSTATION_2", + "FEDORA", + "FEDORA_64", + "FREEBSD", + "FREEBSD_11", + "FREEBSD_11_64", + "FREEBSD_12", + "FREEBSD_12_64", + "FREEBSD_13", + "FREEBSD_13_64", + "FREEBSD_64", + "GENERIC_LINUX", + "MANDRAKE", + "MANDRIVA", + "MANDRIVA_64", + "NETWARE_4", + "NETWARE_5", + "NETWARE_6", + "NLD_9", + "OES", + "OPENSERVER_5", + "OPENSERVER_6", + "OPENSUSE", + "OPENSUSE_64", + "ORACLE_LINUX", + "ORACLE_LINUX_6", + "ORACLE_LINUX_64", + "ORACLE_LINUX_6_64", + "ORACLE_LINUX_7", + "ORACLE_LINUX_7_64", + "ORACLE_LINUX_8_64", + "ORACLE_LINUX_9_64", + "OS2", + "OTHER", + "OTHER_24X_LINUX", + "OTHER_24X_LINUX_64", + "OTHER_26X_LINUX", + "OTHER_26X_LINUX_64", + "OTHER_3X_LINUX", + "OTHER_3X_LINUX_64", + "OTHER_4X_LINUX", + "OTHER_4X_LINUX_64", + "OTHER_5X_LINUX", + "OTHER_5X_LINUX_64", + "OTHER_64", + "OTHER_LINUX", + "OTHER_LINUX_64", + "REDHAT", + "RHEL_2", + "RHEL_3", + "RHEL_3_64", + "RHEL_4", + "RHEL_4_64", + "RHEL_5", + "RHEL_5_64", + "RHEL_6", + "RHEL_6_64", + "RHEL_7", + "RHEL_7_64", + "RHEL_8_64", + "RHEL_9_64", + "SJDS", + "SLES", + "SLES_10", + "SLES_10_64", + "SLES_11", + "SLES_11_64", + "SLES_12", + "SLES_12_64", + "SLES_15_64", + "SLES_16_64", + "SLES_64", + "SOLARIS_10", + "SOLARIS_10_64", + "SOLARIS_11_64", + "SOLARIS_6", + "SOLARIS_7", + "SOLARIS_8", + "SOLARIS_9", + "SUSE", + "SUSE_64", + "TURBO_LINUX", + "TURBO_LINUX_64", + "UBUNTU", + "UBUNTU_64", + "UNIXWARE_7", + "VMKERNEL", + "VMKERNEL_5", + "VMKERNEL_6", + "VMKERNEL_65", + "VMKERNEL_7", + "VMWARE_PHOTON_64", + "WINDOWS_7", + "WINDOWS_7_64", + "WINDOWS_7_SERVER_64", + "WINDOWS_8", + "WINDOWS_8_64", + "WINDOWS_8_SERVER_64", + "WINDOWS_9", + "WINDOWS_9_64", + "WINDOWS_9_SERVER_64", + "WINDOWS_HYPERV", + "WINDOWS_SERVER_2019", + "WINDOWS_SERVER_2021", + "WIN_2000_ADV_SERV", + "WIN_2000_PRO", + "WIN_2000_SERV", + "WIN_31", + "WIN_95", + "WIN_98", + "WIN_LONGHORN", + "WIN_LONGHORN_64", + "WIN_ME", + "WIN_NET_BUSINESS", + "WIN_NET_DATACENTER", + "WIN_NET_DATACENTER_64", + "WIN_NET_ENTERPRISE", + "WIN_NET_ENTERPRISE_64", + "WIN_NET_STANDARD", + "WIN_NET_STANDARD_64", + "WIN_NET_WEB", + "WIN_NT", + "WIN_VISTA", + "WIN_VISTA_64", + "WIN_XP_HOME", + "WIN_XP_PRO", + "WIN_XP_PRO_64", + ], + } + argument_spec["guest_customization_spec"] = {"type": "dict"} + argument_spec["hardware_version"] = { + "type": "str", + "choices": [ + "VMX_03", + "VMX_04", + "VMX_06", + "VMX_07", + "VMX_08", + "VMX_09", + "VMX_10", + "VMX_11", + "VMX_12", + "VMX_13", + "VMX_14", + "VMX_15", + "VMX_16", + "VMX_17", + "VMX_18", + "VMX_19", + ], + } + argument_spec["memory"] = {"type": "dict"} + argument_spec["name"] = {"type": "str"} + argument_spec["nics"] = {"type": "list", "elements": "dict"} + argument_spec["nics_to_update"] = {"type": "dict"} + argument_spec["parallel_ports"] = {"type": "list", "elements": "dict"} + argument_spec["parallel_ports_to_update"] = {"type": "dict"} + argument_spec["path"] = {"type": "str"} + argument_spec["placement"] = {"type": "dict"} + argument_spec["power_on"] = {"type": "bool"} + argument_spec["sata_adapters"] = {"type": "list", "elements": "dict"} + argument_spec["scsi_adapters"] = {"type": "list", "elements": "dict"} + argument_spec["serial_ports"] = {"type": "list", "elements": "dict"} + argument_spec["serial_ports_to_update"] = {"type": "dict"} + argument_spec["source"] = {"type": "str"} + argument_spec["state"] = { + "type": "str", + "choices": [ + "absent", + "clone", + "instant_clone", + "present", + "register", + "relocate", + "unregister", + ], + "default": "present", + } + argument_spec["storage_policy"] = {"type": "dict"} + argument_spec["vm"] = {"type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/vcenter/vm").format(**params) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _clone(params, session): + + lookup_url = per_id_url = build_url(params) + uniquity_keys = ["vm"] + comp_func = None + + async def lookup_with_filters(params, session, url): + # e.g: for the datacenter resources + if "folder" not in params: + return + if "name" not in params: + return + async with session.get( + f"{url}?names={params['name']}&folders={params['folder']}" + ) as resp: + _json = await resp.json() + if isinstance(_json, list) and len(_json) == 1: + return await get_device_info(session, url, _json[0]["vm"]) + + _json = None + + if params["vm"]: + _json = await get_device_info(session, build_url(params), params["vm"]) + + if not _json and (uniquity_keys or comp_func): + _json = await exists( + params, + session, + url=lookup_url, + uniquity_keys=uniquity_keys, + per_id_url=per_id_url, + comp_func=comp_func, + ) + + if not _json: + _json = await lookup_with_filters(params, session, build_url(params)) + + if _json: + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + if "_update" in globals(): + params["vm"] = _json["id"] + return await globals()["_update"](params, session) + + return await update_changed_flag(_json, 200, "get") + + payload = prepare_payload(params, PAYLOAD_FORMAT["clone"]) + _url = ("https://{vcenter_hostname}" "/api/vcenter/vm?action=clone").format( + **params + ) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + if resp.status == 500: + text = await resp.text() + raise EmbeddedModuleFailure( + f"Request has failed: status={resp.status}, {text}" + ) + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + + if (resp.status in [200, 201]) and "error" not in _json: + if isinstance(_json, str): # 7.0.2 and greater + _id = _json # TODO: fetch the object + elif isinstance(_json, dict) and "value" not in _json: + _id = list(_json["value"].values())[0] + elif isinstance(_json, dict) and "value" in _json: + _id = _json["value"] + _json_device_info = await get_device_info(session, _url, _id) + if _json_device_info: + _json = _json_device_info + + return await update_changed_flag(_json, resp.status, "clone") + + +async def _create(params, session): + + lookup_url = per_id_url = build_url(params) + uniquity_keys = ["vm"] + comp_func = None + + async def lookup_with_filters(params, session, url): + # e.g: for the datacenter resources + if "folder" not in params: + return + if "name" not in params: + return + async with session.get( + f"{url}?names={params['name']}&folders={params['folder']}" + ) as resp: + _json = await resp.json() + if isinstance(_json, list) and len(_json) == 1: + return await get_device_info(session, url, _json[0]["vm"]) + + _json = None + + if params["vm"]: + _json = await get_device_info(session, build_url(params), params["vm"]) + + if not _json and (uniquity_keys or comp_func): + _json = await exists( + params, + session, + url=lookup_url, + uniquity_keys=uniquity_keys, + per_id_url=per_id_url, + comp_func=comp_func, + ) + + if not _json: + _json = await lookup_with_filters(params, session, build_url(params)) + + if _json: + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + if "_update" in globals(): + params["vm"] = _json["id"] + return await globals()["_update"](params, session) + + return await update_changed_flag(_json, 200, "get") + + payload = prepare_payload(params, PAYLOAD_FORMAT["create"]) + _url = ("https://{vcenter_hostname}" "/api/vcenter/vm").format(**params) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + if resp.status == 500: + text = await resp.text() + raise EmbeddedModuleFailure( + f"Request has failed: status={resp.status}, {text}" + ) + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + + if (resp.status in [200, 201]) and "error" not in _json: + if isinstance(_json, str): # 7.0.2 and greater + _id = _json # TODO: fetch the object + elif isinstance(_json, dict) and "value" not in _json: + _id = list(_json["value"].values())[0] + elif isinstance(_json, dict) and "value" in _json: + _id = _json["value"] + _json_device_info = await get_device_info(session, _url, _id) + if _json_device_info: + _json = _json_device_info + + return await update_changed_flag(_json, resp.status, "create") + + +async def _delete(params, session): + _in_query_parameters = PAYLOAD_FORMAT["delete"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["delete"]) + subdevice_type = get_subdevice_type("/api/vcenter/vm/{vm}") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.delete(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "delete") + + +async def _instant_clone(params, session): + + lookup_url = per_id_url = build_url(params) + uniquity_keys = ["vm"] + comp_func = None + + async def lookup_with_filters(params, session, url): + # e.g: for the datacenter resources + if "folder" not in params: + return + if "name" not in params: + return + async with session.get( + f"{url}?names={params['name']}&folders={params['folder']}" + ) as resp: + _json = await resp.json() + if isinstance(_json, list) and len(_json) == 1: + return await get_device_info(session, url, _json[0]["vm"]) + + _json = None + + if params["vm"]: + _json = await get_device_info(session, build_url(params), params["vm"]) + + if not _json and (uniquity_keys or comp_func): + _json = await exists( + params, + session, + url=lookup_url, + uniquity_keys=uniquity_keys, + per_id_url=per_id_url, + comp_func=comp_func, + ) + + if not _json: + _json = await lookup_with_filters(params, session, build_url(params)) + + if _json: + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + if "_update" in globals(): + params["vm"] = _json["id"] + return await globals()["_update"](params, session) + + return await update_changed_flag(_json, 200, "get") + + payload = prepare_payload(params, PAYLOAD_FORMAT["instant_clone"]) + _url = ("https://{vcenter_hostname}" "/api/vcenter/vm?action=instant-clone").format( + **params + ) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + if resp.status == 500: + text = await resp.text() + raise EmbeddedModuleFailure( + f"Request has failed: status={resp.status}, {text}" + ) + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + + if (resp.status in [200, 201]) and "error" not in _json: + if isinstance(_json, str): # 7.0.2 and greater + _id = _json # TODO: fetch the object + elif isinstance(_json, dict) and "value" not in _json: + _id = list(_json["value"].values())[0] + elif isinstance(_json, dict) and "value" in _json: + _id = _json["value"] + _json_device_info = await get_device_info(session, _url, _id) + if _json_device_info: + _json = _json_device_info + + return await update_changed_flag(_json, resp.status, "instant_clone") + + +async def _register(params, session): + _in_query_parameters = PAYLOAD_FORMAT["register"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["register"]) + subdevice_type = get_subdevice_type("/api/vcenter/vm?action=register") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/vcenter/vm?action=register" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "register") + + +async def _relocate(params, session): + _in_query_parameters = PAYLOAD_FORMAT["relocate"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["relocate"]) + subdevice_type = get_subdevice_type("/api/vcenter/vm/{vm}?action=relocate") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/vcenter/vm/{vm}?action=relocate" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "relocate") + + +async def _unregister(params, session): + _in_query_parameters = PAYLOAD_FORMAT["unregister"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["unregister"]) + subdevice_type = get_subdevice_type("/api/vcenter/vm/{vm}?action=unregister") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/vcenter/vm/{vm}?action=unregister" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "unregister") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_guest_customization.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_guest_customization.py new file mode 100644 index 00000000..37a89648 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_guest_customization.py @@ -0,0 +1,368 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_guest_customization +short_description: Applies a customization specification on the virtual machine +description: Applies a customization specification on the virtual machine in {@param.name + vm}. The actual customization happens inside the guest when the virtual machine + is powered on. If there is a pending customization for the virtual machine and a + new one is set, then the existing customization setting will be overwritten with + the new settings. +options: + configuration_spec: + description: + - Settings to be applied to the guest during the customization. This parameter + is mandatory. + - 'Valid attributes are:' + - ' - C(windows_config) (dict): Guest customization specification for a Windows + guest operating system ([''set''])' + - ' - Accepted keys:' + - ' - reboot (string): The C(reboot_option) specifies what should be done + to the guest after the customization.' + - 'Accepted value for this field:' + - ' - C(NO_REBOOT)' + - ' - C(REBOOT)' + - ' - C(SHUTDOWN)' + - ' - sysprep (object): Customization settings like user details, administrator + details, etc for the windows guest operating system. Exactly one of C(#sysprep) + or C(#sysprep_xml) must be specified.' + - ' - sysprep_xml (string): All settings specified in a XML format. This is + the content of a typical answer.xml file that is used by System administrators + during the Windows image customization. Check https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/update-windows-settings-and-scripts-create-your-own-answer-file-sxs + Exactly one of C(#sysprep) or C(#sysprep_xml) must be specified.' + - ' - C(linux_config) (dict): Guest customization specification for a linux guest + operating system ([''set''])' + - ' - Accepted keys:' + - ' - hostname (object): The computer name of the (Windows) virtual machine. + A computer name may contain letters (A-Z), numbers(0-9) and hyphens (-) but + no spaces or periods (.). The name may not consist entirely of digits. A computer + name is restricted to 15 characters in length. If the computer name is longer + than 15 characters, it will be truncated to 15 characters. Check {@link HostnameGenerator} + for various options.' + - ' - domain (string): The fully qualified domain name.' + - ' - time_zone (string): The case-sensitive time zone, such as Europe/Sofia. + Valid time zone values are based on the tz (time zone) database used by Linux. + The values are strings in the form "Area/Location," in which Area is a continent + or ocean name, and Location is the city, island, or other regional designation. + See the https://kb.vmware.com/kb/2145518 for a list of supported time zones + for different versions in Linux.' + - ' - script_text (string): The script to run before and after Linux guest + customization.<br> The max size of the script is 1500 bytes. As long as the + script (shell, perl, python...) has the right "#!" in the header, it is supported. + The caller should not assume any environment variables when the script is run. + The script is invoked by the customization engine using the command line: 1) + with argument "precustomization" before customization, 2) with argument "postcustomization" + after customization. The script should parse this argument and implement pre-customization + or post-customization task code details in the corresponding block. A Linux + shell script example: <code> #!/bin/sh<br> if [ x$1 == x"precustomization" ]; + then<br> echo "Do Precustomization tasks"<br> #code for pre-customization actions...<br> + elif [ x$1 == x"postcustomization" ]; then<br> echo "Do Postcustomization tasks"<br> + #code for post-customization actions...<br> fi<br> </code>' + required: true + type: dict + global_DNS_settings: + description: + - Global DNS settings constitute the DNS settings that are not specific to a particular + virtual network adapter. This parameter is mandatory. + - 'Valid attributes are:' + - ' - C(dns_suffix_list) (list): List of name resolution suffixes for the virtual + network adapter. This list applies to both Windows and Linux guest customization. + For Linux, this setting is global, whereas in Windows, this setting is listed + on a per-adapter basis. ([''set''])' + - ' - C(dns_servers) (list): List of DNS servers, for a virtual network adapter + with a static IP address. If this list is empty, then the guest operating system + is expected to use a DHCP server to get its DNS server settings. These settings + configure the virtual machine to use the specified DNS servers. These DNS server + settings are listed in the order of preference. ([''set''])' + required: true + type: dict + interfaces: + description: + - IP settings that are specific to a particular virtual network adapter. The {@link + AdapterMapping} {@term structure} maps a network adapter's MAC address to its + {@link IPSettings}. May be empty if there are no network adapters, else should + match number of network adapters configured for the VM. This parameter is mandatory. + - 'Valid attributes are:' + - ' - C(mac_address) (str): The MAC address of a network adapter being customized. + ([''set''])' + - ' - C(adapter) (dict): The IP settings for the associated virtual network adapter. + ([''set''])' + - ' This key is required with [''set''].' + - ' - Accepted keys:' + - ' - ipv4 (object): Specification to configure IPv4 address, subnet mask + and gateway info for this virtual network adapter.' + - ' - ipv6 (object): Specification to configure IPv6 address, subnet mask + and gateway info for this virtual network adapter.' + - ' - windows (object): Windows settings to be configured for this specific + virtual Network adapter. This is valid only for Windows guest operating systems.' + elements: dict + required: true + type: list + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - The unique identifier of the virtual machine that needs to be customized. This + parameter is mandatory. + required: true + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Customize the VM + vmware.vmware_rest.vcenter_vm_guest_customization: + vm: "{{ lookup('vmware.vmware_rest.vm_moid', '/my_dc/vm/test_vm1') }}" + configuration_spec: + linux_config: + domain: mydomain + hostname: + fixed_name: foobar + type: FIXED + interfaces: + - adapter: + ipv4: + type: STATIC + gateways: + - 192.168.123.1 + ip_address: 192.168.123.50 + prefix: 24 + global_DNS_settings: + dns_suffix_list: [] + dns_servers: + - 1.1.1.1 +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Customize the VM +value: + description: Customize the VM + returned: On success + sample: {} + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "set": { + "query": {}, + "body": { + "configuration_spec": "spec/configuration_spec", + "global_DNS_settings": "spec/global_DNS_settings", + "interfaces": "spec/interfaces", + }, + "path": {"vm": "vm"}, + } +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["configuration_spec"] = {"required": True, "type": "dict"} + argument_spec["global_DNS_settings"] = {"required": True, "type": "dict"} + argument_spec["interfaces"] = {"required": True, "type": "list", "elements": "dict"} + argument_spec["vm"] = {"required": True, "type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/guest/customization" + ).format(**params) + + +async def entry_point(module, session): + + func = globals()["_set"] + + return await func(module.params, session) + + +async def _set(params, session): + _in_query_parameters = PAYLOAD_FORMAT["set"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["set"]) + subdevice_type = get_subdevice_type("/api/vcenter/vm/{vm}/guest/customization") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/guest/customization" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.get(_url, json=payload, **session_timeout(params)) as resp: + before = await resp.json() + + async with session.put(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # The PUT answer does not let us know if the resource has actually been + # modified + if resp.status < 300: + async with session.get( + _url, json=payload, **session_timeout(params) + ) as resp_get: + after = await resp_get.json() + if before == after: + return await update_changed_flag(after, resp_get.status, "get") + return await update_changed_flag(_json, resp.status, "set") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_guest_filesystem_directories.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_guest_filesystem_directories.py new file mode 100644 index 00000000..45af10fb --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_guest_filesystem_directories.py @@ -0,0 +1,483 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_guest_filesystem_directories +short_description: Creates a directory in the guest operating system +description: Creates a directory in the guest operating system. <p> +options: + create_parents: + description: + - Whether any parent directories should be created. If any failure occurs, some + parent directories could be left behind. + type: bool + credentials: + description: + - The guest authentication data. This parameter is mandatory. + - 'Valid attributes are:' + - ' - C(interactive_session) (bool): If {@term set}, theoperation will interact + with the logged-in desktop session in the guest. This requires that the logged-on + user matches the user specified by the {@link Credentials}. This is currently + only supported for {@link Type#USERNAME_PASSWORD}. ([''absent'', ''create_temporary'', + ''move'', ''present''])' + - ' This key is required with [''absent'', ''create_temporary'', ''move'', ''present''].' + - ' - C(type) (str): Types of guest credentials ([''absent'', ''create_temporary'', + ''move'', ''present''])' + - ' This key is required with [''absent'', ''create_temporary'', ''move'', ''present''].' + - ' - Accepted values:' + - ' - SAML_BEARER_TOKEN' + - ' - USERNAME_PASSWORD' + - ' - C(user_name) (str): For {@link Type#SAML_BEARER_TOKEN}, this is the guest + user to be associated with the credentials. For {@link Type#USERNAME_PASSWORD} + this is the guest username. ([''absent'', ''create_temporary'', ''move'', ''present''])' + - ' - C(password) (str): password ([''absent'', ''create_temporary'', ''move'', + ''present''])' + - ' - C(saml_token) (str): SAML Bearer Token ([''absent'', ''create_temporary'', + ''move'', ''present''])' + required: true + type: dict + new_path: + description: + - The complete path to where the directory is moved or its new name. It cannot + be a path to an existing directory or an existing file. Required with I(state=['move']) + type: str + parent_path: + description: + - The complete path to the directory in which to create the new directory. + type: str + path: + description: + - The complete path to the directory to be created. Required with I(state=['absent', + 'move', 'present']) + type: str + prefix: + description: + - The prefix to be given to the new temporary directory. Required with I(state=['create_temporary']) + type: str + recursive: + description: + - If true, all files and subdirectories are also deleted. If false, the directory + must be empty for the operation to succeed. + type: bool + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - absent + - create_temporary + - move + - present + default: present + description: [] + type: str + suffix: + description: + - The suffix to be given to the new temporary directory. Required with I(state=['create_temporary']) + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual Machine to perform the operation on. This parameter is mandatory. + required: true + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Create a VM + vmware.vmware_rest.vcenter_vm: + placement: + cluster: "{{ lookup('vmware.vmware_rest.cluster_moid', '/my_dc/host/my_cluster')\ + \ }}" + datastore: "{{ lookup('vmware.vmware_rest.datastore_moid', '/my_dc/datastore/local')\ + \ }}" + folder: "{{ lookup('vmware.vmware_rest.folder_moid', '/my_dc/vm') }}" + resource_pool: "{{ lookup('vmware.vmware_rest.resource_pool_moid', '/my_dc/host/my_cluster/Resources')\ + \ }}" + name: test_vm1 + guest_OS: RHEL_7_64 + hardware_version: VMX_11 + memory: + hot_add_enabled: true + size_MiB: 1024 + disks: + - type: SATA + backing: + type: VMDK_FILE + vmdk_file: '[local] test_vm1/{{ disk_name }}.vmdk' + - type: SATA + new_vmdk: + name: second_disk + capacity: 32000000000 + cdroms: + - type: SATA + sata: + bus: 0 + unit: 2 + nics: + - backing: + type: STANDARD_PORTGROUP + network: "{{ lookup('vmware.vmware_rest.network_moid', '/my_dc/network/VM\ + \ Network') }}" + + register: my_vm + +- name: Create a directory in /tmp + vmware.vmware_rest.vcenter_vm_guest_filesystem_directories: + vm: '{{ my_vm.id }}' + path: /tmp/my/path + create_parents: true + credentials: + interactive_session: false + type: USERNAME_PASSWORD + user_name: root + password: root +""" + +RETURN = r""" +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "create_temporary": { + "query": {}, + "body": { + "credentials": "credentials", + "parent_path": "parent_path", + "prefix": "prefix", + "suffix": "suffix", + }, + "path": {"vm": "vm"}, + }, + "create": { + "query": {}, + "body": { + "create_parents": "create_parents", + "credentials": "credentials", + "path": "path", + }, + "path": {"vm": "vm"}, + }, + "delete": { + "query": {}, + "body": { + "credentials": "credentials", + "path": "path", + "recursive": "recursive", + }, + "path": {"vm": "vm"}, + }, + "move": { + "query": {}, + "body": {"credentials": "credentials", "new_path": "new_path", "path": "path"}, + "path": {"vm": "vm"}, + }, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["create_parents"] = {"type": "bool"} + argument_spec["credentials"] = {"required": True, "type": "dict"} + argument_spec["new_path"] = {"type": "str"} + argument_spec["parent_path"] = {"type": "str"} + argument_spec["path"] = {"type": "str"} + argument_spec["prefix"] = {"type": "str"} + argument_spec["recursive"] = {"type": "bool"} + argument_spec["state"] = { + "type": "str", + "choices": ["absent", "create_temporary", "move", "present"], + "default": "present", + } + argument_spec["suffix"] = {"type": "str"} + argument_spec["vm"] = {"required": True, "type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ( + "https://{vcenter_hostname}" + "/api/vcenter/vm/{vm}/guest/filesystem/directories?action=create" + ).format(**params) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _create(params, session): + + uniquity_keys = [] + + payload = prepare_payload(params, PAYLOAD_FORMAT["create"]) + _url = ( + "https://{vcenter_hostname}" + "/api/vcenter/vm/{vm}/guest/filesystem/directories?action=create" + ).format(**params) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + if resp.status == 500: + text = await resp.text() + raise EmbeddedModuleFailure( + f"Request has failed: status={resp.status}, {text}" + ) + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + + if (resp.status in [200, 201]) and "error" not in _json: + if isinstance(_json, str): # 7.0.2 and greater + _id = _json # TODO: fetch the object + elif isinstance(_json, dict) and "value" not in _json: + _id = list(_json["value"].values())[0] + elif isinstance(_json, dict) and "value" in _json: + _id = _json["value"] + _json_device_info = await get_device_info(session, _url, _id) + if _json_device_info: + _json = _json_device_info + + return await update_changed_flag(_json, resp.status, "create") + + +async def _create_temporary(params, session): + _in_query_parameters = PAYLOAD_FORMAT["create_temporary"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["create_temporary"]) + subdevice_type = get_subdevice_type( + "/api/vcenter/vm/{vm}/guest/filesystem/directories?action=createTemporary" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/vcenter/vm/{vm}/guest/filesystem/directories?action=createTemporary" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "create_temporary") + + +async def _delete(params, session): + _in_query_parameters = PAYLOAD_FORMAT["delete"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["delete"]) + subdevice_type = get_subdevice_type( + "/api/vcenter/vm/{vm}/guest/filesystem/directories?action=delete" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + "/api/vcenter/vm/{vm}/guest/filesystem/directories?action=delete" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "delete") + + +async def _move(params, session): + _in_query_parameters = PAYLOAD_FORMAT["move"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["move"]) + subdevice_type = get_subdevice_type( + "/api/vcenter/vm/{vm}/guest/filesystem/directories?action=move" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/vcenter/vm/{vm}/guest/filesystem/directories?action=move" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "move") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_guest_identity_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_guest_identity_info.py new file mode 100644 index 00000000..387cefca --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_guest_identity_info.py @@ -0,0 +1,239 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_guest_identity_info +short_description: Return information about the guest. +description: Return information about the guest. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Identifier of the virtual machine. Required with I(state=['get']) + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Get guest identity information + vmware.vmware_rest.vcenter_vm_guest_identity_info: + vm: '{{ test_vm1_info.id }}' +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get guest identity information +value: + description: Get guest identity information + returned: On success + sample: + family: LINUX + full_name: + args: [] + default_message: Red Hat Fedora (64-bit) + id: vmsg.guestos.fedora64Guest.label + host_name: localhost.localdomain + name: FEDORA_64 + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"vm": "vm"}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["vm"] = {"type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/guest/identity").format( + **params + ) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/guest/identity").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_guest_localfilesystem_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_guest_localfilesystem_info.py new file mode 100644 index 00000000..31f73f67 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_guest_localfilesystem_info.py @@ -0,0 +1,241 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_guest_localfilesystem_info +short_description: Returns details of the local file systems in the guest operating + system. +description: Returns details of the local file systems in the guest operating system. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Identifier of the virtual machine. Required with I(state=['get']) + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Get guest filesystem information + vmware.vmware_rest.vcenter_vm_guest_localfilesystem_info: + vm: '{{ test_vm1_info.id }}' + until: + - _result is not failed + retries: 60 + delay: 5 +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get guest filesystem information +value: + description: Get guest filesystem information + returned: On success + sample: + /: + capacity: 2515173376 + free_space: 774778880 + mappings: [] + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"vm": "vm"}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["vm"] = {"type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/guest/local-filesystem" + ).format(**params) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/guest/local-filesystem" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_guest_networking_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_guest_networking_info.py new file mode 100644 index 00000000..fbcf99cc --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_guest_networking_info.py @@ -0,0 +1,242 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_guest_networking_info +short_description: Returns information about the network configuration in the guest + operating system. +description: Returns information about the network configuration in the guest operating + system. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine ID Required with I(state=['get']) + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Get guest networking information + vmware.vmware_rest.vcenter_vm_guest_networking_info: + vm: '{{ test_vm1_info.id }}' +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get guest networking information +value: + description: Get guest networking information + returned: On success + sample: + dns: + ip_addresses: + - 10.0.2.3 + search_domains: + - localdomain + dns_values: + domain_name: localdomain + host_name: localhost.localdomain + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"vm": "vm"}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["vm"] = {"type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/guest/networking" + ).format(**params) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/guest/networking" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_guest_networking_interfaces_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_guest_networking_interfaces_info.py new file mode 100644 index 00000000..c424dc74 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_guest_networking_interfaces_info.py @@ -0,0 +1,231 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_guest_networking_interfaces_info +short_description: Returns information about the networking interfaces in the guest + operating system. +description: Returns information about the networking interfaces in the guest operating + system. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine ID Required with I(state=['list']) + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Get guest network interfaces information + vmware.vmware_rest.vcenter_vm_guest_networking_interfaces_info: + vm: '{{ test_vm1_info.id }}' +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get guest network interfaces information +value: + description: Get guest network interfaces information + returned: On success + sample: + - ip: + ip_addresses: [] + mac_address: 00:50:56:87:8f:08 + nic: '4000' + type: list +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "list": {"query": {}, "body": {}, "path": {"vm": "vm"}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["vm"] = {"type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_list_and_get_module.j2 +def build_url(params): + _in_query_parameters = PAYLOAD_FORMAT["list"]["query"].keys() + return ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/guest/networking/interfaces" + ).format(**params) + gen_args(params, _in_query_parameters) + + +async def entry_point(module, session): + url = build_url(module.params) + async with session.get(url, **session_timeout(module.params)) as resp: + _json = await resp.json() + + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_guest_networking_routes_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_guest_networking_routes_info.py new file mode 100644 index 00000000..6cc997d5 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_guest_networking_routes_info.py @@ -0,0 +1,226 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_guest_networking_routes_info +short_description: Returns information about network routing in the guest operating + system. +description: Returns information about network routing in the guest operating system. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine ID Required with I(state=['list']) + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Get guest network routes information + vmware.vmware_rest.vcenter_vm_guest_networking_routes_info: + vm: '{{ test_vm1_info.id }}' +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get guest network routes information +value: + description: Get guest network routes information + returned: On success + sample: [] + type: list +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "list": {"query": {}, "body": {}, "path": {"vm": "vm"}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["vm"] = {"type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_list_and_get_module.j2 +def build_url(params): + _in_query_parameters = PAYLOAD_FORMAT["list"]["query"].keys() + return ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/guest/networking/routes" + ).format(**params) + gen_args(params, _in_query_parameters) + + +async def entry_point(module, session): + url = build_url(module.params) + async with session.get(url, **session_timeout(module.params)) as resp: + _json = await resp.json() + + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_guest_operations_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_guest_operations_info.py new file mode 100644 index 00000000..bc8bab73 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_guest_operations_info.py @@ -0,0 +1,212 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_guest_operations_info +short_description: Get information about the guest operation status. +description: Get information about the guest operation status. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Identifier of the virtual machine. Required with I(state=['get']) + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.0.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +""" + +RETURN = r""" +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"vm": "vm"}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["vm"] = {"type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/guest/operations" + ).format(**params) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/guest/operations" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_guest_power.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_guest_power.py new file mode 100644 index 00000000..cbe0567a --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_guest_power.py @@ -0,0 +1,361 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_guest_power +short_description: Issues a request to the guest operating system asking it to perform + a soft shutdown, standby (suspend) or soft reboot +description: Issues a request to the guest operating system asking it to perform a + soft shutdown, standby (suspend) or soft reboot. This request returns immediately + and does not wait for the guest operating. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - reboot + - shutdown + - standby + description: [] + required: true + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Identifier of the virtual machine. This parameter is mandatory. + required: true + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +seealso: +- description: A module to boot, hard shutdown and hard reset guest + module: vmware.vmware_rest.vcenter_vm_power +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Create a VM + vmware.vmware_rest.vcenter_vm: + placement: + cluster: "{{ lookup('vmware.vmware_rest.cluster_moid', '/my_dc/host/my_cluster')\ + \ }}" + datastore: "{{ lookup('vmware.vmware_rest.datastore_moid', '/my_dc/datastore/local')\ + \ }}" + folder: "{{ lookup('vmware.vmware_rest.folder_moid', '/my_dc/vm') }}" + resource_pool: "{{ lookup('vmware.vmware_rest.resource_pool_moid', '/my_dc/host/my_cluster/Resources')\ + \ }}" + name: test_vm1 + guest_OS: RHEL_7_64 + hardware_version: VMX_11 + memory: + hot_add_enabled: true + size_MiB: 1024 + disks: + - type: SATA + backing: + type: VMDK_FILE + vmdk_file: '[local] test_vm1/{{ disk_name }}.vmdk' + - type: SATA + new_vmdk: + name: second_disk + capacity: 32000000000 + cdroms: + - type: SATA + sata: + bus: 0 + unit: 2 + nics: + - backing: + type: STANDARD_PORTGROUP + network: "{{ lookup('vmware.vmware_rest.network_moid', '/my_dc/network/VM\ + \ Network') }}" + + register: my_vm + +- name: Shut down the VM + vmware.vmware_rest.vcenter_vm_guest_power: + state: shutdown + vm: '{{ my_vm.id }}' +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Shut down the VM +value: + description: Shut down the VM + returned: On success + sample: {} + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "shutdown": {"query": {}, "body": {}, "path": {"vm": "vm"}}, + "reboot": {"query": {}, "body": {}, "path": {"vm": "vm"}}, + "standby": {"query": {}, "body": {}, "path": {"vm": "vm"}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["state"] = { + "required": True, + "type": "str", + "choices": ["reboot", "shutdown", "standby"], + } + argument_spec["vm"] = {"required": True, "type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/guest/power").format( + **params + ) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _reboot(params, session): + _in_query_parameters = PAYLOAD_FORMAT["reboot"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["reboot"]) + subdevice_type = get_subdevice_type( + "/api/vcenter/vm/{vm}/guest/power?action=reboot" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/vcenter/vm/{vm}/guest/power?action=reboot" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "reboot") + + +async def _shutdown(params, session): + _in_query_parameters = PAYLOAD_FORMAT["shutdown"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["shutdown"]) + subdevice_type = get_subdevice_type( + "/api/vcenter/vm/{vm}/guest/power?action=shutdown" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/vcenter/vm/{vm}/guest/power?action=shutdown" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "shutdown") + + +async def _standby(params, session): + _in_query_parameters = PAYLOAD_FORMAT["standby"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["standby"]) + subdevice_type = get_subdevice_type( + "/api/vcenter/vm/{vm}/guest/power?action=standby" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/vcenter/vm/{vm}/guest/power?action=standby" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "standby") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_guest_power_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_guest_power_info.py new file mode 100644 index 00000000..c0c5f59b --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_guest_power_info.py @@ -0,0 +1,261 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_guest_power_info +short_description: Returns information about the guest operating system power state. +description: Returns information about the guest operating system power state. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Identifier of the virtual machine. Required with I(state=['get']) + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Create a VM + vmware.vmware_rest.vcenter_vm: + placement: + cluster: "{{ lookup('vmware.vmware_rest.cluster_moid', '/my_dc/host/my_cluster')\ + \ }}" + datastore: "{{ lookup('vmware.vmware_rest.datastore_moid', '/my_dc/datastore/local')\ + \ }}" + folder: "{{ lookup('vmware.vmware_rest.folder_moid', '/my_dc/vm') }}" + resource_pool: "{{ lookup('vmware.vmware_rest.resource_pool_moid', '/my_dc/host/my_cluster/Resources')\ + \ }}" + name: test_vm1 + guest_OS: RHEL_7_64 + hardware_version: VMX_11 + memory: + hot_add_enabled: true + size_MiB: 1024 + disks: + - type: SATA + backing: + type: VMDK_FILE + vmdk_file: '[local] test_vm1/{{ disk_name }}.vmdk' + - type: SATA + new_vmdk: + name: second_disk + capacity: 32000000000 + cdroms: + - type: SATA + sata: + bus: 0 + unit: 2 + nics: + - backing: + type: STANDARD_PORTGROUP + network: "{{ lookup('vmware.vmware_rest.network_moid', '/my_dc/network/VM\ + \ Network') }}" + + register: my_vm + +- name: Read the power status of the VM + vmware.vmware_rest.vcenter_vm_guest_power_info: + vm: '{{ my_vm.id }}' +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Read the power status of the VM +value: + description: Read the power status of the VM + returned: On success + sample: + operations_ready: 0 + state: NOT_RUNNING + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"vm": "vm"}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["vm"] = {"type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/guest/power").format( + **params + ) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/guest/power").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware.py new file mode 100644 index 00000000..a1cb4a1f --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware.py @@ -0,0 +1,424 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_hardware +short_description: Updates the virtual hardware settings of a virtual machine. +description: Updates the virtual hardware settings of a virtual machine. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - present + - upgrade + default: present + description: [] + type: str + upgrade_policy: + choices: + - AFTER_CLEAN_SHUTDOWN + - ALWAYS + - NEVER + description: + - The C(upgrade_policy) defines the valid virtual hardware upgrade policies for + a virtual machine. + type: str + upgrade_version: + choices: + - VMX_03 + - VMX_04 + - VMX_06 + - VMX_07 + - VMX_08 + - VMX_09 + - VMX_10 + - VMX_11 + - VMX_12 + - VMX_13 + - VMX_14 + - VMX_15 + - VMX_16 + - VMX_17 + - VMX_18 + - VMX_19 + description: + - The C(version) defines the valid virtual hardware versions for a virtual machine. + See https://kb.vmware.com/s/article/1003746 (Virtual machine hardware versions + (1003746)). + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + version: + choices: + - VMX_03 + - VMX_04 + - VMX_06 + - VMX_07 + - VMX_08 + - VMX_09 + - VMX_10 + - VMX_11 + - VMX_12 + - VMX_13 + - VMX_14 + - VMX_15 + - VMX_16 + - VMX_17 + - VMX_18 + - VMX_19 + description: + - The C(version) defines the valid virtual hardware versions for a virtual machine. + See https://kb.vmware.com/s/article/1003746 (Virtual machine hardware versions + (1003746)). + type: str + vm: + description: + - Virtual machine identifier. This parameter is mandatory. + required: true + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Upgrade the VM hardware version + vmware.vmware_rest.vcenter_vm_hardware: + upgrade_policy: AFTER_CLEAN_SHUTDOWN + upgrade_version: VMX_11 + vm: "{{ lookup('vmware.vmware_rest.vm_moid', '/my_dc/vm/test_vm1') }}" +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Upgrade the VM hardware version +id: + description: moid of the resource + returned: On success + sample: null + type: dict +value: + description: Upgrade the VM hardware version + returned: On success + sample: {} + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "upgrade": {"query": {}, "body": {"version": "version"}, "path": {"vm": "vm"}}, + "update": { + "query": {}, + "body": { + "upgrade_policy": "upgrade_policy", + "upgrade_version": "upgrade_version", + }, + "path": {"vm": "vm"}, + }, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["state"] = { + "type": "str", + "choices": ["present", "upgrade"], + "default": "present", + } + argument_spec["upgrade_policy"] = { + "type": "str", + "choices": ["AFTER_CLEAN_SHUTDOWN", "ALWAYS", "NEVER"], + } + argument_spec["upgrade_version"] = { + "type": "str", + "choices": [ + "VMX_03", + "VMX_04", + "VMX_06", + "VMX_07", + "VMX_08", + "VMX_09", + "VMX_10", + "VMX_11", + "VMX_12", + "VMX_13", + "VMX_14", + "VMX_15", + "VMX_16", + "VMX_17", + "VMX_18", + "VMX_19", + ], + } + argument_spec["version"] = { + "type": "str", + "choices": [ + "VMX_03", + "VMX_04", + "VMX_06", + "VMX_07", + "VMX_08", + "VMX_09", + "VMX_10", + "VMX_11", + "VMX_12", + "VMX_13", + "VMX_14", + "VMX_15", + "VMX_16", + "VMX_17", + "VMX_18", + "VMX_19", + ], + } + argument_spec["vm"] = {"required": True, "type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware").format( + **params + ) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _update(params, session): + payload = prepare_payload(params, PAYLOAD_FORMAT["update"]) + _url = ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware").format( + **params + ) + async with session.get(_url, **session_timeout(params)) as resp: + _json = await resp.json() + if "value" in _json: + value = _json["value"] + else: # 7.0.2 and greater + value = _json + for k, v in value.items(): + if k in payload: + if isinstance(payload[k], dict) and isinstance(v, dict): + to_delete = True + for _k in list(payload[k].keys()): + if payload[k][_k] != v.get(_k): + to_delete = False + if to_delete: + del payload[k] + elif payload[k] == v: + del payload[k] + elif payload[k] == {}: + del payload[k] + + if payload == {} or payload == {"spec": {}}: + # Nothing has changed + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + _json["id"] = params.get("None") + return await update_changed_flag(_json, resp.status, "get") + async with session.patch(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # e.g: content_configuration + if not _json and resp.status == 204: + async with session.get(_url, **session_timeout(params)) as resp_get: + _json_get = await resp_get.json() + if _json_get: + _json = _json_get + + _json["id"] = params.get("None") + return await update_changed_flag(_json, resp.status, "update") + + +async def _upgrade(params, session): + _in_query_parameters = PAYLOAD_FORMAT["upgrade"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["upgrade"]) + subdevice_type = get_subdevice_type("/api/vcenter/vm/{vm}/hardware?action=upgrade") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/vcenter/vm/{vm}/hardware?action=upgrade" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "upgrade") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_adapter_sata.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_adapter_sata.py new file mode 100644 index 00000000..fce9e6b2 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_adapter_sata.py @@ -0,0 +1,390 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_hardware_adapter_sata +short_description: Adds a virtual SATA adapter to the virtual machine. +description: Adds a virtual SATA adapter to the virtual machine. +options: + adapter: + description: + - Virtual SATA adapter identifier. Required with I(state=['absent']) + type: str + bus: + description: + - SATA bus number. + type: int + label: + description: + - The name of the item + type: str + pci_slot_number: + description: + - Address of the SATA adapter on the PCI bus. + type: int + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - absent + - present + default: present + description: [] + type: str + type: + choices: + - AHCI + description: + - The C(type) defines the valid emulation types for a virtual SATA adapter. + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine identifier. This parameter is mandatory. + required: true + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Create a SATA adapter at PCI slot 34 + vmware.vmware_rest.vcenter_vm_hardware_adapter_sata: + vm: '{{ test_vm1_info.id }}' + pci_slot_number: 34 + +- name: Remove SATA adapter at PCI slot 34 + vmware.vmware_rest.vcenter_vm_hardware_adapter_sata: + vm: '{{ test_vm1_info.id }}' + pci_slot_number: 34 + state: absent +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Create a SATA adapter at PCI slot 34 +id: + description: moid of the resource + returned: On success + sample: '15000' + type: str +value: + description: Create a SATA adapter at PCI slot 34 + returned: On success + sample: + bus: 0 + label: SATA controller 0 + pci_slot_number: 34 + type: AHCI + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "create": { + "query": {}, + "body": {"bus": "bus", "pci_slot_number": "pci_slot_number", "type": "type"}, + "path": {"vm": "vm"}, + }, + "delete": {"query": {}, "body": {}, "path": {"adapter": "adapter", "vm": "vm"}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["adapter"] = {"type": "str"} + argument_spec["bus"] = {"type": "int", "default": 0} + argument_spec["label"] = {"type": "str"} + argument_spec["pci_slot_number"] = {"type": "int"} + argument_spec["state"] = { + "type": "str", + "choices": ["absent", "present"], + "default": "present", + } + argument_spec["type"] = {"type": "str", "choices": ["AHCI"]} + argument_spec["vm"] = {"required": True, "type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/adapter/sata" + ).format(**params) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _create(params, session): + + lookup_url = per_id_url = build_url(params) + uniquity_keys = ["adapter"] + comp_func = None + + async def lookup_with_filters(params, session, url): + # e.g: for the datacenter resources + if "folder" not in params: + return + if "name" not in params: + return + async with session.get( + f"{url}?names={params['name']}&folders={params['folder']}" + ) as resp: + _json = await resp.json() + if isinstance(_json, list) and len(_json) == 1: + return await get_device_info(session, url, _json[0]["adapter"]) + + _json = None + + if params["adapter"]: + _json = await get_device_info(session, build_url(params), params["adapter"]) + + if not _json and (uniquity_keys or comp_func): + _json = await exists( + params, + session, + url=lookup_url, + uniquity_keys=uniquity_keys, + per_id_url=per_id_url, + comp_func=comp_func, + ) + + if not _json: + _json = await lookup_with_filters(params, session, build_url(params)) + + if _json: + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + if "_update" in globals(): + params["adapter"] = _json["id"] + return await globals()["_update"](params, session) + + return await update_changed_flag(_json, 200, "get") + + payload = prepare_payload(params, PAYLOAD_FORMAT["create"]) + _url = ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/adapter/sata" + ).format(**params) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + if resp.status == 500: + text = await resp.text() + raise EmbeddedModuleFailure( + f"Request has failed: status={resp.status}, {text}" + ) + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + + if (resp.status in [200, 201]) and "error" not in _json: + if isinstance(_json, str): # 7.0.2 and greater + _id = _json # TODO: fetch the object + elif isinstance(_json, dict) and "value" not in _json: + _id = list(_json["value"].values())[0] + elif isinstance(_json, dict) and "value" in _json: + _id = _json["value"] + _json_device_info = await get_device_info(session, _url, _id) + if _json_device_info: + _json = _json_device_info + + return await update_changed_flag(_json, resp.status, "create") + + +async def _delete(params, session): + _in_query_parameters = PAYLOAD_FORMAT["delete"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["delete"]) + subdevice_type = get_subdevice_type( + "/api/vcenter/vm/{vm}/hardware/adapter/sata/{adapter}" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + "/api/vcenter/vm/{vm}/hardware/adapter/sata/{adapter}" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.delete(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "delete") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_adapter_sata_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_adapter_sata_info.py new file mode 100644 index 00000000..6a1e040a --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_adapter_sata_info.py @@ -0,0 +1,274 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_hardware_adapter_sata_info +short_description: Returns information about a virtual SATA adapter. +description: Returns information about a virtual SATA adapter. +options: + adapter: + description: + - Virtual SATA adapter identifier. Required with I(state=['get']) + type: str + label: + description: + - The name of the item + type: str + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine identifier. This parameter is mandatory. + required: true + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Get information about a specific controller + vmware.vmware_rest.vcenter_vm_hardware_adapter_sata_info: + vm: '{{ test_vm1_info.id }}' + adapter: '{{ _sata_adapter_result_1.id }}' + +- name: List the controller + vmware.vmware_rest.vcenter_vm_hardware_adapter_sata_info: + vm: '{{ test_vm1_info.id }}' +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get information about a specific controller +id: + description: moid of the resource + returned: On success + sample: '15000' + type: str +value: + description: Get information about a specific controller + returned: On success + sample: + bus: 0 + label: SATA controller 0 + pci_slot_number: 34 + type: AHCI + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"adapter": "adapter", "vm": "vm"}}, + "list": {"query": {}, "body": {}, "path": {"vm": "vm"}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["adapter"] = {"type": "str"} + argument_spec["label"] = {"type": "str"} + argument_spec["vm"] = {"required": True, "type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_list_and_get_module.j2 +def build_url(params): + if params.get("adapter"): + _in_query_parameters = PAYLOAD_FORMAT["get"]["query"].keys() + return ( + ( + "https://{vcenter_hostname}" + "/api/vcenter/vm/{vm}/hardware/adapter/sata/" + ).format(**params) + + params["adapter"] + + gen_args(params, _in_query_parameters) + ) + _in_query_parameters = PAYLOAD_FORMAT["list"]["query"].keys() + return ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/adapter/sata" + ).format(**params) + gen_args(params, _in_query_parameters) + + +async def entry_point(module, session): + url = build_url(module.params) + async with session.get(url, **session_timeout(module.params)) as resp: + _json = await resp.json() + + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + + if module.params.get("adapter"): + _json["id"] = module.params.get("adapter") + elif module.params.get("label"): # TODO extend the list of filter + _json = await exists(module.params, session, url) + elif ( + isinstance(_json["value"], list) + and len(_json["value"]) > 0 + and isinstance(_json["value"][0], str) + ): + # this is a list of id, we fetch the details + full_device_list = await build_full_device_list(session, url, _json) + _json = {"value": [i["value"] for i in full_device_list]} + + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_adapter_scsi.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_adapter_scsi.py new file mode 100644 index 00000000..db5076ba --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_adapter_scsi.py @@ -0,0 +1,474 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_hardware_adapter_scsi +short_description: Adds a virtual SCSI adapter to the virtual machine. +description: Adds a virtual SCSI adapter to the virtual machine. +options: + adapter: + description: + - Virtual SCSI adapter identifier. Required with I(state=['absent', 'present']) + type: str + bus: + description: + - SCSI bus number. + type: int + label: + description: + - The name of the item + type: str + pci_slot_number: + description: + - Address of the SCSI adapter on the PCI bus. If the PCI address is invalid, + the server will change it when the VM is started or as the device is hot added. + type: int + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + sharing: + choices: + - NONE + - PHYSICAL + - VIRTUAL + description: + - The C(sharing) defines the valid bus sharing modes for a virtual SCSI adapter. + type: str + state: + choices: + - absent + - present + default: present + description: [] + type: str + type: + choices: + - BUSLOGIC + - LSILOGIC + - LSILOGICSAS + - PVSCSI + description: + - The C(type) defines the valid emulation types for a virtual SCSI adapter. + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine identifier. This parameter is mandatory. + required: true + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Create a SCSI adapter at PCI slot 35 + vmware.vmware_rest.vcenter_vm_hardware_adapter_scsi: + vm: '{{ test_vm1_info.id }}' + pci_slot_number: 35 + +- name: Drop the SCSI controller + vmware.vmware_rest.vcenter_vm_hardware_adapter_scsi: + vm: '{{ test_vm1_info.id }}' + pci_slot_number: 35 + state: absent +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Create a SCSI adapter at PCI slot 35 +id: + description: moid of the resource + returned: On success + sample: '1000' + type: str +value: + description: Create a SCSI adapter at PCI slot 35 + returned: On success + sample: + label: SCSI controller 0 + pci_slot_number: 35 + scsi: + bus: 0 + unit: 7 + sharing: NONE + type: PVSCSI + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "delete": {"query": {}, "body": {}, "path": {"adapter": "adapter", "vm": "vm"}}, + "create": { + "query": {}, + "body": { + "bus": "bus", + "pci_slot_number": "pci_slot_number", + "sharing": "sharing", + "type": "type", + }, + "path": {"vm": "vm"}, + }, + "update": { + "query": {}, + "body": {"sharing": "sharing"}, + "path": {"adapter": "adapter", "vm": "vm"}, + }, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["adapter"] = {"type": "str"} + argument_spec["bus"] = {"type": "int", "default": 0} + argument_spec["label"] = {"type": "str"} + argument_spec["pci_slot_number"] = {"type": "int"} + argument_spec["sharing"] = { + "type": "str", + "choices": ["NONE", "PHYSICAL", "VIRTUAL"], + } + argument_spec["state"] = { + "type": "str", + "choices": ["absent", "present"], + "default": "present", + } + argument_spec["type"] = { + "type": "str", + "choices": ["BUSLOGIC", "LSILOGIC", "LSILOGICSAS", "PVSCSI"], + } + argument_spec["vm"] = {"required": True, "type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/adapter/scsi" + ).format(**params) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _create(params, session): + + lookup_url = per_id_url = build_url(params) + uniquity_keys = ["adapter"] + comp_func = None + + async def lookup_with_filters(params, session, url): + # e.g: for the datacenter resources + if "folder" not in params: + return + if "name" not in params: + return + async with session.get( + f"{url}?names={params['name']}&folders={params['folder']}" + ) as resp: + _json = await resp.json() + if isinstance(_json, list) and len(_json) == 1: + return await get_device_info(session, url, _json[0]["adapter"]) + + _json = None + + if params["adapter"]: + _json = await get_device_info(session, build_url(params), params["adapter"]) + + if not _json and (uniquity_keys or comp_func): + _json = await exists( + params, + session, + url=lookup_url, + uniquity_keys=uniquity_keys, + per_id_url=per_id_url, + comp_func=comp_func, + ) + + if not _json: + _json = await lookup_with_filters(params, session, build_url(params)) + + if _json: + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + if "_update" in globals(): + params["adapter"] = _json["id"] + return await globals()["_update"](params, session) + + return await update_changed_flag(_json, 200, "get") + + payload = prepare_payload(params, PAYLOAD_FORMAT["create"]) + _url = ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/adapter/scsi" + ).format(**params) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + if resp.status == 500: + text = await resp.text() + raise EmbeddedModuleFailure( + f"Request has failed: status={resp.status}, {text}" + ) + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + + if (resp.status in [200, 201]) and "error" not in _json: + if isinstance(_json, str): # 7.0.2 and greater + _id = _json # TODO: fetch the object + elif isinstance(_json, dict) and "value" not in _json: + _id = list(_json["value"].values())[0] + elif isinstance(_json, dict) and "value" in _json: + _id = _json["value"] + _json_device_info = await get_device_info(session, _url, _id) + if _json_device_info: + _json = _json_device_info + + return await update_changed_flag(_json, resp.status, "create") + + +async def _delete(params, session): + _in_query_parameters = PAYLOAD_FORMAT["delete"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["delete"]) + subdevice_type = get_subdevice_type( + "/api/vcenter/vm/{vm}/hardware/adapter/scsi/{adapter}" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + "/api/vcenter/vm/{vm}/hardware/adapter/scsi/{adapter}" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.delete(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "delete") + + +async def _update(params, session): + payload = prepare_payload(params, PAYLOAD_FORMAT["update"]) + _url = ( + "https://{vcenter_hostname}" + "/api/vcenter/vm/{vm}/hardware/adapter/scsi/{adapter}" + ).format(**params) + async with session.get(_url, **session_timeout(params)) as resp: + _json = await resp.json() + if "value" in _json: + value = _json["value"] + else: # 7.0.2 and greater + value = _json + for k, v in value.items(): + if k in payload: + if isinstance(payload[k], dict) and isinstance(v, dict): + to_delete = True + for _k in list(payload[k].keys()): + if payload[k][_k] != v.get(_k): + to_delete = False + if to_delete: + del payload[k] + elif payload[k] == v: + del payload[k] + elif payload[k] == {}: + del payload[k] + + if payload == {} or payload == {"spec": {}}: + # Nothing has changed + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + _json["id"] = params.get("adapter") + return await update_changed_flag(_json, resp.status, "get") + async with session.patch(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # e.g: content_configuration + if not _json and resp.status == 204: + async with session.get(_url, **session_timeout(params)) as resp_get: + _json_get = await resp_get.json() + if _json_get: + _json = _json_get + + _json["id"] = params.get("adapter") + return await update_changed_flag(_json, resp.status, "update") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_adapter_scsi_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_adapter_scsi_info.py new file mode 100644 index 00000000..90b93f05 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_adapter_scsi_info.py @@ -0,0 +1,261 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_hardware_adapter_scsi_info +short_description: Returns information about a virtual SCSI adapter. +description: Returns information about a virtual SCSI adapter. +options: + adapter: + description: + - Virtual SCSI adapter identifier. Required with I(state=['get']) + type: str + label: + description: + - The name of the item + type: str + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine identifier. This parameter is mandatory. + required: true + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: List the SCSI adapter of a given VM + vmware.vmware_rest.vcenter_vm_hardware_adapter_scsi_info: + vm: '{{ test_vm1_info.id }}' +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: List the SCSI adapter of a given VM +value: + description: List the SCSI adapter of a given VM + returned: On success + sample: + - adapter: '1000' + type: list +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"adapter": "adapter", "vm": "vm"}}, + "list": {"query": {}, "body": {}, "path": {"vm": "vm"}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["adapter"] = {"type": "str"} + argument_spec["label"] = {"type": "str"} + argument_spec["vm"] = {"required": True, "type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_list_and_get_module.j2 +def build_url(params): + if params.get("adapter"): + _in_query_parameters = PAYLOAD_FORMAT["get"]["query"].keys() + return ( + ( + "https://{vcenter_hostname}" + "/api/vcenter/vm/{vm}/hardware/adapter/scsi/" + ).format(**params) + + params["adapter"] + + gen_args(params, _in_query_parameters) + ) + _in_query_parameters = PAYLOAD_FORMAT["list"]["query"].keys() + return ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/adapter/scsi" + ).format(**params) + gen_args(params, _in_query_parameters) + + +async def entry_point(module, session): + url = build_url(module.params) + async with session.get(url, **session_timeout(module.params)) as resp: + _json = await resp.json() + + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + + if module.params.get("adapter"): + _json["id"] = module.params.get("adapter") + elif module.params.get("label"): # TODO extend the list of filter + _json = await exists(module.params, session, url) + elif ( + isinstance(_json["value"], list) + and len(_json["value"]) > 0 + and isinstance(_json["value"][0], str) + ): + # this is a list of id, we fetch the details + full_device_list = await build_full_device_list(session, url, _json) + _json = {"value": [i["value"] for i in full_device_list]} + + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_boot.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_boot.py new file mode 100644 index 00000000..a9f3db61 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_boot.py @@ -0,0 +1,360 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_hardware_boot +short_description: Updates the boot-related settings of a virtual machine. +description: Updates the boot-related settings of a virtual machine. +options: + delay: + description: + - Delay in milliseconds before beginning the firmware boot process when the virtual + machine is powered on. This delay may be used to provide a time window for + users to connect to the virtual machine console and enter BIOS setup mode. + type: int + efi_legacy_boot: + description: + - Flag indicating whether to use EFI legacy boot mode. + type: bool + enter_setup_mode: + description: + - Flag indicating whether the firmware boot process should automatically enter + setup mode the next time the virtual machine boots. Note that this flag will + automatically be reset to false once the virtual machine enters setup mode. + type: bool + network_protocol: + choices: + - IPV4 + - IPV6 + description: + - The C(network_protocol) defines the valid network boot protocols supported when + booting a virtual machine with {@link Type#EFI} firmware over the network. + type: str + retry: + description: + - Flag indicating whether the virtual machine should automatically retry the boot + process after a failure. + type: bool + retry_delay: + description: + - Delay in milliseconds before retrying the boot process after a failure; applicable + only when {@link Info#retry} is true. + type: int + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - present + default: present + description: [] + type: str + type: + choices: + - BIOS + - EFI + description: + - The C(type) defines the valid firmware types for a virtual machine. + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine identifier. This parameter is mandatory. + required: true + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Change a VM boot parameters + vmware.vmware_rest.vcenter_vm_hardware_boot: + vm: '{{ test_vm1_info.id }}' + efi_legacy_boot: true + type: EFI +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Change a VM boot parameters +id: + description: moid of the resource + returned: On success + sample: null + type: dict +value: + description: Change a VM boot parameters + returned: On success + sample: {} + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "update": { + "query": {}, + "body": { + "delay": "delay", + "efi_legacy_boot": "efi_legacy_boot", + "enter_setup_mode": "enter_setup_mode", + "network_protocol": "network_protocol", + "retry": "retry", + "retry_delay": "retry_delay", + "type": "type", + }, + "path": {"vm": "vm"}, + } +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["delay"] = {"type": "int"} + argument_spec["efi_legacy_boot"] = {"type": "bool"} + argument_spec["enter_setup_mode"] = {"type": "bool"} + argument_spec["network_protocol"] = {"type": "str", "choices": ["IPV4", "IPV6"]} + argument_spec["retry"] = {"type": "bool"} + argument_spec["retry_delay"] = {"type": "int"} + argument_spec["state"] = { + "type": "str", + "choices": ["present"], + "default": "present", + } + argument_spec["type"] = {"type": "str", "choices": ["BIOS", "EFI"]} + argument_spec["vm"] = {"required": True, "type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/boot").format( + **params + ) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _update(params, session): + payload = prepare_payload(params, PAYLOAD_FORMAT["update"]) + _url = ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/boot").format( + **params + ) + async with session.get(_url, **session_timeout(params)) as resp: + _json = await resp.json() + if "value" in _json: + value = _json["value"] + else: # 7.0.2 and greater + value = _json + for k, v in value.items(): + if k in payload: + if isinstance(payload[k], dict) and isinstance(v, dict): + to_delete = True + for _k in list(payload[k].keys()): + if payload[k][_k] != v.get(_k): + to_delete = False + if to_delete: + del payload[k] + elif payload[k] == v: + del payload[k] + elif payload[k] == {}: + del payload[k] + + if payload == {} or payload == {"spec": {}}: + # Nothing has changed + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + _json["id"] = params.get("None") + return await update_changed_flag(_json, resp.status, "get") + async with session.patch(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # e.g: content_configuration + if not _json and resp.status == 204: + async with session.get(_url, **session_timeout(params)) as resp_get: + _json_get = await resp_get.json() + if _json_get: + _json = _json_get + + _json["id"] = params.get("None") + return await update_changed_flag(_json, resp.status, "update") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_boot_device.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_boot_device.py new file mode 100644 index 00000000..f2916898 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_boot_device.py @@ -0,0 +1,301 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_hardware_boot_device +short_description: Sets the virtual devices that will be used to boot the virtual + machine +description: Sets the virtual devices that will be used to boot the virtual machine. The + virtual machine will check the devices in order, attempting to boot from each, until + the virtual machine boots successfully. If the {@term list} is empty, the virtual + machine will use a default boot sequence. There should be no more than one instance + of {@link Entry} for a given device type except {@link Device.Type#ETHERNET} in + the {@term list}. +options: + devices: + description: + - Ordered list of boot devices. This parameter is mandatory. + - 'Valid attributes are:' + - ' - C(type) (str): The C(type) defines the valid device types that may be used + as bootable devices. ([''set''])' + - ' This key is required with [''set''].' + - ' - Accepted values:' + - ' - CDROM' + - ' - DISK' + - ' - ETHERNET' + - ' - FLOPPY' + - ' - C(nic) (str): Virtual Ethernet device. Ethernet device to use as boot device + for this entry. ([''set''])' + - ' - C(disks) (list): Virtual disk device. List of virtual disks in boot order. + ([''set''])' + elements: dict + required: true + type: list + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - set + default: set + description: [] + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine identifier. This parameter is mandatory. + required: true + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Set a boot device + vmware.vmware_rest.vcenter_vm_hardware_boot_device: + vm: '{{ test_vm1_info.id }}' + devices: + - type: CDROM +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Set a boot device +value: + description: Set a boot device + returned: On success + sample: {} + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "set": {"query": {}, "body": {"devices": "devices"}, "path": {"vm": "vm"}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["devices"] = {"required": True, "type": "list", "elements": "dict"} + argument_spec["state"] = {"type": "str", "choices": ["set"], "default": "set"} + argument_spec["vm"] = {"required": True, "type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/boot/device" + ).format(**params) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _set(params, session): + _in_query_parameters = PAYLOAD_FORMAT["set"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["set"]) + subdevice_type = get_subdevice_type("/api/vcenter/vm/{vm}/hardware/boot/device") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/boot/device" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.get(_url, json=payload, **session_timeout(params)) as resp: + before = await resp.json() + + async with session.put(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # The PUT answer does not let us know if the resource has actually been + # modified + if resp.status < 300: + async with session.get( + _url, json=payload, **session_timeout(params) + ) as resp_get: + after = await resp_get.json() + if before == after: + return await update_changed_flag(after, resp_get.status, "get") + return await update_changed_flag(_json, resp.status, "set") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_boot_device_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_boot_device_info.py new file mode 100644 index 00000000..fe07505c --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_boot_device_info.py @@ -0,0 +1,238 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_hardware_boot_device_info +short_description: Returns an ordered list of boot devices for the virtual machine +description: Returns an ordered list of boot devices for the virtual machine. If the + {@term list} is empty, the virtual machine uses a default boot sequence. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine identifier. Required with I(state=['get']) + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Get boot device info + vmware.vmware_rest.vcenter_vm_hardware_boot_device_info: + vm: '{{ test_vm1_info.id }}' + +- name: Get information about the boot device + vmware.vmware_rest.vcenter_vm_hardware_boot_device_info: + vm: '{{ test_vm1_info.id }}' +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get information about the boot device +value: + description: Get information about the boot device + returned: On success + sample: + - type: CDROM + type: list +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"vm": "vm"}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["vm"] = {"type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/boot/device" + ).format(**params) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/boot/device" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_boot_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_boot_info.py new file mode 100644 index 00000000..49c8b5c3 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_boot_info.py @@ -0,0 +1,237 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_hardware_boot_info +short_description: Returns the boot-related settings of a virtual machine. +description: Returns the boot-related settings of a virtual machine. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine identifier. Required with I(state=['get']) + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Retrieve the boot information from the VM + vmware.vmware_rest.vcenter_vm_hardware_boot_info: + vm: '{{ test_vm1_info.id }}' +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Retrieve the boot information from the VM +value: + description: Retrieve the boot information from the VM + returned: On success + sample: + delay: 0 + enter_setup_mode: 0 + retry: 0 + retry_delay: 10000 + type: BIOS + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"vm": "vm"}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["vm"] = {"type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/boot").format( + **params + ) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/boot").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_cdrom.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_cdrom.py new file mode 100644 index 00000000..e134212c --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_cdrom.py @@ -0,0 +1,568 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_hardware_cdrom +short_description: Adds a virtual CD-ROM device to the virtual machine. +description: Adds a virtual CD-ROM device to the virtual machine. +options: + allow_guest_control: + description: + - Flag indicating whether the guest can connect and disconnect the device. + type: bool + backing: + description: + - Physical resource backing for the virtual CD-ROM device. Required with I(state=['present']) + - 'Valid attributes are:' + - ' - C(type) (str): The C(backing_type) defines the valid backing types for a + virtual CD-ROM device. ([''present''])' + - ' This key is required with [''present''].' + - ' - Accepted values:' + - ' - CLIENT_DEVICE' + - ' - HOST_DEVICE' + - ' - ISO_FILE' + - ' - C(iso_file) (str): Path of the image file that should be used as the virtual + CD-ROM device backing. ([''present''])' + - ' - C(host_device) (str): Name of the device that should be used as the virtual + CD-ROM device backing. ([''present''])' + - ' - C(device_access_type) (str): The C(device_access_type) defines the valid + device access types for a physical device packing of a virtual CD-ROM device. + ([''present''])' + - ' - Accepted values:' + - ' - EMULATION' + - ' - PASSTHRU' + - ' - PASSTHRU_EXCLUSIVE' + type: dict + cdrom: + description: + - Virtual CD-ROM device identifier. Required with I(state=['absent', 'connect', + 'disconnect', 'present']) + type: str + ide: + description: + - Address for attaching the device to a virtual IDE adapter. + - 'Valid attributes are:' + - ' - C(primary) (bool): Flag specifying whether the device should be attached + to the primary or secondary IDE adapter of the virtual machine. ([''present''])' + - ' - C(master) (bool): Flag specifying whether the device should be the master + or slave device on the IDE adapter. ([''present''])' + type: dict + label: + description: + - The name of the item + type: str + sata: + description: + - Address for attaching the device to a virtual SATA adapter. Required with I(state=['present']) + - 'Valid attributes are:' + - ' - C(bus) (int): Bus number of the adapter to which the device should be attached. + ([''present''])' + - ' This key is required with [''present''].' + - ' - C(unit) (int): Unit number of the device. ([''present''])' + type: dict + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + start_connected: + description: + - Flag indicating whether the virtual device should be connected whenever the + virtual machine is powered on. + type: bool + state: + choices: + - absent + - connect + - disconnect + - present + default: present + description: [] + type: str + type: + choices: + - IDE + - SATA + description: + - The C(host_bus_adapter_type) defines the valid types of host bus adapters that + may be used for attaching a Cdrom to a virtual machine. + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine identifier. This parameter is mandatory. + required: true + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Attach an ISO image to a guest VM + vmware.vmware_rest.vcenter_vm_hardware_cdrom: + vm: '{{ test_vm1_info.id }}' + type: SATA + sata: + bus: 0 + unit: 2 + start_connected: true + backing: + iso_file: '[ro_datastore] fedora.iso' + type: ISO_FILE +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Attach an ISO image to a guest VM +id: + description: moid of the resource + returned: On success + sample: '16002' + type: str +value: + description: Attach an ISO image to a guest VM + returned: On success + sample: + allow_guest_control: 0 + backing: + iso_file: '[ro_datastore] fedora.iso' + type: ISO_FILE + label: CD/DVD drive 1 + sata: + bus: 0 + unit: 2 + start_connected: 1 + state: NOT_CONNECTED + type: SATA + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "connect": {"query": {}, "body": {}, "path": {"cdrom": "cdrom", "vm": "vm"}}, + "update": { + "query": {}, + "body": { + "allow_guest_control": "allow_guest_control", + "backing": "backing", + "start_connected": "start_connected", + }, + "path": {"cdrom": "cdrom", "vm": "vm"}, + }, + "create": { + "query": {}, + "body": { + "allow_guest_control": "allow_guest_control", + "backing": "backing", + "ide": "ide", + "sata": "sata", + "start_connected": "start_connected", + "type": "type", + }, + "path": {"vm": "vm"}, + }, + "disconnect": {"query": {}, "body": {}, "path": {"cdrom": "cdrom", "vm": "vm"}}, + "delete": {"query": {}, "body": {}, "path": {"cdrom": "cdrom", "vm": "vm"}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["allow_guest_control"] = {"type": "bool"} + argument_spec["backing"] = {"type": "dict"} + argument_spec["cdrom"] = {"type": "str"} + argument_spec["ide"] = {"type": "dict"} + argument_spec["label"] = {"type": "str"} + argument_spec["sata"] = {"type": "dict"} + argument_spec["start_connected"] = {"type": "bool"} + argument_spec["state"] = { + "type": "str", + "choices": ["absent", "connect", "disconnect", "present"], + "default": "present", + } + argument_spec["type"] = {"type": "str", "choices": ["IDE", "SATA"]} + argument_spec["vm"] = {"required": True, "type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/cdrom").format( + **params + ) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _connect(params, session): + _in_query_parameters = PAYLOAD_FORMAT["connect"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["connect"]) + subdevice_type = get_subdevice_type( + "/api/vcenter/vm/{vm}/hardware/cdrom/{cdrom}?action=connect" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/vcenter/vm/{vm}/hardware/cdrom/{cdrom}?action=connect" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "connect") + + +async def _create(params, session): + + lookup_url = per_id_url = build_url(params) + uniquity_keys = ["cdrom"] + comp_func = None + + async def lookup_with_filters(params, session, url): + # e.g: for the datacenter resources + if "folder" not in params: + return + if "name" not in params: + return + async with session.get( + f"{url}?names={params['name']}&folders={params['folder']}" + ) as resp: + _json = await resp.json() + if isinstance(_json, list) and len(_json) == 1: + return await get_device_info(session, url, _json[0]["cdrom"]) + + _json = None + + if params["cdrom"]: + _json = await get_device_info(session, build_url(params), params["cdrom"]) + + if not _json and (uniquity_keys or comp_func): + _json = await exists( + params, + session, + url=lookup_url, + uniquity_keys=uniquity_keys, + per_id_url=per_id_url, + comp_func=comp_func, + ) + + if not _json: + _json = await lookup_with_filters(params, session, build_url(params)) + + if _json: + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + if "_update" in globals(): + params["cdrom"] = _json["id"] + return await globals()["_update"](params, session) + + return await update_changed_flag(_json, 200, "get") + + payload = prepare_payload(params, PAYLOAD_FORMAT["create"]) + _url = ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/cdrom").format( + **params + ) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + if resp.status == 500: + text = await resp.text() + raise EmbeddedModuleFailure( + f"Request has failed: status={resp.status}, {text}" + ) + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + + if (resp.status in [200, 201]) and "error" not in _json: + if isinstance(_json, str): # 7.0.2 and greater + _id = _json # TODO: fetch the object + elif isinstance(_json, dict) and "value" not in _json: + _id = list(_json["value"].values())[0] + elif isinstance(_json, dict) and "value" in _json: + _id = _json["value"] + _json_device_info = await get_device_info(session, _url, _id) + if _json_device_info: + _json = _json_device_info + + return await update_changed_flag(_json, resp.status, "create") + + +async def _delete(params, session): + _in_query_parameters = PAYLOAD_FORMAT["delete"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["delete"]) + subdevice_type = get_subdevice_type("/api/vcenter/vm/{vm}/hardware/cdrom/{cdrom}") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/cdrom/{cdrom}" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.delete(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "delete") + + +async def _disconnect(params, session): + _in_query_parameters = PAYLOAD_FORMAT["disconnect"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["disconnect"]) + subdevice_type = get_subdevice_type( + "/api/vcenter/vm/{vm}/hardware/cdrom/{cdrom}?action=disconnect" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/vcenter/vm/{vm}/hardware/cdrom/{cdrom}?action=disconnect" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "disconnect") + + +async def _update(params, session): + payload = prepare_payload(params, PAYLOAD_FORMAT["update"]) + _url = ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/cdrom/{cdrom}" + ).format(**params) + async with session.get(_url, **session_timeout(params)) as resp: + _json = await resp.json() + if "value" in _json: + value = _json["value"] + else: # 7.0.2 and greater + value = _json + for k, v in value.items(): + if k in payload: + if isinstance(payload[k], dict) and isinstance(v, dict): + to_delete = True + for _k in list(payload[k].keys()): + if payload[k][_k] != v.get(_k): + to_delete = False + if to_delete: + del payload[k] + elif payload[k] == v: + del payload[k] + elif payload[k] == {}: + del payload[k] + + if payload == {} or payload == {"spec": {}}: + # Nothing has changed + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + _json["id"] = params.get("cdrom") + return await update_changed_flag(_json, resp.status, "get") + async with session.patch(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # e.g: content_configuration + if not _json and resp.status == 204: + async with session.get(_url, **session_timeout(params)) as resp_get: + _json_get = await resp_get.json() + if _json_get: + _json = _json_get + + _json["id"] = params.get("cdrom") + return await update_changed_flag(_json, resp.status, "update") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_cdrom_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_cdrom_info.py new file mode 100644 index 00000000..faf3d9d3 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_cdrom_info.py @@ -0,0 +1,259 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_hardware_cdrom_info +short_description: Returns information about a virtual CD-ROM device. +description: Returns information about a virtual CD-ROM device. +options: + cdrom: + description: + - Virtual CD-ROM device identifier. Required with I(state=['get']) + type: str + label: + description: + - The name of the item + type: str + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine identifier. This parameter is mandatory. + required: true + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: List the cdrom devices on the guest + vmware.vmware_rest.vcenter_vm_hardware_cdrom_info: + vm: '{{ test_vm1_info.id }}' +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: List the cdrom devices on the guest +value: + description: List the cdrom devices on the guest + returned: On success + sample: [] + type: list +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"cdrom": "cdrom", "vm": "vm"}}, + "list": {"query": {}, "body": {}, "path": {"vm": "vm"}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["cdrom"] = {"type": "str"} + argument_spec["label"] = {"type": "str"} + argument_spec["vm"] = {"required": True, "type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_list_and_get_module.j2 +def build_url(params): + if params.get("cdrom"): + _in_query_parameters = PAYLOAD_FORMAT["get"]["query"].keys() + return ( + ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/cdrom/" + ).format(**params) + + params["cdrom"] + + gen_args(params, _in_query_parameters) + ) + _in_query_parameters = PAYLOAD_FORMAT["list"]["query"].keys() + return ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/cdrom").format( + **params + ) + gen_args(params, _in_query_parameters) + + +async def entry_point(module, session): + url = build_url(module.params) + async with session.get(url, **session_timeout(module.params)) as resp: + _json = await resp.json() + + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + + if module.params.get("cdrom"): + _json["id"] = module.params.get("cdrom") + elif module.params.get("label"): # TODO extend the list of filter + _json = await exists(module.params, session, url) + elif ( + isinstance(_json["value"], list) + and len(_json["value"]) > 0 + and isinstance(_json["value"][0], str) + ): + # this is a list of id, we fetch the details + full_device_list = await build_full_device_list(session, url, _json) + _json = {"value": [i["value"] for i in full_device_list]} + + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_cpu.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_cpu.py new file mode 100644 index 00000000..4e1cfedc --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_cpu.py @@ -0,0 +1,340 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_hardware_cpu +short_description: Updates the CPU-related settings of a virtual machine. +description: Updates the CPU-related settings of a virtual machine. +options: + cores_per_socket: + description: + - New number of CPU cores per socket. The number of CPU cores in the virtual + machine must be a multiple of the number of cores per socket. + type: int + count: + description: + - New number of CPU cores. The number of CPU cores in the virtual machine must + be a multiple of the number of cores per socket. The supported range of CPU + counts is constrained by the configured guest operating system and virtual hardware + version of the virtual machine. If the virtual machine is running, the number + of CPU cores may only be increased if {@link Info#hotAddEnabled} is true, and + may only be decreased if {@link Info#hotRemoveEnabled} is true. + type: int + hot_add_enabled: + description: + - Flag indicating whether adding CPUs while the virtual machine is running is + enabled. This field may only be modified if the virtual machine is powered off. + type: bool + hot_remove_enabled: + description: + - Flag indicating whether removing CPUs while the virtual machine is running is + enabled. This field may only be modified if the virtual machine is powered off. + type: bool + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - present + default: present + description: [] + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine identifier. This parameter is mandatory. + required: true + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Dedicate one core to the VM + vmware.vmware_rest.vcenter_vm_hardware_cpu: + vm: '{{ test_vm1_info.id }}' + count: 1 +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Dedicate one core to the VM +id: + description: moid of the resource + returned: On success + sample: null + type: dict +value: + description: Dedicate one core to the VM + returned: On success + sample: + cores_per_socket: 1 + count: 1 + hot_add_enabled: 0 + hot_remove_enabled: 0 + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "update": { + "query": {}, + "body": { + "cores_per_socket": "cores_per_socket", + "count": "count", + "hot_add_enabled": "hot_add_enabled", + "hot_remove_enabled": "hot_remove_enabled", + }, + "path": {"vm": "vm"}, + } +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["cores_per_socket"] = {"type": "int"} + argument_spec["count"] = {"type": "int"} + argument_spec["hot_add_enabled"] = {"type": "bool"} + argument_spec["hot_remove_enabled"] = {"type": "bool"} + argument_spec["state"] = { + "type": "str", + "choices": ["present"], + "default": "present", + } + argument_spec["vm"] = {"required": True, "type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/cpu").format( + **params + ) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _update(params, session): + payload = prepare_payload(params, PAYLOAD_FORMAT["update"]) + _url = ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/cpu").format( + **params + ) + async with session.get(_url, **session_timeout(params)) as resp: + _json = await resp.json() + if "value" in _json: + value = _json["value"] + else: # 7.0.2 and greater + value = _json + for k, v in value.items(): + if k in payload: + if isinstance(payload[k], dict) and isinstance(v, dict): + to_delete = True + for _k in list(payload[k].keys()): + if payload[k][_k] != v.get(_k): + to_delete = False + if to_delete: + del payload[k] + elif payload[k] == v: + del payload[k] + elif payload[k] == {}: + del payload[k] + + if payload == {} or payload == {"spec": {}}: + # Nothing has changed + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + _json["id"] = params.get("None") + return await update_changed_flag(_json, resp.status, "get") + async with session.patch(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # e.g: content_configuration + if not _json and resp.status == 204: + async with session.get(_url, **session_timeout(params)) as resp_get: + _json_get = await resp_get.json() + if _json_get: + _json = _json_get + + _json["id"] = params.get("None") + return await update_changed_flag(_json, resp.status, "update") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_cpu_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_cpu_info.py new file mode 100644 index 00000000..0e541648 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_cpu_info.py @@ -0,0 +1,236 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_hardware_cpu_info +short_description: Returns the CPU-related settings of a virtual machine. +description: Returns the CPU-related settings of a virtual machine. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine identifier. Required with I(state=['get']) + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Retrieve the CPU information from the VM + vmware.vmware_rest.vcenter_vm_hardware_cpu_info: + vm: '{{ test_vm1_info.id }}' +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Retrieve the CPU information from the VM +value: + description: Retrieve the CPU information from the VM + returned: On success + sample: + cores_per_socket: 1 + count: 1 + hot_add_enabled: 0 + hot_remove_enabled: 0 + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"vm": "vm"}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["vm"] = {"type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/cpu").format( + **params + ) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/cpu").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_disk.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_disk.py new file mode 100644 index 00000000..cd3ec639 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_disk.py @@ -0,0 +1,512 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_hardware_disk +short_description: Adds a virtual disk to the virtual machine +description: Adds a virtual disk to the virtual machine. While adding the virtual + disk, a new VMDK file may be created or an existing VMDK file may be used to back + the virtual disk. +options: + backing: + description: + - Existing physical resource backing for the virtual disk. Exactly one of C(#backing) + or C(#new_vmdk) must be specified. Required with I(state=['present']) + - 'Valid attributes are:' + - ' - C(type) (str): The C(backing_type) defines the valid backing types for a + virtual disk. ([''present''])' + - ' This key is required with [''present''].' + - ' - Accepted values:' + - ' - VMDK_FILE' + - ' - C(vmdk_file) (str): Path of the VMDK file backing the virtual disk. ([''present''])' + type: dict + disk: + description: + - Virtual disk identifier. Required with I(state=['absent', 'present']) + type: str + ide: + description: + - Address for attaching the device to a virtual IDE adapter. + - 'Valid attributes are:' + - ' - C(primary) (bool): Flag specifying whether the device should be attached + to the primary or secondary IDE adapter of the virtual machine. ([''present''])' + - ' - C(master) (bool): Flag specifying whether the device should be the master + or slave device on the IDE adapter. ([''present''])' + type: dict + label: + description: + - The name of the item + type: str + new_vmdk: + description: + - Specification for creating a new VMDK backing for the virtual disk. Exactly + one of C(#backing) or C(#new_vmdk) must be specified. + - 'Valid attributes are:' + - ' - C(name) (str): Base name of the VMDK file. The name should not include + the ''.vmdk'' file extension. ([''present''])' + - ' - C(capacity) (int): Capacity of the virtual disk backing in bytes. ([''present''])' + - ' - C(storage_policy) (dict): The C(storage_policy_spec) {@term structure} contains + information about the storage policy that is to be associated the with VMDK + file. ([''present''])' + - ' - Accepted keys:' + - ' - policy (string): Identifier of the storage policy which should be associated + with the VMDK file.' + type: dict + sata: + description: + - Address for attaching the device to a virtual SATA adapter. Required with I(state=['present']) + - 'Valid attributes are:' + - ' - C(bus) (int): Bus number of the adapter to which the device should be attached. + ([''present''])' + - ' This key is required with [''present''].' + - ' - C(unit) (int): Unit number of the device. ([''present''])' + type: dict + scsi: + description: + - Address for attaching the device to a virtual SCSI adapter. Required with I(state=['present']) + - 'Valid attributes are:' + - ' - C(bus) (int): Bus number of the adapter to which the device should be attached. + ([''present''])' + - ' This key is required with [''present''].' + - ' - C(unit) (int): Unit number of the device. ([''present''])' + type: dict + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - absent + - present + default: present + description: [] + type: str + type: + choices: + - IDE + - SATA + - SCSI + description: + - The C(host_bus_adapter_type) defines the valid types of host bus adapters that + may be used for attaching a virtual storage device to a virtual machine. + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine identifier. This parameter is mandatory. + required: true + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Create a new disk + vmware.vmware_rest.vcenter_vm_hardware_disk: + vm: '{{ test_vm1_info.id }}' + type: SATA + new_vmdk: + capacity: 320000 + register: my_new_disk + +- name: Delete the disk + vmware.vmware_rest.vcenter_vm_hardware_disk: + vm: '{{ test_vm1_info.id }}' + disk: '{{ my_new_disk.id }}' + state: absent +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Create a new disk +id: + description: moid of the resource + returned: On success + sample: '16000' + type: str +value: + description: Create a new disk + returned: On success + sample: + backing: + type: VMDK_FILE + vmdk_file: '[local] test_vm1_1/test_vm1_1.vmdk' + capacity: 320000 + label: Hard disk 2 + sata: + bus: 0 + unit: 0 + type: SATA + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "delete": {"query": {}, "body": {}, "path": {"disk": "disk", "vm": "vm"}}, + "create": { + "query": {}, + "body": { + "backing": "backing", + "ide": "ide", + "new_vmdk": "new_vmdk", + "sata": "sata", + "scsi": "scsi", + "type": "type", + }, + "path": {"vm": "vm"}, + }, + "update": { + "query": {}, + "body": {"backing": "backing"}, + "path": {"disk": "disk", "vm": "vm"}, + }, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["backing"] = {"type": "dict"} + argument_spec["disk"] = {"type": "str"} + argument_spec["ide"] = {"type": "dict"} + argument_spec["label"] = {"type": "str"} + argument_spec["new_vmdk"] = {"type": "dict"} + argument_spec["sata"] = {"type": "dict"} + argument_spec["scsi"] = {"type": "dict"} + argument_spec["state"] = { + "type": "str", + "choices": ["absent", "present"], + "default": "present", + } + argument_spec["type"] = {"type": "str", "choices": ["IDE", "SATA", "SCSI"]} + argument_spec["vm"] = {"required": True, "type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/disk").format( + **params + ) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _create(params, session): + + lookup_url = per_id_url = build_url(params) + uniquity_keys = ["disk"] + comp_func = None + + async def lookup_with_filters(params, session, url): + # e.g: for the datacenter resources + if "folder" not in params: + return + if "name" not in params: + return + async with session.get( + f"{url}?names={params['name']}&folders={params['folder']}" + ) as resp: + _json = await resp.json() + if isinstance(_json, list) and len(_json) == 1: + return await get_device_info(session, url, _json[0]["disk"]) + + _json = None + + if params["disk"]: + _json = await get_device_info(session, build_url(params), params["disk"]) + + if not _json and (uniquity_keys or comp_func): + _json = await exists( + params, + session, + url=lookup_url, + uniquity_keys=uniquity_keys, + per_id_url=per_id_url, + comp_func=comp_func, + ) + + if not _json: + _json = await lookup_with_filters(params, session, build_url(params)) + + if _json: + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + if "_update" in globals(): + params["disk"] = _json["id"] + return await globals()["_update"](params, session) + + return await update_changed_flag(_json, 200, "get") + + payload = prepare_payload(params, PAYLOAD_FORMAT["create"]) + _url = ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/disk").format( + **params + ) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + if resp.status == 500: + text = await resp.text() + raise EmbeddedModuleFailure( + f"Request has failed: status={resp.status}, {text}" + ) + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + + if (resp.status in [200, 201]) and "error" not in _json: + if isinstance(_json, str): # 7.0.2 and greater + _id = _json # TODO: fetch the object + elif isinstance(_json, dict) and "value" not in _json: + _id = list(_json["value"].values())[0] + elif isinstance(_json, dict) and "value" in _json: + _id = _json["value"] + _json_device_info = await get_device_info(session, _url, _id) + if _json_device_info: + _json = _json_device_info + + return await update_changed_flag(_json, resp.status, "create") + + +async def _delete(params, session): + _in_query_parameters = PAYLOAD_FORMAT["delete"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["delete"]) + subdevice_type = get_subdevice_type("/api/vcenter/vm/{vm}/hardware/disk/{disk}") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/disk/{disk}" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.delete(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "delete") + + +async def _update(params, session): + payload = prepare_payload(params, PAYLOAD_FORMAT["update"]) + _url = ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/disk/{disk}" + ).format(**params) + async with session.get(_url, **session_timeout(params)) as resp: + _json = await resp.json() + if "value" in _json: + value = _json["value"] + else: # 7.0.2 and greater + value = _json + for k, v in value.items(): + if k in payload: + if isinstance(payload[k], dict) and isinstance(v, dict): + to_delete = True + for _k in list(payload[k].keys()): + if payload[k][_k] != v.get(_k): + to_delete = False + if to_delete: + del payload[k] + elif payload[k] == v: + del payload[k] + elif payload[k] == {}: + del payload[k] + + if payload == {} or payload == {"spec": {}}: + # Nothing has changed + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + _json["id"] = params.get("disk") + return await update_changed_flag(_json, resp.status, "get") + async with session.patch(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # e.g: content_configuration + if not _json and resp.status == 204: + async with session.get(_url, **session_timeout(params)) as resp_get: + _json_get = await resp_get.json() + if _json_get: + _json = _json_get + + _json["id"] = params.get("disk") + return await update_changed_flag(_json, resp.status, "update") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_disk_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_disk_info.py new file mode 100644 index 00000000..af0c441d --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_disk_info.py @@ -0,0 +1,278 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_hardware_disk_info +short_description: Returns information about a virtual disk. +description: Returns information about a virtual disk. +options: + disk: + description: + - Virtual disk identifier. Required with I(state=['get']) + type: str + label: + description: + - The name of the item + type: str + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine identifier. This parameter is mandatory. + required: true + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Retrieve the disk information from the VM + vmware.vmware_rest.vcenter_vm_hardware_disk_info: + vm: '{{ test_vm1_info.id }}' + +- name: Retrieve disk information using the label + vmware.vmware_rest.vcenter_vm_hardware_disk_info: + vm: '{{ test_vm1_info.id }}' + label: Hard disk 1 +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Retrieve disk information using the label +id: + description: moid of the resource + returned: On success + sample: '2000' + type: str +value: + description: Retrieve disk information using the label + returned: On success + sample: + backing: + type: VMDK_FILE + vmdk_file: '[local] test_vm1_1/test_vm1.vmdk' + capacity: 17179869184 + label: Hard disk 1 + scsi: + bus: 0 + unit: 0 + type: SCSI + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"disk": "disk", "vm": "vm"}}, + "list": {"query": {}, "body": {}, "path": {"vm": "vm"}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["disk"] = {"type": "str"} + argument_spec["label"] = {"type": "str"} + argument_spec["vm"] = {"required": True, "type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_list_and_get_module.j2 +def build_url(params): + if params.get("disk"): + _in_query_parameters = PAYLOAD_FORMAT["get"]["query"].keys() + return ( + ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/disk/").format( + **params + ) + + params["disk"] + + gen_args(params, _in_query_parameters) + ) + _in_query_parameters = PAYLOAD_FORMAT["list"]["query"].keys() + return ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/disk").format( + **params + ) + gen_args(params, _in_query_parameters) + + +async def entry_point(module, session): + url = build_url(module.params) + async with session.get(url, **session_timeout(module.params)) as resp: + _json = await resp.json() + + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + + if module.params.get("disk"): + _json["id"] = module.params.get("disk") + elif module.params.get("label"): # TODO extend the list of filter + _json = await exists(module.params, session, url) + elif ( + isinstance(_json["value"], list) + and len(_json["value"]) > 0 + and isinstance(_json["value"][0], str) + ): + # this is a list of id, we fetch the details + full_device_list = await build_full_device_list(session, url, _json) + _json = {"value": [i["value"] for i in full_device_list]} + + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_ethernet.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_ethernet.py new file mode 100644 index 00000000..c7242f9e --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_ethernet.py @@ -0,0 +1,660 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_hardware_ethernet +short_description: Adds a virtual Ethernet adapter to the virtual machine. +description: Adds a virtual Ethernet adapter to the virtual machine. +options: + allow_guest_control: + description: + - Flag indicating whether the guest can connect and disconnect the device. + type: bool + backing: + description: + - Physical resource backing for the virtual Ethernet adapter. Required with I(state=['present']) + - 'Valid attributes are:' + - ' - C(type) (str): The C(backing_type) defines the valid backing types for a + virtual Ethernet adapter. ([''present''])' + - ' This key is required with [''present''].' + - ' - Accepted values:' + - ' - DISTRIBUTED_PORTGROUP' + - ' - HOST_DEVICE' + - ' - OPAQUE_NETWORK' + - ' - STANDARD_PORTGROUP' + - ' - C(network) (str): Identifier of the network that backs the virtual Ethernet + adapter. ([''present''])' + - ' - C(distributed_port) (str): Key of the distributed virtual port that backs + the virtual Ethernet adapter. Depending on the type of the Portgroup, the port + may be specified using this field. If the portgroup type is early-binding (also + known as static), a port is assigned when the Ethernet adapter is configured + to use the port. The port may be either automatically or specifically assigned + based on the value of this field. If the portgroup type is ephemeral, the port + is created and assigned to a virtual machine when it is powered on and the Ethernet + adapter is connected. This field cannot be specified as no free ports exist + before use. ([''present''])' + type: dict + label: + description: + - The name of the item + type: str + mac_address: + description: + - MAC address. This field may be modified at any time, and changes will be applied + the next time the virtual machine is powered on. + type: str + mac_type: + choices: + - ASSIGNED + - GENERATED + - MANUAL + description: + - The C(mac_address_type) defines the valid MAC address origins for a virtual + Ethernet adapter. + type: str + nic: + description: + - Virtual Ethernet adapter identifier. Required with I(state=['absent', 'connect', + 'disconnect', 'present']) + type: str + pci_slot_number: + description: + - Address of the virtual Ethernet adapter on the PCI bus. If the PCI address + is invalid, the server will change when it the VM is started or as the device + is hot added. + type: int + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + start_connected: + description: + - Flag indicating whether the virtual device should be connected whenever the + virtual machine is powered on. + type: bool + state: + choices: + - absent + - connect + - disconnect + - present + default: present + description: [] + type: str + type: + choices: + - E1000 + - E1000E + - PCNET32 + - VMXNET + - VMXNET2 + - VMXNET3 + description: + - The C(emulation_type) defines the valid emulation types for a virtual Ethernet + adapter. + type: str + upt_compatibility_enabled: + description: + - Flag indicating whether Universal Pass-Through (UPT) compatibility should be + enabled on this virtual Ethernet adapter. This field may be modified at any + time, and changes will be applied the next time the virtual machine is powered + on. + type: bool + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine identifier. This parameter is mandatory. + required: true + type: str + wake_on_lan_enabled: + description: + - Flag indicating whether wake-on-LAN shoud be enabled on this virtual Ethernet + adapter. This field may be modified at any time, and changes will be applied + the next time the virtual machine is powered on. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Get the dvswitch called my-portgroup + vmware.vmware_rest.vcenter_network_info: + filter_types: DISTRIBUTED_PORTGROUP + filter_names: my-portrgoup + register: my_portgroup + +- name: Attach a VM to a dvswitch + vmware.vmware_rest.vcenter_vm_hardware_ethernet: + vm: '{{ test_vm1_info.id }}' + pci_slot_number: 4 + backing: + type: DISTRIBUTED_PORTGROUP + network: '{{ my_portgroup.value[0].network }}' + start_connected: false + register: vm_hardware_ethernet_1 + +- name: Turn the NIC's start_connected flag on + vmware.vmware_rest.vcenter_vm_hardware_ethernet: + nic: '{{ vm_hardware_ethernet_1.id }}' + start_connected: true + vm: '{{ test_vm1_info.id }}' + +- name: Attach the VM to a standard portgroup + vmware.vmware_rest.vcenter_vm_hardware_ethernet: + vm: '{{ test_vm1_info.id }}' + pci_slot_number: 4 + backing: + type: STANDARD_PORTGROUP + network: "{{ lookup('vmware.vmware_rest.network_moid', '/my_dc/network/VM Network')\ + \ }}" + +- name: Attach the VM to a standard portgroup (again) + vmware.vmware_rest.vcenter_vm_hardware_ethernet: + vm: '{{ test_vm1_info.id }}' + pci_slot_number: 4 + backing: + type: STANDARD_PORTGROUP + network: "{{ lookup('vmware.vmware_rest.network_moid', '/my_dc/network/VM Network')\ + \ }}" + +- name: Collect a list of the NIC for a given VM + vmware.vmware_rest.vcenter_vm_hardware_ethernet_info: + vm: '{{ test_vm1_info.id }}' + register: vm_nic + +- name: Attach the VM to a standard portgroup (again) using the nic ID + vmware.vmware_rest.vcenter_vm_hardware_ethernet: + vm: '{{ test_vm1_info.id }}' + nic: '{{ vm_nic.value[0].nic }}' + backing: + type: STANDARD_PORTGROUP + network: "{{ lookup('vmware.vmware_rest.network_moid', '/my_dc/network/VM Network')\ + \ }}" + +- name: Attach to another standard portgroup + vmware.vmware_rest.vcenter_vm_hardware_ethernet: + vm: '{{ test_vm1_info.id }}' + nic: '{{ vm_nic.value[0].nic }}' + backing: + type: STANDARD_PORTGROUP + network: "{{ lookup('vmware.vmware_rest.network_moid', '/my_dc/network/second_vswitch')\ + \ }}" +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Attach a VM to a dvswitch +id: + description: moid of the resource + returned: On success + sample: '4000' + type: str +value: + description: Attach a VM to a dvswitch + returned: On success + sample: + allow_guest_control: 0 + backing: + connection_cookie: 2094406230 + distributed_port: '2' + distributed_switch_uuid: 50 07 57 eb bf a2 0d 64-4f c5 98 66 47 29 93 35 + network: dvportgroup-1157 + type: DISTRIBUTED_PORTGROUP + label: Network adapter 1 + mac_address: 00:50:56:87:8f:08 + mac_type: ASSIGNED + pci_slot_number: 4 + start_connected: 0 + state: NOT_CONNECTED + type: VMXNET3 + upt_compatibility_enabled: 0 + wake_on_lan_enabled: 0 + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "connect": {"query": {}, "body": {}, "path": {"nic": "nic", "vm": "vm"}}, + "update": { + "query": {}, + "body": { + "allow_guest_control": "allow_guest_control", + "backing": "backing", + "mac_address": "mac_address", + "mac_type": "mac_type", + "start_connected": "start_connected", + "upt_compatibility_enabled": "upt_compatibility_enabled", + "wake_on_lan_enabled": "wake_on_lan_enabled", + }, + "path": {"nic": "nic", "vm": "vm"}, + }, + "create": { + "query": {}, + "body": { + "allow_guest_control": "allow_guest_control", + "backing": "backing", + "mac_address": "mac_address", + "mac_type": "mac_type", + "pci_slot_number": "pci_slot_number", + "start_connected": "start_connected", + "type": "type", + "upt_compatibility_enabled": "upt_compatibility_enabled", + "wake_on_lan_enabled": "wake_on_lan_enabled", + }, + "path": {"vm": "vm"}, + }, + "disconnect": {"query": {}, "body": {}, "path": {"nic": "nic", "vm": "vm"}}, + "delete": {"query": {}, "body": {}, "path": {"nic": "nic", "vm": "vm"}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["allow_guest_control"] = {"type": "bool"} + argument_spec["backing"] = {"type": "dict"} + argument_spec["label"] = {"type": "str"} + argument_spec["mac_address"] = {"type": "str"} + argument_spec["mac_type"] = { + "type": "str", + "choices": ["ASSIGNED", "GENERATED", "MANUAL"], + } + argument_spec["nic"] = {"type": "str"} + argument_spec["pci_slot_number"] = {"type": "int"} + argument_spec["start_connected"] = {"type": "bool"} + argument_spec["state"] = { + "type": "str", + "choices": ["absent", "connect", "disconnect", "present"], + "default": "present", + } + argument_spec["type"] = { + "type": "str", + "choices": ["E1000", "E1000E", "PCNET32", "VMXNET", "VMXNET2", "VMXNET3"], + } + argument_spec["upt_compatibility_enabled"] = {"type": "bool"} + argument_spec["vm"] = {"required": True, "type": "str"} + argument_spec["wake_on_lan_enabled"] = {"type": "bool"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/ethernet" + ).format(**params) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _connect(params, session): + _in_query_parameters = PAYLOAD_FORMAT["connect"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["connect"]) + subdevice_type = get_subdevice_type( + "/api/vcenter/vm/{vm}/hardware/ethernet/{nic}?action=connect" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/vcenter/vm/{vm}/hardware/ethernet/{nic}?action=connect" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "connect") + + +async def _create(params, session): + + lookup_url = per_id_url = build_url(params) + uniquity_keys = ["nic"] + comp_func = None + + async def lookup_with_filters(params, session, url): + # e.g: for the datacenter resources + if "folder" not in params: + return + if "name" not in params: + return + async with session.get( + f"{url}?names={params['name']}&folders={params['folder']}" + ) as resp: + _json = await resp.json() + if isinstance(_json, list) and len(_json) == 1: + return await get_device_info(session, url, _json[0]["nic"]) + + _json = None + + if params["nic"]: + _json = await get_device_info(session, build_url(params), params["nic"]) + + if not _json and (uniquity_keys or comp_func): + _json = await exists( + params, + session, + url=lookup_url, + uniquity_keys=uniquity_keys, + per_id_url=per_id_url, + comp_func=comp_func, + ) + + if not _json: + _json = await lookup_with_filters(params, session, build_url(params)) + + if _json: + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + if "_update" in globals(): + params["nic"] = _json["id"] + return await globals()["_update"](params, session) + + return await update_changed_flag(_json, 200, "get") + + payload = prepare_payload(params, PAYLOAD_FORMAT["create"]) + _url = ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/ethernet" + ).format(**params) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + if resp.status == 500: + text = await resp.text() + raise EmbeddedModuleFailure( + f"Request has failed: status={resp.status}, {text}" + ) + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + + if (resp.status in [200, 201]) and "error" not in _json: + if isinstance(_json, str): # 7.0.2 and greater + _id = _json # TODO: fetch the object + elif isinstance(_json, dict) and "value" not in _json: + _id = list(_json["value"].values())[0] + elif isinstance(_json, dict) and "value" in _json: + _id = _json["value"] + _json_device_info = await get_device_info(session, _url, _id) + if _json_device_info: + _json = _json_device_info + + return await update_changed_flag(_json, resp.status, "create") + + +async def _delete(params, session): + _in_query_parameters = PAYLOAD_FORMAT["delete"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["delete"]) + subdevice_type = get_subdevice_type("/api/vcenter/vm/{vm}/hardware/ethernet/{nic}") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/ethernet/{nic}" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.delete(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "delete") + + +async def _disconnect(params, session): + _in_query_parameters = PAYLOAD_FORMAT["disconnect"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["disconnect"]) + subdevice_type = get_subdevice_type( + "/api/vcenter/vm/{vm}/hardware/ethernet/{nic}?action=disconnect" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/vcenter/vm/{vm}/hardware/ethernet/{nic}?action=disconnect" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "disconnect") + + +async def _update(params, session): + payload = prepare_payload(params, PAYLOAD_FORMAT["update"]) + _url = ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/ethernet/{nic}" + ).format(**params) + async with session.get(_url, **session_timeout(params)) as resp: + _json = await resp.json() + if "value" in _json: + value = _json["value"] + else: # 7.0.2 and greater + value = _json + for k, v in value.items(): + if k in payload: + if isinstance(payload[k], dict) and isinstance(v, dict): + to_delete = True + for _k in list(payload[k].keys()): + if payload[k][_k] != v.get(_k): + to_delete = False + if to_delete: + del payload[k] + elif payload[k] == v: + del payload[k] + elif payload[k] == {}: + del payload[k] + + if payload == {} or payload == {"spec": {}}: + # Nothing has changed + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + _json["id"] = params.get("nic") + return await update_changed_flag(_json, resp.status, "get") + async with session.patch(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # e.g: content_configuration + if not _json and resp.status == 204: + async with session.get(_url, **session_timeout(params)) as resp_get: + _json_get = await resp_get.json() + if _json_get: + _json = _json_get + + _json["id"] = params.get("nic") + return await update_changed_flag(_json, resp.status, "update") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_ethernet_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_ethernet_info.py new file mode 100644 index 00000000..d4d0e541 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_ethernet_info.py @@ -0,0 +1,264 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_hardware_ethernet_info +short_description: Returns information about a virtual Ethernet adapter. +description: Returns information about a virtual Ethernet adapter. +options: + label: + description: + - The name of the item + type: str + nic: + description: + - Virtual Ethernet adapter identifier. Required with I(state=['get']) + type: str + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine identifier. This parameter is mandatory. + required: true + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Collect a list of the NIC for a given VM + vmware.vmware_rest.vcenter_vm_hardware_ethernet_info: + vm: '{{ test_vm1_info.id }}' + +- name: Collect a list of the NIC for a given VM + vmware.vmware_rest.vcenter_vm_hardware_ethernet_info: + vm: '{{ test_vm1_info.id }}' + register: vm_nic +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Collect a list of the NIC for a given VM +value: + description: Collect a list of the NIC for a given VM + returned: On success + sample: [] + type: list +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"nic": "nic", "vm": "vm"}}, + "list": {"query": {}, "body": {}, "path": {"vm": "vm"}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["label"] = {"type": "str"} + argument_spec["nic"] = {"type": "str"} + argument_spec["vm"] = {"required": True, "type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_list_and_get_module.j2 +def build_url(params): + if params.get("nic"): + _in_query_parameters = PAYLOAD_FORMAT["get"]["query"].keys() + return ( + ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/ethernet/" + ).format(**params) + + params["nic"] + + gen_args(params, _in_query_parameters) + ) + _in_query_parameters = PAYLOAD_FORMAT["list"]["query"].keys() + return ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/ethernet" + ).format(**params) + gen_args(params, _in_query_parameters) + + +async def entry_point(module, session): + url = build_url(module.params) + async with session.get(url, **session_timeout(module.params)) as resp: + _json = await resp.json() + + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + + if module.params.get("nic"): + _json["id"] = module.params.get("nic") + elif module.params.get("label"): # TODO extend the list of filter + _json = await exists(module.params, session, url) + elif ( + isinstance(_json["value"], list) + and len(_json["value"]) > 0 + and isinstance(_json["value"][0], str) + ): + # this is a list of id, we fetch the details + full_device_list = await build_full_device_list(session, url, _json) + _json = {"value": [i["value"] for i in full_device_list]} + + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_floppy.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_floppy.py new file mode 100644 index 00000000..26aa01da --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_floppy.py @@ -0,0 +1,526 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_hardware_floppy +short_description: Adds a virtual floppy drive to the virtual machine. +description: Adds a virtual floppy drive to the virtual machine. +options: + allow_guest_control: + description: + - Flag indicating whether the guest can connect and disconnect the device. + type: bool + backing: + description: + - Physical resource backing for the virtual floppy drive. Required with I(state=['present']) + - 'Valid attributes are:' + - ' - C(type) (str): The C(backing_type) defines the valid backing types for a + virtual floppy drive. ([''present''])' + - ' This key is required with [''present''].' + - ' - Accepted values:' + - ' - CLIENT_DEVICE' + - ' - HOST_DEVICE' + - ' - IMAGE_FILE' + - ' - C(image_file) (str): Path of the image file that should be used as the virtual + floppy drive backing. ([''present''])' + - ' - C(host_device) (str): Name of the device that should be used as the virtual + floppy drive backing. ([''present''])' + type: dict + floppy: + description: + - Virtual floppy drive identifier. Required with I(state=['absent', 'connect', + 'disconnect', 'present']) + type: str + label: + description: + - The name of the item + type: str + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + start_connected: + description: + - Flag indicating whether the virtual device should be connected whenever the + virtual machine is powered on. + type: bool + state: + choices: + - absent + - connect + - disconnect + - present + default: present + description: [] + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine identifier. This parameter is mandatory. + required: true + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Add a floppy disk drive + vmware.vmware_rest.vcenter_vm_hardware_floppy: + vm: '{{ test_vm1_info.id }}' + allow_guest_control: true + register: my_floppy_drive + +- name: Remove a floppy drive + vmware.vmware_rest.vcenter_vm_hardware_floppy: + vm: '{{ test_vm1_info.id }}' + floppy: '{{ my_floppy_drive.id }}' + state: absent +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Add a floppy disk drive +id: + description: moid of the resource + returned: On success + sample: '8000' + type: str +value: + description: Add a floppy disk drive + returned: On success + sample: + allow_guest_control: 1 + backing: + auto_detect: 1 + host_device: '' + type: HOST_DEVICE + label: Floppy drive 1 + start_connected: 0 + state: NOT_CONNECTED + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "connect": {"query": {}, "body": {}, "path": {"floppy": "floppy", "vm": "vm"}}, + "update": { + "query": {}, + "body": { + "allow_guest_control": "allow_guest_control", + "backing": "backing", + "start_connected": "start_connected", + }, + "path": {"floppy": "floppy", "vm": "vm"}, + }, + "create": { + "query": {}, + "body": { + "allow_guest_control": "allow_guest_control", + "backing": "backing", + "start_connected": "start_connected", + }, + "path": {"vm": "vm"}, + }, + "disconnect": {"query": {}, "body": {}, "path": {"floppy": "floppy", "vm": "vm"}}, + "delete": {"query": {}, "body": {}, "path": {"floppy": "floppy", "vm": "vm"}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["allow_guest_control"] = {"type": "bool"} + argument_spec["backing"] = {"type": "dict"} + argument_spec["floppy"] = {"type": "str"} + argument_spec["label"] = {"type": "str"} + argument_spec["start_connected"] = {"type": "bool"} + argument_spec["state"] = { + "type": "str", + "choices": ["absent", "connect", "disconnect", "present"], + "default": "present", + } + argument_spec["vm"] = {"required": True, "type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/floppy").format( + **params + ) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _connect(params, session): + _in_query_parameters = PAYLOAD_FORMAT["connect"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["connect"]) + subdevice_type = get_subdevice_type( + "/api/vcenter/vm/{vm}/hardware/floppy/{floppy}?action=connect" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/vcenter/vm/{vm}/hardware/floppy/{floppy}?action=connect" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "connect") + + +async def _create(params, session): + + lookup_url = per_id_url = build_url(params) + uniquity_keys = ["floppy"] + comp_func = None + + async def lookup_with_filters(params, session, url): + # e.g: for the datacenter resources + if "folder" not in params: + return + if "name" not in params: + return + async with session.get( + f"{url}?names={params['name']}&folders={params['folder']}" + ) as resp: + _json = await resp.json() + if isinstance(_json, list) and len(_json) == 1: + return await get_device_info(session, url, _json[0]["floppy"]) + + _json = None + + if params["floppy"]: + _json = await get_device_info(session, build_url(params), params["floppy"]) + + if not _json and (uniquity_keys or comp_func): + _json = await exists( + params, + session, + url=lookup_url, + uniquity_keys=uniquity_keys, + per_id_url=per_id_url, + comp_func=comp_func, + ) + + if not _json: + _json = await lookup_with_filters(params, session, build_url(params)) + + if _json: + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + if "_update" in globals(): + params["floppy"] = _json["id"] + return await globals()["_update"](params, session) + + return await update_changed_flag(_json, 200, "get") + + payload = prepare_payload(params, PAYLOAD_FORMAT["create"]) + _url = ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/floppy").format( + **params + ) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + if resp.status == 500: + text = await resp.text() + raise EmbeddedModuleFailure( + f"Request has failed: status={resp.status}, {text}" + ) + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + + if (resp.status in [200, 201]) and "error" not in _json: + if isinstance(_json, str): # 7.0.2 and greater + _id = _json # TODO: fetch the object + elif isinstance(_json, dict) and "value" not in _json: + _id = list(_json["value"].values())[0] + elif isinstance(_json, dict) and "value" in _json: + _id = _json["value"] + _json_device_info = await get_device_info(session, _url, _id) + if _json_device_info: + _json = _json_device_info + + return await update_changed_flag(_json, resp.status, "create") + + +async def _delete(params, session): + _in_query_parameters = PAYLOAD_FORMAT["delete"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["delete"]) + subdevice_type = get_subdevice_type("/api/vcenter/vm/{vm}/hardware/floppy/{floppy}") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/floppy/{floppy}" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.delete(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "delete") + + +async def _disconnect(params, session): + _in_query_parameters = PAYLOAD_FORMAT["disconnect"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["disconnect"]) + subdevice_type = get_subdevice_type( + "/api/vcenter/vm/{vm}/hardware/floppy/{floppy}?action=disconnect" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/vcenter/vm/{vm}/hardware/floppy/{floppy}?action=disconnect" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "disconnect") + + +async def _update(params, session): + payload = prepare_payload(params, PAYLOAD_FORMAT["update"]) + _url = ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/floppy/{floppy}" + ).format(**params) + async with session.get(_url, **session_timeout(params)) as resp: + _json = await resp.json() + if "value" in _json: + value = _json["value"] + else: # 7.0.2 and greater + value = _json + for k, v in value.items(): + if k in payload: + if isinstance(payload[k], dict) and isinstance(v, dict): + to_delete = True + for _k in list(payload[k].keys()): + if payload[k][_k] != v.get(_k): + to_delete = False + if to_delete: + del payload[k] + elif payload[k] == v: + del payload[k] + elif payload[k] == {}: + del payload[k] + + if payload == {} or payload == {"spec": {}}: + # Nothing has changed + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + _json["id"] = params.get("floppy") + return await update_changed_flag(_json, resp.status, "get") + async with session.patch(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # e.g: content_configuration + if not _json and resp.status == 204: + async with session.get(_url, **session_timeout(params)) as resp_get: + _json_get = await resp_get.json() + if _json_get: + _json = _json_get + + _json["id"] = params.get("floppy") + return await update_changed_flag(_json, resp.status, "update") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_floppy_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_floppy_info.py new file mode 100644 index 00000000..22ba77fc --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_floppy_info.py @@ -0,0 +1,259 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_hardware_floppy_info +short_description: Returns information about a virtual floppy drive. +description: Returns information about a virtual floppy drive. +options: + floppy: + description: + - Virtual floppy drive identifier. Required with I(state=['get']) + type: str + label: + description: + - The name of the item + type: str + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine identifier. This parameter is mandatory. + required: true + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: List the floppy disk drives + vmware.vmware_rest.vcenter_vm_hardware_floppy_info: + vm: '{{ test_vm1_info.id }}' +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: List the floppy disk drives +value: + description: List the floppy disk drives + returned: On success + sample: [] + type: list +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"floppy": "floppy", "vm": "vm"}}, + "list": {"query": {}, "body": {}, "path": {"vm": "vm"}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["floppy"] = {"type": "str"} + argument_spec["label"] = {"type": "str"} + argument_spec["vm"] = {"required": True, "type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_list_and_get_module.j2 +def build_url(params): + if params.get("floppy"): + _in_query_parameters = PAYLOAD_FORMAT["get"]["query"].keys() + return ( + ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/floppy/" + ).format(**params) + + params["floppy"] + + gen_args(params, _in_query_parameters) + ) + _in_query_parameters = PAYLOAD_FORMAT["list"]["query"].keys() + return ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/floppy").format( + **params + ) + gen_args(params, _in_query_parameters) + + +async def entry_point(module, session): + url = build_url(module.params) + async with session.get(url, **session_timeout(module.params)) as resp: + _json = await resp.json() + + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + + if module.params.get("floppy"): + _json["id"] = module.params.get("floppy") + elif module.params.get("label"): # TODO extend the list of filter + _json = await exists(module.params, session, url) + elif ( + isinstance(_json["value"], list) + and len(_json["value"]) > 0 + and isinstance(_json["value"][0], str) + ): + # this is a list of id, we fetch the details + full_device_list = await build_full_device_list(session, url, _json) + _json = {"value": [i["value"] for i in full_device_list]} + + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_info.py new file mode 100644 index 00000000..f10b0f3a --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_info.py @@ -0,0 +1,231 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_hardware_info +short_description: Returns the virtual hardware settings of a virtual machine. +description: Returns the virtual hardware settings of a virtual machine. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine identifier. Required with I(state=['get']) + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect the hardware information + vmware.vmware_rest.vcenter_vm_hardware_info: + vm: '{{ search_result.value[0].vm }}' + register: my_vm1_hardware_info +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Collect the hardware information +value: + description: Collect the hardware information + returned: On success + sample: + upgrade_policy: NEVER + upgrade_status: NONE + version: VMX_10 + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"vm": "vm"}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["vm"] = {"type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware").format( + **params + ) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_memory.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_memory.py new file mode 100644 index 00000000..69ce2435 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_memory.py @@ -0,0 +1,322 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_hardware_memory +short_description: Updates the memory-related settings of a virtual machine. +description: Updates the memory-related settings of a virtual machine. +options: + hot_add_enabled: + description: + - Flag indicating whether adding memory while the virtual machine is running should + be enabled. Some guest operating systems may consume more resources or perform + less efficiently when they run on hardware that supports adding memory while + the machine is running. This field may only be modified if the virtual machine + is not powered on. + type: bool + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + size_MiB: + description: + - New memory size in mebibytes. The supported range of memory sizes is constrained + by the configured guest operating system and virtual hardware version of the + virtual machine. If the virtual machine is running, this value may only be changed + if {@link Info#hotAddEnabled} is true, and the new memory size must satisfy + the constraints specified by {@link Info#hotAddIncrementSizeMiB} and {@link + Info#hotAddLimitMiB}. + type: int + state: + choices: + - present + default: present + description: [] + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine identifier. This parameter is mandatory. + required: true + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Increase the memory of a VM + vmware.vmware_rest.vcenter_vm_hardware_memory: + vm: '{{ test_vm1_info.id }}' + size_MiB: 1080 +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Increase the memory of a VM +id: + description: moid of the resource + returned: On success + sample: null + type: dict +value: + description: Increase the memory of a VM + returned: On success + sample: {} + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "update": { + "query": {}, + "body": {"hot_add_enabled": "hot_add_enabled", "size_MiB": "size_MiB"}, + "path": {"vm": "vm"}, + } +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["hot_add_enabled"] = {"type": "bool"} + argument_spec["size_MiB"] = {"type": "int"} + argument_spec["state"] = { + "type": "str", + "choices": ["present"], + "default": "present", + } + argument_spec["vm"] = {"required": True, "type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/memory").format( + **params + ) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _update(params, session): + payload = prepare_payload(params, PAYLOAD_FORMAT["update"]) + _url = ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/memory").format( + **params + ) + async with session.get(_url, **session_timeout(params)) as resp: + _json = await resp.json() + if "value" in _json: + value = _json["value"] + else: # 7.0.2 and greater + value = _json + for k, v in value.items(): + if k in payload: + if isinstance(payload[k], dict) and isinstance(v, dict): + to_delete = True + for _k in list(payload[k].keys()): + if payload[k][_k] != v.get(_k): + to_delete = False + if to_delete: + del payload[k] + elif payload[k] == v: + del payload[k] + elif payload[k] == {}: + del payload[k] + + if payload == {} or payload == {"spec": {}}: + # Nothing has changed + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + _json["id"] = params.get("None") + return await update_changed_flag(_json, resp.status, "get") + async with session.patch(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # e.g: content_configuration + if not _json and resp.status == 204: + async with session.get(_url, **session_timeout(params)) as resp_get: + _json_get = await resp_get.json() + if _json_get: + _json = _json_get + + _json["id"] = params.get("None") + return await update_changed_flag(_json, resp.status, "update") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_memory_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_memory_info.py new file mode 100644 index 00000000..47898d5c --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_memory_info.py @@ -0,0 +1,234 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_hardware_memory_info +short_description: Returns the memory-related settings of a virtual machine. +description: Returns the memory-related settings of a virtual machine. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine identifier. Required with I(state=['get']) + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Retrieve the memory information from the VM + vmware.vmware_rest.vcenter_vm_hardware_memory_info: + vm: '{{ test_vm1_info.id }}' +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Retrieve the memory information from the VM +value: + description: Retrieve the memory information from the VM + returned: On success + sample: + hot_add_enabled: 1 + size_MiB: 1024 + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"vm": "vm"}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["vm"] = {"type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/memory").format( + **params + ) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/memory").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_parallel.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_parallel.py new file mode 100644 index 00000000..3a4499d2 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_parallel.py @@ -0,0 +1,518 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_hardware_parallel +short_description: Adds a virtual parallel port to the virtual machine. +description: Adds a virtual parallel port to the virtual machine. +options: + allow_guest_control: + description: + - Flag indicating whether the guest can connect and disconnect the device. + type: bool + backing: + description: + - Physical resource backing for the virtual parallel port. Required with I(state=['present']) + - 'Valid attributes are:' + - ' - C(type) (str): The C(backing_type) defines the valid backing types for a + virtual parallel port. ([''present''])' + - ' This key is required with [''present''].' + - ' - Accepted values:' + - ' - FILE' + - ' - HOST_DEVICE' + - ' - C(file) (str): Path of the file that should be used as the virtual parallel + port backing. ([''present''])' + - ' - C(host_device) (str): Name of the device that should be used as the virtual + parallel port backing. ([''present''])' + type: dict + label: + description: + - The name of the item + type: str + port: + description: + - Virtual parallel port identifier. Required with I(state=['absent', 'connect', + 'disconnect', 'present']) + type: str + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + start_connected: + description: + - Flag indicating whether the virtual device should be connected whenever the + virtual machine is powered on. + type: bool + state: + choices: + - absent + - connect + - disconnect + - present + default: present + description: [] + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine identifier. This parameter is mandatory. + required: true + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Turn on guest control on the parallel port + vmware.vmware_rest.vcenter_vm_hardware_parallel: + vm: '{{ test_vm1_info.id }}' + allow_guest_control: true +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Turn on guest control on the parallel port +id: + description: moid of the resource + returned: On success + sample: '10000' + type: str +value: + description: Turn on guest control on the parallel port + returned: On success + sample: + allow_guest_control: 1 + backing: + auto_detect: 1 + host_device: '' + type: HOST_DEVICE + label: Parallel port 1 + start_connected: 0 + state: NOT_CONNECTED + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "connect": {"query": {}, "body": {}, "path": {"port": "port", "vm": "vm"}}, + "update": { + "query": {}, + "body": { + "allow_guest_control": "allow_guest_control", + "backing": "backing", + "start_connected": "start_connected", + }, + "path": {"port": "port", "vm": "vm"}, + }, + "create": { + "query": {}, + "body": { + "allow_guest_control": "allow_guest_control", + "backing": "backing", + "start_connected": "start_connected", + }, + "path": {"vm": "vm"}, + }, + "disconnect": {"query": {}, "body": {}, "path": {"port": "port", "vm": "vm"}}, + "delete": {"query": {}, "body": {}, "path": {"port": "port", "vm": "vm"}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["allow_guest_control"] = {"type": "bool"} + argument_spec["backing"] = {"type": "dict"} + argument_spec["label"] = {"type": "str"} + argument_spec["port"] = {"type": "str"} + argument_spec["start_connected"] = {"type": "bool"} + argument_spec["state"] = { + "type": "str", + "choices": ["absent", "connect", "disconnect", "present"], + "default": "present", + } + argument_spec["vm"] = {"required": True, "type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/parallel" + ).format(**params) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _connect(params, session): + _in_query_parameters = PAYLOAD_FORMAT["connect"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["connect"]) + subdevice_type = get_subdevice_type( + "/api/vcenter/vm/{vm}/hardware/parallel/{port}?action=connect" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/vcenter/vm/{vm}/hardware/parallel/{port}?action=connect" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "connect") + + +async def _create(params, session): + + lookup_url = per_id_url = build_url(params) + uniquity_keys = ["port"] + comp_func = None + + async def lookup_with_filters(params, session, url): + # e.g: for the datacenter resources + if "folder" not in params: + return + if "name" not in params: + return + async with session.get( + f"{url}?names={params['name']}&folders={params['folder']}" + ) as resp: + _json = await resp.json() + if isinstance(_json, list) and len(_json) == 1: + return await get_device_info(session, url, _json[0]["port"]) + + _json = None + + if params["port"]: + _json = await get_device_info(session, build_url(params), params["port"]) + + if not _json and (uniquity_keys or comp_func): + _json = await exists( + params, + session, + url=lookup_url, + uniquity_keys=uniquity_keys, + per_id_url=per_id_url, + comp_func=comp_func, + ) + + if not _json: + _json = await lookup_with_filters(params, session, build_url(params)) + + if _json: + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + if "_update" in globals(): + params["port"] = _json["id"] + return await globals()["_update"](params, session) + + return await update_changed_flag(_json, 200, "get") + + payload = prepare_payload(params, PAYLOAD_FORMAT["create"]) + _url = ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/parallel" + ).format(**params) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + if resp.status == 500: + text = await resp.text() + raise EmbeddedModuleFailure( + f"Request has failed: status={resp.status}, {text}" + ) + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + + if (resp.status in [200, 201]) and "error" not in _json: + if isinstance(_json, str): # 7.0.2 and greater + _id = _json # TODO: fetch the object + elif isinstance(_json, dict) and "value" not in _json: + _id = list(_json["value"].values())[0] + elif isinstance(_json, dict) and "value" in _json: + _id = _json["value"] + _json_device_info = await get_device_info(session, _url, _id) + if _json_device_info: + _json = _json_device_info + + return await update_changed_flag(_json, resp.status, "create") + + +async def _delete(params, session): + _in_query_parameters = PAYLOAD_FORMAT["delete"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["delete"]) + subdevice_type = get_subdevice_type("/api/vcenter/vm/{vm}/hardware/parallel/{port}") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/parallel/{port}" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.delete(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "delete") + + +async def _disconnect(params, session): + _in_query_parameters = PAYLOAD_FORMAT["disconnect"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["disconnect"]) + subdevice_type = get_subdevice_type( + "/api/vcenter/vm/{vm}/hardware/parallel/{port}?action=disconnect" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/vcenter/vm/{vm}/hardware/parallel/{port}?action=disconnect" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "disconnect") + + +async def _update(params, session): + payload = prepare_payload(params, PAYLOAD_FORMAT["update"]) + _url = ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/parallel/{port}" + ).format(**params) + async with session.get(_url, **session_timeout(params)) as resp: + _json = await resp.json() + if "value" in _json: + value = _json["value"] + else: # 7.0.2 and greater + value = _json + for k, v in value.items(): + if k in payload: + if isinstance(payload[k], dict) and isinstance(v, dict): + to_delete = True + for _k in list(payload[k].keys()): + if payload[k][_k] != v.get(_k): + to_delete = False + if to_delete: + del payload[k] + elif payload[k] == v: + del payload[k] + elif payload[k] == {}: + del payload[k] + + if payload == {} or payload == {"spec": {}}: + # Nothing has changed + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + _json["id"] = params.get("port") + return await update_changed_flag(_json, resp.status, "get") + async with session.patch(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # e.g: content_configuration + if not _json and resp.status == 204: + async with session.get(_url, **session_timeout(params)) as resp_get: + _json_get = await resp_get.json() + if _json_get: + _json = _json_get + + _json["id"] = params.get("port") + return await update_changed_flag(_json, resp.status, "update") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_parallel_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_parallel_info.py new file mode 100644 index 00000000..f5a848f9 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_parallel_info.py @@ -0,0 +1,259 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_hardware_parallel_info +short_description: Returns information about a virtual parallel port. +description: Returns information about a virtual parallel port. +options: + label: + description: + - The name of the item + type: str + port: + description: + - Virtual parallel port identifier. Required with I(state=['get']) + type: str + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine identifier. This parameter is mandatory. + required: true + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Retrieve the parallel port information from the VM + vmware.vmware_rest.vcenter_vm_hardware_parallel_info: + vm: '{{ test_vm1_info.id }}' +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Retrieve the parallel port information from the VM +value: + description: Retrieve the parallel port information from the VM + returned: On success + sample: [] + type: list +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"port": "port", "vm": "vm"}}, + "list": {"query": {}, "body": {}, "path": {"vm": "vm"}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["label"] = {"type": "str"} + argument_spec["port"] = {"type": "str"} + argument_spec["vm"] = {"required": True, "type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_list_and_get_module.j2 +def build_url(params): + if params.get("port"): + _in_query_parameters = PAYLOAD_FORMAT["get"]["query"].keys() + return ( + ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/parallel/" + ).format(**params) + + params["port"] + + gen_args(params, _in_query_parameters) + ) + _in_query_parameters = PAYLOAD_FORMAT["list"]["query"].keys() + return ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/parallel" + ).format(**params) + gen_args(params, _in_query_parameters) + + +async def entry_point(module, session): + url = build_url(module.params) + async with session.get(url, **session_timeout(module.params)) as resp: + _json = await resp.json() + + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + + if module.params.get("port"): + _json["id"] = module.params.get("port") + elif module.params.get("label"): # TODO extend the list of filter + _json = await exists(module.params, session, url) + elif ( + isinstance(_json["value"], list) + and len(_json["value"]) > 0 + and isinstance(_json["value"][0], str) + ): + # this is a list of id, we fetch the details + full_device_list = await build_full_device_list(session, url, _json) + _json = {"value": [i["value"] for i in full_device_list]} + + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_serial.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_serial.py new file mode 100644 index 00000000..01164d5f --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_serial.py @@ -0,0 +1,579 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_hardware_serial +short_description: Adds a virtual serial port to the virtual machine. +description: Adds a virtual serial port to the virtual machine. +options: + allow_guest_control: + description: + - Flag indicating whether the guest can connect and disconnect the device. + type: bool + backing: + description: + - Physical resource backing for the virtual serial port. Required with I(state=['present']) + - 'Valid attributes are:' + - ' - C(type) (str): The C(backing_type) defines the valid backing types for a + virtual serial port. ([''present''])' + - ' This key is required with [''present''].' + - ' - Accepted values:' + - ' - FILE' + - ' - HOST_DEVICE' + - ' - NETWORK_CLIENT' + - ' - NETWORK_SERVER' + - ' - PIPE_CLIENT' + - ' - PIPE_SERVER' + - ' - C(file) (str): Path of the file backing the virtual serial port. ([''present''])' + - ' - C(host_device) (str): Name of the device backing the virtual serial port. + ([''present''])' + - ' - C(pipe) (str): Name of the pipe backing the virtual serial port. ([''present''])' + - ' - C(no_rx_loss) (bool): Flag that enables optimized data transfer over the + pipe. When the value is true, the host buffers data to prevent data overrun. This + allows the virtual machine to read all of the data transferred over the pipe + with no data loss. ([''present''])' + - ' - C(network_location) (str): URI specifying the location of the network service + backing the virtual serial port. <ul> <li>If {@link #type} is {@link BackingType#NETWORK_SERVER}, + this field is the location used by clients to connect to this server. The hostname + part of the URI should either be empty or should specify the address of the + host on which the virtual machine is running.</li> <li>If {@link #type} is {@link + BackingType#NETWORK_CLIENT}, this field is the location used by the virtual + machine to connect to the remote server.</li> </ul> ([''present''])' + - ' - C(proxy) (str): Proxy service that provides network access to the network + backing. If set, the virtual machine initiates a connection with the proxy + service and forwards the traffic to the proxy. ([''present''])' + type: dict + label: + description: + - The name of the item + type: str + port: + description: + - Virtual serial port identifier. Required with I(state=['absent', 'connect', + 'disconnect', 'present']) + type: str + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + start_connected: + description: + - Flag indicating whether the virtual device should be connected whenever the + virtual machine is powered on. + type: bool + state: + choices: + - absent + - connect + - disconnect + - present + default: present + description: [] + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine identifier. This parameter is mandatory. + required: true + type: str + yield_on_poll: + description: + - CPU yield behavior. If set to true, the virtual machine will periodically relinquish + the processor if its sole task is polling the virtual serial port. The amount + of time it takes to regain the processor will depend on the degree of other + virtual machine activity on the host. This field may be modified at any time, + and changes applied to a connected virtual serial port take effect immediately. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Create a new serial port + vmware.vmware_rest.vcenter_vm_hardware_serial: + vm: '{{ test_vm1_info.id }}' + label: Serial port 2 + allow_guest_control: true + +- name: Create another serial port with a label + vmware.vmware_rest.vcenter_vm_hardware_serial: + vm: '{{ test_vm1_info.id }}' + label: Serial port 2 + allow_guest_control: true + +- name: Create an existing serial port (label) + vmware.vmware_rest.vcenter_vm_hardware_serial: + vm: '{{ test_vm1_info.id }}' + label: Serial port 1 + allow_guest_control: true + +- name: Get an existing serial port (label) + vmware.vmware_rest.vcenter_vm_hardware_serial_info: + vm: '{{ test_vm1_info.id }}' + label: Serial port 1 + register: serial_port_1 + +- name: Delete an existing serial port (port id) + vmware.vmware_rest.vcenter_vm_hardware_serial: + vm: '{{ test_vm1_info.id }}' + port: '{{ serial_port_1.id }}' + state: absent + +- name: Delete an existing serial port (label) + vmware.vmware_rest.vcenter_vm_hardware_serial: + vm: '{{ test_vm1_info.id }}' + label: Serial port 2 + state: absent +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Create an existing serial port (label) +id: + description: moid of the resource + returned: On success + sample: '9000' + type: str +value: + description: Create an existing serial port (label) + returned: On success + sample: + allow_guest_control: 1 + backing: + auto_detect: 1 + host_device: '' + type: HOST_DEVICE + label: Serial port 1 + start_connected: 0 + state: NOT_CONNECTED + yield_on_poll: 0 + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "connect": {"query": {}, "body": {}, "path": {"port": "port", "vm": "vm"}}, + "update": { + "query": {}, + "body": { + "allow_guest_control": "allow_guest_control", + "backing": "backing", + "start_connected": "start_connected", + "yield_on_poll": "yield_on_poll", + }, + "path": {"port": "port", "vm": "vm"}, + }, + "create": { + "query": {}, + "body": { + "allow_guest_control": "allow_guest_control", + "backing": "backing", + "start_connected": "start_connected", + "yield_on_poll": "yield_on_poll", + }, + "path": {"vm": "vm"}, + }, + "disconnect": {"query": {}, "body": {}, "path": {"port": "port", "vm": "vm"}}, + "delete": {"query": {}, "body": {}, "path": {"port": "port", "vm": "vm"}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["allow_guest_control"] = {"type": "bool"} + argument_spec["backing"] = {"type": "dict"} + argument_spec["label"] = {"type": "str"} + argument_spec["port"] = {"type": "str"} + argument_spec["start_connected"] = {"type": "bool"} + argument_spec["state"] = { + "type": "str", + "choices": ["absent", "connect", "disconnect", "present"], + "default": "present", + } + argument_spec["vm"] = {"required": True, "type": "str"} + argument_spec["yield_on_poll"] = {"type": "bool"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/serial").format( + **params + ) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _connect(params, session): + _in_query_parameters = PAYLOAD_FORMAT["connect"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["connect"]) + subdevice_type = get_subdevice_type( + "/api/vcenter/vm/{vm}/hardware/serial/{port}?action=connect" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/vcenter/vm/{vm}/hardware/serial/{port}?action=connect" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "connect") + + +async def _create(params, session): + + lookup_url = per_id_url = build_url(params) + uniquity_keys = ["port"] + comp_func = None + + async def lookup_with_filters(params, session, url): + # e.g: for the datacenter resources + if "folder" not in params: + return + if "name" not in params: + return + async with session.get( + f"{url}?names={params['name']}&folders={params['folder']}" + ) as resp: + _json = await resp.json() + if isinstance(_json, list) and len(_json) == 1: + return await get_device_info(session, url, _json[0]["port"]) + + _json = None + + if params["port"]: + _json = await get_device_info(session, build_url(params), params["port"]) + + if not _json and (uniquity_keys or comp_func): + _json = await exists( + params, + session, + url=lookup_url, + uniquity_keys=uniquity_keys, + per_id_url=per_id_url, + comp_func=comp_func, + ) + + if not _json: + _json = await lookup_with_filters(params, session, build_url(params)) + + if _json: + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + if "_update" in globals(): + params["port"] = _json["id"] + return await globals()["_update"](params, session) + + return await update_changed_flag(_json, 200, "get") + + payload = prepare_payload(params, PAYLOAD_FORMAT["create"]) + _url = ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/serial").format( + **params + ) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + if resp.status == 500: + text = await resp.text() + raise EmbeddedModuleFailure( + f"Request has failed: status={resp.status}, {text}" + ) + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + + if (resp.status in [200, 201]) and "error" not in _json: + if isinstance(_json, str): # 7.0.2 and greater + _id = _json # TODO: fetch the object + elif isinstance(_json, dict) and "value" not in _json: + _id = list(_json["value"].values())[0] + elif isinstance(_json, dict) and "value" in _json: + _id = _json["value"] + _json_device_info = await get_device_info(session, _url, _id) + if _json_device_info: + _json = _json_device_info + + return await update_changed_flag(_json, resp.status, "create") + + +async def _delete(params, session): + _in_query_parameters = PAYLOAD_FORMAT["delete"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["delete"]) + subdevice_type = get_subdevice_type("/api/vcenter/vm/{vm}/hardware/serial/{port}") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/serial/{port}" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.delete(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "delete") + + +async def _disconnect(params, session): + _in_query_parameters = PAYLOAD_FORMAT["disconnect"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["disconnect"]) + subdevice_type = get_subdevice_type( + "/api/vcenter/vm/{vm}/hardware/serial/{port}?action=disconnect" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/vcenter/vm/{vm}/hardware/serial/{port}?action=disconnect" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "disconnect") + + +async def _update(params, session): + payload = prepare_payload(params, PAYLOAD_FORMAT["update"]) + _url = ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/serial/{port}" + ).format(**params) + async with session.get(_url, **session_timeout(params)) as resp: + _json = await resp.json() + if "value" in _json: + value = _json["value"] + else: # 7.0.2 and greater + value = _json + for k, v in value.items(): + if k in payload: + if isinstance(payload[k], dict) and isinstance(v, dict): + to_delete = True + for _k in list(payload[k].keys()): + if payload[k][_k] != v.get(_k): + to_delete = False + if to_delete: + del payload[k] + elif payload[k] == v: + del payload[k] + elif payload[k] == {}: + del payload[k] + + if payload == {} or payload == {"spec": {}}: + # Nothing has changed + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + _json["id"] = params.get("port") + return await update_changed_flag(_json, resp.status, "get") + async with session.patch(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # e.g: content_configuration + if not _json and resp.status == 204: + async with session.get(_url, **session_timeout(params)) as resp_get: + _json_get = await resp_get.json() + if _json_get: + _json = _json_get + + _json["id"] = params.get("port") + return await update_changed_flag(_json, resp.status, "update") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_serial_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_serial_info.py new file mode 100644 index 00000000..6473fa4d --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_hardware_serial_info.py @@ -0,0 +1,279 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_hardware_serial_info +short_description: Returns information about a virtual serial port. +description: Returns information about a virtual serial port. +options: + label: + description: + - The name of the item + type: str + port: + description: + - Virtual serial port identifier. Required with I(state=['get']) + type: str + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine identifier. This parameter is mandatory. + required: true + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Retrieve the serial ports information from the VM + vmware.vmware_rest.vcenter_vm_hardware_serial_info: + vm: '{{ test_vm1_info.id }}' + +- name: Get an existing serial port (label) + vmware.vmware_rest.vcenter_vm_hardware_serial_info: + vm: '{{ test_vm1_info.id }}' + label: Serial port 1 + register: serial_port_1 +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get an existing serial port (label) +id: + description: moid of the resource + returned: On success + sample: '9000' + type: str +value: + description: Get an existing serial port (label) + returned: On success + sample: + allow_guest_control: 1 + backing: + auto_detect: 1 + host_device: '' + type: HOST_DEVICE + label: Serial port 1 + start_connected: 0 + state: NOT_CONNECTED + yield_on_poll: 0 + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"port": "port", "vm": "vm"}}, + "list": {"query": {}, "body": {}, "path": {"vm": "vm"}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["label"] = {"type": "str"} + argument_spec["port"] = {"type": "str"} + argument_spec["vm"] = {"required": True, "type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_list_and_get_module.j2 +def build_url(params): + if params.get("port"): + _in_query_parameters = PAYLOAD_FORMAT["get"]["query"].keys() + return ( + ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/serial/" + ).format(**params) + + params["port"] + + gen_args(params, _in_query_parameters) + ) + _in_query_parameters = PAYLOAD_FORMAT["list"]["query"].keys() + return ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/hardware/serial").format( + **params + ) + gen_args(params, _in_query_parameters) + + +async def entry_point(module, session): + url = build_url(module.params) + async with session.get(url, **session_timeout(module.params)) as resp: + _json = await resp.json() + + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + + if module.params.get("port"): + _json["id"] = module.params.get("port") + elif module.params.get("label"): # TODO extend the list of filter + _json = await exists(module.params, session, url) + elif ( + isinstance(_json["value"], list) + and len(_json["value"]) > 0 + and isinstance(_json["value"][0], str) + ): + # this is a list of id, we fetch the details + full_device_list = await build_full_device_list(session, url, _json) + _json = {"value": [i["value"] for i in full_device_list]} + + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_info.py new file mode 100644 index 00000000..68f78ee2 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_info.py @@ -0,0 +1,478 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_info +short_description: Returns information about a virtual machine. +description: Returns information about a virtual machine. +options: + clusters: + description: + - Clusters that must contain the virtual machine for the virtual machine to match + the filter. + elements: str + type: list + datacenters: + aliases: + - filter_datacenters + description: + - Datacenters that must contain the virtual machine for the virtual machine to + match the filter. + elements: str + type: list + folders: + aliases: + - filter_folders + description: + - Folders that must contain the virtual machine for the virtual machine to match + the filter. + elements: str + type: list + hosts: + description: + - Hosts that must contain the virtual machine for the virtual machine to match + the filter. + elements: str + type: list + names: + aliases: + - filter_names + description: + - Names that virtual machines must have to match the filter (see {@link Info#name}). + elements: str + type: list + power_states: + description: + - Power states that a virtual machine must be in to match the filter (see {@link + I(info)#state}. + elements: str + type: list + resource_pools: + description: + - Resource pools that must contain the virtual machine for the virtual machine + to match the filter. + elements: str + type: list + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine identifier. Required with I(state=['get']) + type: str + vms: + description: + - Identifiers of virtual machines that can match the filter. + elements: str + type: list +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Search with an invalid filter + vmware.vmware_rest.vcenter_vm_info: + filter_names: test_vm1_does_not_exists + +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Collect the list of the existing VM + vmware.vmware_rest.vcenter_vm_info: + register: existing_vms + until: existing_vms is not failed + +- name: Create a VM + vmware.vmware_rest.vcenter_vm: + placement: + cluster: "{{ lookup('vmware.vmware_rest.cluster_moid', '/my_dc/host/my_cluster')\ + \ }}" + datastore: "{{ lookup('vmware.vmware_rest.datastore_moid', '/my_dc/datastore/local')\ + \ }}" + folder: "{{ lookup('vmware.vmware_rest.folder_moid', '/my_dc/vm') }}" + resource_pool: "{{ lookup('vmware.vmware_rest.resource_pool_moid', '/my_dc/host/my_cluster/Resources')\ + \ }}" + name: test_vm1 + guest_OS: RHEL_7_64 + hardware_version: VMX_11 + memory: + hot_add_enabled: true + size_MiB: 1024 + disks: + - type: SATA + backing: + type: VMDK_FILE + vmdk_file: '[local] test_vm1/{{ disk_name }}.vmdk' + - type: SATA + new_vmdk: + name: second_disk + capacity: 32000000000 + cdroms: + - type: SATA + sata: + bus: 0 + unit: 2 + nics: + - backing: + type: STANDARD_PORTGROUP + network: "{{ lookup('vmware.vmware_rest.network_moid', '/my_dc/network/VM\ + \ Network') }}" + + register: my_vm + +- name: Wait until my VM is off + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ my_vm.id }}' + register: vm_info + until: + - vm_info is not failed + - vm_info.value.power_state == "POWERED_OFF" + retries: 60 + delay: 5 +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Wait until my VM is off +id: + description: moid of the resource + returned: On success + sample: vm-1184 + type: str +value: + description: Wait until my VM is off + returned: On success + sample: + boot: + delay: 0 + enter_setup_mode: 0 + retry: 0 + retry_delay: 10000 + type: BIOS + boot_devices: [] + cdroms: + '16002': + allow_guest_control: 0 + backing: + auto_detect: 1 + device_access_type: EMULATION + type: HOST_DEVICE + label: CD/DVD drive 1 + sata: + bus: 0 + unit: 2 + start_connected: 0 + state: NOT_CONNECTED + type: SATA + cpu: + cores_per_socket: 1 + count: 1 + hot_add_enabled: 0 + hot_remove_enabled: 0 + disks: + '16000': + backing: + type: VMDK_FILE + vmdk_file: '[local] test_vm1/rhel-8.5.vmdk' + capacity: 16106127360 + label: Hard disk 1 + sata: + bus: 0 + unit: 0 + type: SATA + '16001': + backing: + type: VMDK_FILE + vmdk_file: '[local] test_vm1_2/second_disk.vmdk' + capacity: 32000000000 + label: Hard disk 2 + sata: + bus: 0 + unit: 1 + type: SATA + floppies: {} + guest_OS: RHEL_7_64 + hardware: + upgrade_policy: NEVER + upgrade_status: NONE + version: VMX_11 + identity: + bios_uuid: 420719b2-c821-f9e6-9e19-02727fe7828b + instance_uuid: 50072b43-be81-0b7b-5d2b-e03126c76cb5 + name: test_vm1 + instant_clone_frozen: 0 + memory: + hot_add_enabled: 1 + size_MiB: 1024 + name: test_vm1 + nics: + '4000': + allow_guest_control: 0 + backing: + network: network-1177 + network_name: VM Network + type: STANDARD_PORTGROUP + label: Network adapter 1 + mac_address: 00:50:56:87:97:87 + mac_type: ASSIGNED + pci_slot_number: 160 + start_connected: 0 + state: NOT_CONNECTED + type: VMXNET3 + upt_compatibility_enabled: 0 + wake_on_lan_enabled: 0 + nvme_adapters: {} + parallel_ports: {} + power_state: POWERED_OFF + sata_adapters: + '15000': + bus: 0 + label: SATA controller 0 + pci_slot_number: 32 + type: AHCI + scsi_adapters: {} + serial_ports: {} + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"vm": "vm"}}, + "list": { + "query": { + "clusters": "clusters", + "datacenters": "datacenters", + "folders": "folders", + "hosts": "hosts", + "names": "names", + "power_states": "power_states", + "resource_pools": "resource_pools", + "vms": "vms", + }, + "body": {}, + "path": {}, + }, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["clusters"] = {"type": "list", "elements": "str"} + argument_spec["datacenters"] = { + "aliases": ["filter_datacenters"], + "type": "list", + "elements": "str", + } + argument_spec["folders"] = { + "aliases": ["filter_folders"], + "type": "list", + "elements": "str", + } + argument_spec["hosts"] = {"type": "list", "elements": "str"} + argument_spec["names"] = { + "aliases": ["filter_names"], + "type": "list", + "elements": "str", + } + argument_spec["power_states"] = {"type": "list", "elements": "str"} + argument_spec["resource_pools"] = {"type": "list", "elements": "str"} + argument_spec["vm"] = {"type": "str"} + argument_spec["vms"] = {"type": "list", "elements": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_list_and_get_module.j2 +def build_url(params): + if params.get("vm"): + _in_query_parameters = PAYLOAD_FORMAT["get"]["query"].keys() + return ( + ("https://{vcenter_hostname}" "/api/vcenter/vm/").format(**params) + + params["vm"] + + gen_args(params, _in_query_parameters) + ) + _in_query_parameters = PAYLOAD_FORMAT["list"]["query"].keys() + return ("https://{vcenter_hostname}" "/api/vcenter/vm").format(**params) + gen_args( + params, _in_query_parameters + ) + + +async def entry_point(module, session): + url = build_url(module.params) + async with session.get(url, **session_timeout(module.params)) as resp: + _json = await resp.json() + + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + + if module.params.get("vm"): + _json["id"] = module.params.get("vm") + elif module.params.get("label"): # TODO extend the list of filter + _json = await exists(module.params, session, url) + elif ( + isinstance(_json["value"], list) + and len(_json["value"]) > 0 + and isinstance(_json["value"][0], str) + ): + # this is a list of id, we fetch the details + full_device_list = await build_full_device_list(session, url, _json) + _json = {"value": [i["value"] for i in full_device_list]} + + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_libraryitem_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_libraryitem_info.py new file mode 100644 index 00000000..ee5947ea --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_libraryitem_info.py @@ -0,0 +1,234 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_libraryitem_info +short_description: Returns the information about the library item associated with + the virtual machine. +description: Returns the information about the library item associated with the virtual + machine. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Identifier of the virtual machine. Required with I(state=['get']) + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Get the information from the library + vmware.vmware_rest.vcenter_vm_libraryitem_info: + vm: '{{ test_vm1_info.id }}' +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get the information from the library +value: + description: Get the information from the library + returned: On success + sample: {} + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"vm": "vm"}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["vm"] = {"type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/library-item").format( + **params + ) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/library-item").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_power.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_power.py new file mode 100644 index 00000000..d7f7265d --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_power.py @@ -0,0 +1,527 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_power +short_description: Operate a boot, hard shutdown, hard reset or hard suspend on a + guest. +description: Ask the vCenter to boot, force shutdown or force reset a guest. If you + want to do a soft shutdown or a soft reset, you can use M(vmware.vmware_rest.vmware_vm_guest_power) + instead. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - reset + - start + - stop + - suspend + description: [] + required: true + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine identifier. This parameter is mandatory. + required: true + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +seealso: +- description: Issues a request to the guest operating system asking it to perform + a soft shutdown, standby (suspend) or soft reboot + module: vmware.vmware_rest.vcenter_vm_guest_power +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Turn the power of the VM on + vmware.vmware_rest.vcenter_vm_power: + state: start + vm: '{{ test_vm1_info.id }}' + +- name: Collect the list of the existing VM + vmware.vmware_rest.vcenter_vm_info: + register: existing_vms + until: existing_vms is not failed + +- name: Turn off the VM + vmware.vmware_rest.vcenter_vm_power: + state: stop + vm: '{{ item.vm }}' + with_items: '{{ existing_vms.value }}' + ignore_errors: yes + +- name: Create a VM + vmware.vmware_rest.vcenter_vm: + placement: + cluster: "{{ lookup('vmware.vmware_rest.cluster_moid', '/my_dc/host/my_cluster')\ + \ }}" + datastore: "{{ lookup('vmware.vmware_rest.datastore_moid', '/my_dc/datastore/local')\ + \ }}" + folder: "{{ lookup('vmware.vmware_rest.folder_moid', '/my_dc/vm') }}" + resource_pool: "{{ lookup('vmware.vmware_rest.resource_pool_moid', '/my_dc/host/my_cluster/Resources')\ + \ }}" + name: test_vm1 + guest_OS: RHEL_7_64 + hardware_version: VMX_11 + memory: + hot_add_enabled: true + size_MiB: 1024 + disks: + - type: SATA + backing: + type: VMDK_FILE + vmdk_file: '[local] test_vm1/{{ disk_name }}.vmdk' + - type: SATA + new_vmdk: + name: second_disk + capacity: 32000000000 + cdroms: + - type: SATA + sata: + bus: 0 + unit: 2 + nics: + - backing: + type: STANDARD_PORTGROUP + network: "{{ lookup('vmware.vmware_rest.network_moid', '/my_dc/network/VM\ + \ Network') }}" + + register: my_vm + +- name: Turn on the power of the VM + vmware.vmware_rest.vcenter_vm_power: + state: start + vm: '{{ my_vm.id }}' + +- name: Turn the power of the VM on + vmware.vmware_rest.vcenter_vm_power: + state: start + vm: '{{ my_vm.id }}' +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Turn off the VM +msg: + description: Turn off the VM + returned: On success + sample: All items completed + type: str +results: + description: Turn off the VM + returned: On success + sample: + - _ansible_item_label: + cpu_count: 1 + memory_size_MiB: 128 + name: vCLS-a3e9f505-69fc-43d0-beed-c1a43d06184e + power_state: POWERED_OFF + vm: vm-1130 + _ansible_no_log: null + ansible_loop_var: item + changed: 0 + failed: 0 + invocation: + module_args: + session_timeout: null + state: stop + vcenter_hostname: vcenter.test + vcenter_password: VALUE_SPECIFIED_IN_NO_LOG_PARAMETER + vcenter_rest_log_file: null + vcenter_username: administrator@vsphere.local + vcenter_validate_certs: 0 + vm: vm-1130 + item: + cpu_count: 1 + memory_size_MiB: 128 + name: vCLS-a3e9f505-69fc-43d0-beed-c1a43d06184e + power_state: POWERED_OFF + vm: vm-1130 + value: + error_type: ALREADY_IN_DESIRED_STATE + messages: + - args: [] + default_message: Virtual machine is already powered off. + id: com.vmware.api.vcenter.vm.power.already_powered_off + - args: [] + default_message: The attempted operation cannot be performed in the current + state (Powered off). + id: vmsg.InvalidPowerState.summary + - _ansible_item_label: + cpu_count: 1 + memory_size_MiB: 1024 + name: test_vm1 + power_state: POWERED_OFF + vm: vm-1131 + _ansible_no_log: null + ansible_loop_var: item + changed: 0 + failed: 0 + invocation: + module_args: + session_timeout: null + state: stop + vcenter_hostname: vcenter.test + vcenter_password: VALUE_SPECIFIED_IN_NO_LOG_PARAMETER + vcenter_rest_log_file: null + vcenter_username: administrator@vsphere.local + vcenter_validate_certs: 0 + vm: vm-1131 + item: + cpu_count: 1 + memory_size_MiB: 1024 + name: test_vm1 + power_state: POWERED_OFF + vm: vm-1131 + value: + error_type: ALREADY_IN_DESIRED_STATE + messages: + - args: [] + default_message: Virtual machine is already powered off. + id: com.vmware.api.vcenter.vm.power.already_powered_off + - args: [] + default_message: The attempted operation cannot be performed in the current + state (Powered off). + id: vmsg.InvalidPowerState.summary + - _ansible_item_label: + cpu_count: 1 + memory_size_MiB: 1024 + name: foobar2002 + power_state: POWERED_OFF + vm: vm-1134 + _ansible_no_log: null + ansible_loop_var: item + changed: 0 + failed: 0 + invocation: + module_args: + session_timeout: null + state: stop + vcenter_hostname: vcenter.test + vcenter_password: VALUE_SPECIFIED_IN_NO_LOG_PARAMETER + vcenter_rest_log_file: null + vcenter_username: administrator@vsphere.local + vcenter_validate_certs: 0 + vm: vm-1134 + item: + cpu_count: 1 + memory_size_MiB: 1024 + name: foobar2002 + power_state: POWERED_OFF + vm: vm-1134 + value: + error_type: ALREADY_IN_DESIRED_STATE + messages: + - args: [] + default_message: Virtual machine is already powered off. + id: com.vmware.api.vcenter.vm.power.already_powered_off + - args: [] + default_message: The attempted operation cannot be performed in the current + state (Powered off). + id: vmsg.InvalidPowerState.summary + type: list +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "start": {"query": {}, "body": {}, "path": {"vm": "vm"}}, + "suspend": {"query": {}, "body": {}, "path": {"vm": "vm"}}, + "reset": {"query": {}, "body": {}, "path": {"vm": "vm"}}, + "stop": {"query": {}, "body": {}, "path": {"vm": "vm"}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["state"] = { + "required": True, + "type": "str", + "choices": ["reset", "start", "stop", "suspend"], + } + argument_spec["vm"] = {"required": True, "type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/power").format(**params) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _reset(params, session): + _in_query_parameters = PAYLOAD_FORMAT["reset"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["reset"]) + subdevice_type = get_subdevice_type("/api/vcenter/vm/{vm}/power?action=reset") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/vcenter/vm/{vm}/power?action=reset" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "reset") + + +async def _start(params, session): + _in_query_parameters = PAYLOAD_FORMAT["start"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["start"]) + subdevice_type = get_subdevice_type("/api/vcenter/vm/{vm}/power?action=start") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/vcenter/vm/{vm}/power?action=start" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "start") + + +async def _stop(params, session): + _in_query_parameters = PAYLOAD_FORMAT["stop"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["stop"]) + subdevice_type = get_subdevice_type("/api/vcenter/vm/{vm}/power?action=stop") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/vcenter/vm/{vm}/power?action=stop" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "stop") + + +async def _suspend(params, session): + _in_query_parameters = PAYLOAD_FORMAT["suspend"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["suspend"]) + subdevice_type = get_subdevice_type("/api/vcenter/vm/{vm}/power?action=suspend") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/vcenter/vm/{vm}/power?action=suspend" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "suspend") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_power_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_power_info.py new file mode 100644 index 00000000..d51747d3 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_power_info.py @@ -0,0 +1,231 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_power_info +short_description: Returns the power state information of a virtual machine. +description: Returns the power state information of a virtual machine. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine identifier. Required with I(state=['get']) + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Get guest power information + vmware.vmware_rest.vcenter_vm_power_info: + vm: '{{ test_vm1_info.id }}' +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get guest power information +value: + description: Get guest power information + returned: On success + sample: + state: POWERED_ON + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"vm": "vm"}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["vm"] = {"type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/power").format(**params) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/power").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_storage_policy.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_storage_policy.py new file mode 100644 index 00000000..c5634c93 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_storage_policy.py @@ -0,0 +1,327 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_storage_policy +short_description: Updates the storage policy configuration of a virtual machine and/or + its associated virtual hard disks. +description: Updates the storage policy configuration of a virtual machine and/or + its associated virtual hard disks. +options: + disks: + description: + - Storage policy or policies to be used when reconfiguring virtual machine diks. + type: dict + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - present + default: present + description: [] + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine identifier. This parameter is mandatory. + required: true + type: str + vm_home: + description: + - Storage policy to be used when reconfiguring the virtual machine home. This + parameter is mandatory. + - 'Valid attributes are:' + - ' - C(type) (str): The C(policy_type) defines the choices for how to specify + the policy to be associated with the virtual machine home''s directory. ([''present''])' + - ' This key is required with [''present''].' + - ' - Accepted values:' + - ' - USE_DEFAULT_POLICY' + - ' - USE_SPECIFIED_POLICY' + - ' - C(policy) (str): Storage Policy identification. ([''present''])' + required: true + type: dict +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Adjust VM storage policy + vmware.vmware_rest.vcenter_vm_storage_policy: + vm: '{{ test_vm1_info.id }}' + vm_home: + type: USE_DEFAULT_POLICY + disks: '{{ vm_disk_policy }}' +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Adjust VM storage policy +id: + description: moid of the resource + returned: On success + sample: null + type: dict +value: + description: Adjust VM storage policy + returned: On success + sample: {} + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "update": { + "query": {}, + "body": {"disks": "disks", "vm_home": "vm_home"}, + "path": {"vm": "vm"}, + } +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["disks"] = {"type": "dict"} + argument_spec["state"] = { + "type": "str", + "choices": ["present"], + "default": "present", + } + argument_spec["vm"] = {"required": True, "type": "str"} + argument_spec["vm_home"] = {"required": True, "type": "dict"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/storage/policy").format( + **params + ) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _update(params, session): + payload = prepare_payload(params, PAYLOAD_FORMAT["update"]) + _url = ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/storage/policy").format( + **params + ) + async with session.get(_url, **session_timeout(params)) as resp: + _json = await resp.json() + if "value" in _json: + value = _json["value"] + else: # 7.0.2 and greater + value = _json + for k, v in value.items(): + if k in payload: + if isinstance(payload[k], dict) and isinstance(v, dict): + to_delete = True + for _k in list(payload[k].keys()): + if payload[k][_k] != v.get(_k): + to_delete = False + if to_delete: + del payload[k] + elif payload[k] == v: + del payload[k] + elif payload[k] == {}: + del payload[k] + + if payload == {} or payload == {"spec": {}}: + # Nothing has changed + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + _json["id"] = params.get("None") + return await update_changed_flag(_json, resp.status, "get") + async with session.patch(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # e.g: content_configuration + if not _json and resp.status == 204: + async with session.get(_url, **session_timeout(params)) as resp_get: + _json_get = await resp_get.json() + if _json_get: + _json = _json_get + + _json["id"] = params.get("None") + return await update_changed_flag(_json, resp.status, "update") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_storage_policy_compliance.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_storage_policy_compliance.py new file mode 100644 index 00000000..da393b9f --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_storage_policy_compliance.py @@ -0,0 +1,265 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_storage_policy_compliance +short_description: Returns the storage policy Compliance {@link Info} of a virtual + machine after explicitly re-computing compliance check. +description: Returns the storage policy Compliance {@link Info} of a virtual machine + after explicitly re-computing compliance check. +options: + disks: + description: + - Identifiers of the virtual machine's virtual disks for which compliance should + be checked. + elements: str + type: list + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - check + description: [] + required: true + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine identifier. This parameter is mandatory. + required: true + type: str + vm_home: + description: + - Invoke compliance check on the virtual machine home directory if set to true. + This parameter is mandatory. + required: true + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +""" + +RETURN = r""" +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "check": { + "query": {}, + "body": {"disks": "disks", "vm_home": "vm_home"}, + "path": {"vm": "vm"}, + } +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["disks"] = {"type": "list", "elements": "str"} + argument_spec["state"] = {"required": True, "type": "str", "choices": ["check"]} + argument_spec["vm"] = {"required": True, "type": "str"} + argument_spec["vm_home"] = {"required": True, "type": "bool"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/storage/policy/compliance" + ).format(**params) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _check(params, session): + _in_query_parameters = PAYLOAD_FORMAT["check"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["check"]) + subdevice_type = get_subdevice_type( + "/api/vcenter/vm/{vm}/storage/policy/compliance?action=check" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/vcenter/vm/{vm}/storage/policy/compliance?action=check" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "check") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_storage_policy_compliance_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_storage_policy_compliance_info.py new file mode 100644 index 00000000..9d414473 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_storage_policy_compliance_info.py @@ -0,0 +1,241 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_storage_policy_compliance_info +short_description: Returns the cached storage policy compliance information of a virtual + machine. +description: Returns the cached storage policy compliance information of a virtual + machine. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine identifier. Required with I(state=['get']) + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Get VM storage policy compliance information + vmware.vmware_rest.vcenter_vm_storage_policy_compliance_info: + vm: '{{ test_vm1_info.id }}' +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get VM storage policy compliance information +value: + description: Get VM storage policy compliance information + returned: On success + sample: + disks: + '16000': + check_time: '2022-06-23T22:29:27.032Z' + failure_cause: [] + policy: f4e5bade-15a2-4805-bf8e-52318c4ce443 + status: NOT_APPLICABLE + overall_compliance: NOT_APPLICABLE + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"vm": "vm"}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["vm"] = {"type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/storage/policy/compliance" + ).format(**params) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ( + "https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/storage/policy/compliance" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_storage_policy_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_storage_policy_info.py new file mode 100644 index 00000000..b40c2ffa --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_storage_policy_info.py @@ -0,0 +1,235 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_storage_policy_info +short_description: Returns Information about Storage Policy associated with a virtual + machine's home directory and/or its virtual hard disks. +description: Returns Information about Storage Policy associated with a virtual machine's + home directory and/or its virtual hard disks. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine identifier Required with I(state=['get']) + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Get VM storage policy + vmware.vmware_rest.vcenter_vm_storage_policy_info: + vm: '{{ test_vm1_info.id }}' +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get VM storage policy +value: + description: Get VM storage policy + returned: On success + sample: + disks: {} + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"vm": "vm"}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["vm"] = {"type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/storage/policy").format( + **params + ) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/storage/policy").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_tools.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_tools.py new file mode 100644 index 00000000..6b84b2b2 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_tools.py @@ -0,0 +1,364 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_tools +short_description: Update the properties of VMware Tools. +description: Update the properties of VMware Tools. +options: + command_line_options: + description: + - Command line options passed to the installer to modify the installation procedure + for Tools. + type: str + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - present + - upgrade + default: present + description: [] + type: str + upgrade_policy: + choices: + - MANUAL + - UPGRADE_AT_POWER_CYCLE + description: + - The C(upgrade_policy) defines when Tools are auto-upgraded for a virtual machine. + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Identifier of the virtual machine. This parameter is mandatory. + required: true + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Retrive vm-tools information + vmware.vmware_rest.vcenter_vm_tools: + vm: '{{ test_vm1_info.id }}' + +- name: Change vm-tools upgrade policy to UPGRADE_AT_POWER_CYCLE + vmware.vmware_rest.vcenter_vm_tools: + vm: '{{ test_vm1_info.id }}' + upgrade_policy: UPGRADE_AT_POWER_CYCLE + +- name: Change vm-tools upgrade policy to MANUAL + vmware.vmware_rest.vcenter_vm_tools: + vm: '{{ test_vm1_info.id }}' + upgrade_policy: MANUAL +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Retrive vm-tools information +id: + description: moid of the resource + returned: On success + sample: null + type: dict +value: + description: Retrive vm-tools information + returned: On success + sample: + auto_update_supported: 0 + install_attempt_count: 0 + install_type: OPEN_VM_TOOLS + run_state: RUNNING + upgrade_policy: MANUAL + version: '10346' + version_number: 10346 + version_status: UNMANAGED + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "upgrade": { + "query": {}, + "body": {"command_line_options": "command_line_options"}, + "path": {"vm": "vm"}, + }, + "update": { + "query": {}, + "body": {"upgrade_policy": "upgrade_policy"}, + "path": {"vm": "vm"}, + }, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["command_line_options"] = {"type": "str"} + argument_spec["state"] = { + "type": "str", + "choices": ["present", "upgrade"], + "default": "present", + } + argument_spec["upgrade_policy"] = { + "type": "str", + "choices": ["MANUAL", "UPGRADE_AT_POWER_CYCLE"], + } + argument_spec["vm"] = {"required": True, "type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/tools").format(**params) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _update(params, session): + payload = prepare_payload(params, PAYLOAD_FORMAT["update"]) + _url = ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/tools").format(**params) + async with session.get(_url, **session_timeout(params)) as resp: + _json = await resp.json() + if "value" in _json: + value = _json["value"] + else: # 7.0.2 and greater + value = _json + for k, v in value.items(): + if k in payload: + if isinstance(payload[k], dict) and isinstance(v, dict): + to_delete = True + for _k in list(payload[k].keys()): + if payload[k][_k] != v.get(_k): + to_delete = False + if to_delete: + del payload[k] + elif payload[k] == v: + del payload[k] + elif payload[k] == {}: + del payload[k] + + if payload == {} or payload == {"spec": {}}: + # Nothing has changed + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + _json["id"] = params.get("None") + return await update_changed_flag(_json, resp.status, "get") + async with session.patch(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + # e.g: content_configuration + if not _json and resp.status == 204: + async with session.get(_url, **session_timeout(params)) as resp_get: + _json_get = await resp_get.json() + if _json_get: + _json = _json_get + + _json["id"] = params.get("None") + return await update_changed_flag(_json, resp.status, "update") + + +async def _upgrade(params, session): + _in_query_parameters = PAYLOAD_FORMAT["upgrade"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["upgrade"]) + subdevice_type = get_subdevice_type("/api/vcenter/vm/{vm}/tools?action=upgrade") + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/vcenter/vm/{vm}/tools?action=upgrade" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "upgrade") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_tools_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_tools_info.py new file mode 100644 index 00000000..fce3ad6f --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_tools_info.py @@ -0,0 +1,292 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_tools_info +short_description: Get the properties of VMware Tools. +description: Get the properties of VMware Tools. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Identifier of the virtual machine. Required with I(state=['get']) + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Look up the VM called test_vm1 in the inventory + register: search_result + vmware.vmware_rest.vcenter_vm_info: + filter_names: + - test_vm1 + +- name: Collect information about a specific VM + vmware.vmware_rest.vcenter_vm_info: + vm: '{{ search_result.value[0].vm }}' + register: test_vm1_info + +- name: Wait until my VM is ready + vmware.vmware_rest.vcenter_vm_tools_info: + vm: '{{ test_vm1_info.id }}' + register: vm_tools_info + until: + - vm_tools_info is not failed + - vm_tools_info.value.run_state == "RUNNING" + retries: 60 + delay: 5 + +- name: Create a VM + vmware.vmware_rest.vcenter_vm: + placement: + cluster: "{{ lookup('vmware.vmware_rest.cluster_moid', '/my_dc/host/my_cluster')\ + \ }}" + datastore: "{{ lookup('vmware.vmware_rest.datastore_moid', '/my_dc/datastore/local')\ + \ }}" + folder: "{{ lookup('vmware.vmware_rest.folder_moid', '/my_dc/vm') }}" + resource_pool: "{{ lookup('vmware.vmware_rest.resource_pool_moid', '/my_dc/host/my_cluster/Resources')\ + \ }}" + name: test_vm1 + guest_OS: RHEL_7_64 + hardware_version: VMX_11 + memory: + hot_add_enabled: true + size_MiB: 1024 + disks: + - type: SATA + backing: + type: VMDK_FILE + vmdk_file: '[local] test_vm1/{{ disk_name }}.vmdk' + - type: SATA + new_vmdk: + name: second_disk + capacity: 32000000000 + cdroms: + - type: SATA + sata: + bus: 0 + unit: 2 + nics: + - backing: + type: STANDARD_PORTGROUP + network: "{{ lookup('vmware.vmware_rest.network_moid', '/my_dc/network/VM\ + \ Network') }}" + + register: my_vm + +- name: Wait until my VM is ready + vmware.vmware_rest.vcenter_vm_tools_info: + vm: '{{ my_vm.id }}' + register: vm_tools_info + until: + - vm_tools_info is not failed + - vm_tools_info.value.run_state == "RUNNING" + retries: 60 + delay: 5 +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Wait until my VM is ready +value: + description: Wait until my VM is ready + returned: On success + sample: + auto_update_supported: 0 + install_attempt_count: 0 + install_type: OPEN_VM_TOOLS + run_state: RUNNING + upgrade_policy: MANUAL + version: '10346' + version_number: 10346 + version_status: UNMANAGED + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"vm": "vm"}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["vm"] = {"type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/tools").format(**params) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/tools").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_tools_installer.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_tools_installer.py new file mode 100644 index 00000000..ba0ec7c3 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_tools_installer.py @@ -0,0 +1,334 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_tools_installer +short_description: Connects the VMware Tools CD installer as a CD-ROM for the guest + operating system +description: Connects the VMware Tools CD installer as a CD-ROM for the guest operating + system. On Windows guest operating systems with autorun, this should cause the installer + to initiate the Tools installation which will need user input to complete. On other + (non-Windows) guest operating systems this will make the Tools installation available, + and a a user will need to do guest-specific actions. On Linux, this includes opening + an archive and running the installer. To monitor the status of the Tools install, + clients should check the {@name vcenter.vm.Tools.Info#versionStatus} and {@name + vcenter.vm.Tools.Info#runState} from {@link vcenter.vm.Tools#get} +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + state: + choices: + - connect + - disconnect + description: [] + required: true + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Virtual machine ID This parameter is mandatory. + required: true + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Create a VM + vmware.vmware_rest.vcenter_vm: + placement: + cluster: "{{ lookup('vmware.vmware_rest.cluster_moid', '/my_dc/host/my_cluster')\ + \ }}" + datastore: "{{ lookup('vmware.vmware_rest.datastore_moid', '/my_dc/datastore/local')\ + \ }}" + folder: "{{ lookup('vmware.vmware_rest.folder_moid', '/my_dc/vm') }}" + resource_pool: "{{ lookup('vmware.vmware_rest.resource_pool_moid', '/my_dc/host/my_cluster/Resources')\ + \ }}" + name: test_vm1 + guest_OS: RHEL_7_64 + hardware_version: VMX_11 + memory: + hot_add_enabled: true + size_MiB: 1024 + disks: + - type: SATA + backing: + type: VMDK_FILE + vmdk_file: '[local] test_vm1/{{ disk_name }}.vmdk' + - type: SATA + new_vmdk: + name: second_disk + capacity: 32000000000 + cdroms: + - type: SATA + sata: + bus: 0 + unit: 2 + nics: + - backing: + type: STANDARD_PORTGROUP + network: "{{ lookup('vmware.vmware_rest.network_moid', '/my_dc/network/VM\ + \ Network') }}" + + register: my_vm + +- name: Update the vm-tools + vmware.vmware_rest.vcenter_vm_tools_installer: + vm: '{{ my_vm.id }}' + state: connect +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Update the vm-tools +value: + description: Update the vm-tools + returned: On success + sample: {} + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "disconnect": {"query": {}, "body": {}, "path": {"vm": "vm"}}, + "connect": {"query": {}, "body": {}, "path": {"vm": "vm"}}, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["state"] = { + "required": True, + "type": "str", + "choices": ["connect", "disconnect"], + } + argument_spec["vm"] = {"required": True, "type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/tools/installer").format( + **params + ) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _connect(params, session): + _in_query_parameters = PAYLOAD_FORMAT["connect"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["connect"]) + subdevice_type = get_subdevice_type( + "/api/vcenter/vm/{vm}/tools/installer?action=connect" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/vcenter/vm/{vm}/tools/installer?action=connect" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "connect") + + +async def _disconnect(params, session): + _in_query_parameters = PAYLOAD_FORMAT["disconnect"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["disconnect"]) + subdevice_type = get_subdevice_type( + "/api/vcenter/vm/{vm}/tools/installer?action=disconnect" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/vcenter/vm/{vm}/tools/installer?action=disconnect" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "disconnect") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_tools_installer_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_tools_installer_info.py new file mode 100644 index 00000000..78dd890d --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vm_tools_installer_info.py @@ -0,0 +1,260 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vm_tools_installer_info +short_description: Get information about the VMware Tools installer. +description: Get information about the VMware Tools installer. +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm: + description: + - Identifier of the virtual machine. Required with I(state=['get']) + type: str +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 0.1.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Create a VM + vmware.vmware_rest.vcenter_vm: + placement: + cluster: "{{ lookup('vmware.vmware_rest.cluster_moid', '/my_dc/host/my_cluster')\ + \ }}" + datastore: "{{ lookup('vmware.vmware_rest.datastore_moid', '/my_dc/datastore/local')\ + \ }}" + folder: "{{ lookup('vmware.vmware_rest.folder_moid', '/my_dc/vm') }}" + resource_pool: "{{ lookup('vmware.vmware_rest.resource_pool_moid', '/my_dc/host/my_cluster/Resources')\ + \ }}" + name: test_vm1 + guest_OS: RHEL_7_64 + hardware_version: VMX_11 + memory: + hot_add_enabled: true + size_MiB: 1024 + disks: + - type: SATA + backing: + type: VMDK_FILE + vmdk_file: '[local] test_vm1/{{ disk_name }}.vmdk' + - type: SATA + new_vmdk: + name: second_disk + capacity: 32000000000 + cdroms: + - type: SATA + sata: + bus: 0 + unit: 2 + nics: + - backing: + type: STANDARD_PORTGROUP + network: "{{ lookup('vmware.vmware_rest.network_moid', '/my_dc/network/VM\ + \ Network') }}" + + register: my_vm + +- name: Get information about the vm-tools + vmware.vmware_rest.vcenter_vm_tools_installer_info: + vm: '{{ my_vm.id }}' +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Get information about the vm-tools +value: + description: Get information about the vm-tools + returned: On success + sample: + is_connected: 0 + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": {"query": {}, "body": {}, "path": {"vm": "vm"}} +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["vm"] = {"type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/tools/installer").format( + **params + ) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ("https://{vcenter_hostname}" "/api/vcenter/vm/{vm}/tools/installer").format( + **params + ) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vmtemplate_libraryitems.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vmtemplate_libraryitems.py new file mode 100644 index 00000000..47bd76f6 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vmtemplate_libraryitems.py @@ -0,0 +1,581 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vmtemplate_libraryitems +short_description: Creates a library item in content library from a virtual machine +description: Creates a library item in content library from a virtual machine. This + {@term operation} creates a library item in content library whose content is a virtual + machine template created from the source virtual machine, using the supplied create + specification. The virtual machine template is stored in a newly created library + item. +options: + description: + description: + - Description of the deployed virtual machine. + type: str + disk_storage: + description: + - Storage specification for the virtual machine template's disks. + - 'Valid attributes are:' + - ' - C(datastore) (str): Identifier for the datastore associated the deployed + virtual machine''s disk. ([''deploy'', ''present''])' + - ' - C(storage_policy) (dict): Storage policy for the deployed virtual machine''s + disk. ([''deploy'', ''present''])' + - ' - Accepted keys:' + - ' - type (string): Policy type for a virtual machine template''s disk.' + - 'Accepted value for this field:' + - ' - C(USE_SPECIFIED_POLICY)' + - ' - policy (string): Identifier for the storage policy to use.' + type: dict + disk_storage_overrides: + description: + - Storage specification for individual disks in the deployed virtual machine. + This is specified as a mapping between disk identifiers in the source virtual + machine template contained in the library item and their storage specifications. + type: dict + guest_customization: + description: + - Guest customization spec to apply to the deployed virtual machine. + - 'Valid attributes are:' + - ' - C(name) (str): Name of the customization specification. ([''deploy''])' + type: dict + hardware_customization: + description: + - Hardware customization spec which specifies updates to the deployed virtual + machine. + - 'Valid attributes are:' + - ' - C(nics) (dict): Map of Ethernet network adapters to update. ([''deploy''])' + - ' - C(disks_to_remove) (list): Idenfiers of disks to remove from the deployed + virtual machine. ([''deploy''])' + - ' - C(disks_to_update) (dict): Disk update specification for individual disks + in the deployed virtual machine. ([''deploy''])' + - ' - C(cpu_update) (dict): CPU update specification for the deployed virtual + machine. ([''deploy''])' + - ' - Accepted keys:' + - ' - num_cpus (integer): Number of virtual processors in the deployed virtual + machine.' + - ' - num_cores_per_socket (integer): Number of cores among which to distribute + CPUs in the deployed virtual machine.' + - ' - C(memory_update) (dict): Memory update specification for the deployed virtual + machine. ([''deploy''])' + - ' - Accepted keys:' + - ' - memory (integer): Size of a virtual machine''s memory in MB.' + type: dict + library: + description: + - Identifier of the library in which the new library item should be created. Required + with I(state=['present']) + type: str + name: + description: + - Name of the deployed virtual machine. This parameter is mandatory. + required: true + type: str + placement: + description: + - Information used to place the virtual machine template. + - 'Valid attributes are:' + - ' - C(folder) (str): Virtual machine folder into which the deployed virtual + machine should be placed. ([''deploy'', ''present''])' + - ' - C(resource_pool) (str): Resource pool into which the deployed virtual machine + should be placed. ([''deploy'', ''present''])' + - ' - C(host) (str): Host onto which the virtual machine should be placed. If + C(#host) and C(#resource_pool) are both specified, C(#resource_pool) must belong + to C(#host). If C(#host) and C(#cluster) are both specified, C(#host) must be + a member of C(#cluster). ([''deploy'', ''present''])' + - ' - C(cluster) (str): Cluster onto which the deployed virtual machine should + be placed. If C(#cluster) and C(#resource_pool) are both specified, C(#resource_pool) + must belong to C(#cluster). If C(#cluster) and C(#host) are both specified, + C(#host) must be a member of C(#cluster). ([''deploy'', ''present''])' + type: dict + powered_on: + description: + - Specifies whether the deployed virtual machine should be powered on after deployment. + type: bool + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + source_vm: + description: + - Identifier of the source virtual machine to create the library item from. Required + with I(state=['present']) + type: str + state: + choices: + - deploy + - present + default: present + description: [] + type: str + template_library_item: + description: + - identifier of the content library item containing the source virtual machine + template to be deployed. Required with I(state=['deploy']) + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool + vm_home_storage: + description: + - Storage location for the virtual machine template's configuration and log files. + - 'Valid attributes are:' + - ' - C(datastore) (str): Identifier of the datastore for the deployed virtual + machine''s configuration and log files. ([''deploy'', ''present''])' + - ' - C(storage_policy) (dict): Storage policy for the deployed virtual machine''s + configuration and log files. ([''deploy'', ''present''])' + - ' - Accepted keys:' + - ' - type (string): Policy type for the virtual machine template''s configuration + and log files.' + - 'Accepted value for this field:' + - ' - C(USE_SPECIFIED_POLICY)' + - ' - policy (string): Identifier for the storage policy to use.' + type: dict +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.2.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +- name: Create a VM + vmware.vmware_rest.vcenter_vm: + placement: + cluster: "{{ lookup('vmware.vmware_rest.cluster_moid', '/my_dc/host/my_cluster')\ + \ }}" + datastore: "{{ lookup('vmware.vmware_rest.datastore_moid', '/my_dc/datastore/local')\ + \ }}" + folder: "{{ lookup('vmware.vmware_rest.folder_moid', '/my_dc/vm') }}" + resource_pool: "{{ lookup('vmware.vmware_rest.resource_pool_moid', '/my_dc/host/my_cluster/Resources')\ + \ }}" + name: test_vm1 + guest_OS: RHEL_7_64 + hardware_version: VMX_11 + memory: + hot_add_enabled: true + size_MiB: 1024 + disks: + - type: SATA + backing: + type: VMDK_FILE + vmdk_file: '[local] test_vm1/{{ disk_name }}.vmdk' + - type: SATA + new_vmdk: + name: second_disk + capacity: 32000000000 + cdroms: + - type: SATA + sata: + bus: 0 + unit: 2 + nics: + - backing: + type: STANDARD_PORTGROUP + network: "{{ lookup('vmware.vmware_rest.network_moid', '/my_dc/network/VM\ + \ Network') }}" + register: my_vm + +- name: Create a content library based on a DataStore + vmware.vmware_rest.content_locallibrary: + name: my_library_on_datastore + description: automated + publish_info: + published: true + authentication_method: NONE + storage_backings: + - datastore_id: "{{ lookup('vmware.vmware_rest.datastore_moid', '/my_dc/datastore/local')\ + \ }}" + type: DATASTORE + state: present + register: ds_lib + +- name: Create a VM template on the library + vmware.vmware_rest.vcenter_vmtemplate_libraryitems: + name: foobar2001 + library: '{{ ds_lib.id }}' + source_vm: '{{ my_vm.id }}' + placement: + cluster: "{{ lookup('vmware.vmware_rest.cluster_moid', '/my_dc/host/my_cluster')\ + \ }}" + folder: "{{ lookup('vmware.vmware_rest.folder_moid', '/my_dc/vm') }}" + resource_pool: "{{ lookup('vmware.vmware_rest.resource_pool_moid', '/my_dc/host/my_cluster/Resources')\ + \ }}" + register: mylib_item + +- name: Deploy a new VM based on the template + vmware.vmware_rest.vcenter_vmtemplate_libraryitems: + name: foobar2002 + library: '{{ ds_lib.id }}' + template_library_item: '{{ mylib_item.id }}' + placement: + cluster: "{{ lookup('vmware.vmware_rest.cluster_moid', '/my_dc/host/my_cluster')\ + \ }}" + folder: "{{ lookup('vmware.vmware_rest.folder_moid', '/my_dc/vm') }}" + resource_pool: "{{ lookup('vmware.vmware_rest.resource_pool_moid', '/my_dc/host/my_cluster/Resources')\ + \ }}" + state: deploy + register: my_new_vm +""" + +RETURN = r""" +# content generated by the update_return_section callback# task: Create a VM template on the library +id: + description: moid of the resource + returned: On success + sample: 551beca2-0592-433a-86f2-b2581bfb3b60 + type: str +value: + description: Create a VM template on the library + returned: On success + sample: + cpu: + cores_per_socket: 1 + count: 1 + disks: + '16000': + capacity: 16106127360 + disk_storage: + datastore: datastore-1256 + '16001': + capacity: 32000000000 + disk_storage: + datastore: datastore-1256 + guest_OS: RHEL_7_64 + memory: + size_MiB: 1024 + nics: + '4000': + backing_type: STANDARD_PORTGROUP + mac_type: ASSIGNED + network: network-1257 + vm_home_storage: + datastore: datastore-1256 + vm_template: vm-1265 + type: dict +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "deploy": { + "query": {}, + "body": { + "description": "description", + "disk_storage": "disk_storage", + "disk_storage_overrides": "disk_storage_overrides", + "guest_customization": "guest_customization", + "hardware_customization": "hardware_customization", + "name": "name", + "placement": "placement", + "powered_on": "powered_on", + "vm_home_storage": "vm_home_storage", + }, + "path": {"template_library_item": "template_library_item"}, + }, + "create": { + "query": {}, + "body": { + "description": "description", + "disk_storage": "disk_storage", + "disk_storage_overrides": "disk_storage_overrides", + "library": "library", + "name": "name", + "placement": "placement", + "source_vm": "source_vm", + "vm_home_storage": "vm_home_storage", + }, + "path": {}, + }, +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["description"] = {"type": "str"} + argument_spec["disk_storage"] = {"type": "dict"} + argument_spec["disk_storage_overrides"] = {"type": "dict"} + argument_spec["guest_customization"] = {"type": "dict"} + argument_spec["hardware_customization"] = {"type": "dict"} + argument_spec["library"] = {"type": "str"} + argument_spec["name"] = {"required": True, "type": "str"} + argument_spec["placement"] = {"type": "dict"} + argument_spec["powered_on"] = {"type": "bool"} + argument_spec["source_vm"] = {"type": "str"} + argument_spec["state"] = { + "type": "str", + "choices": ["deploy", "present"], + "default": "present", + } + argument_spec["template_library_item"] = {"type": "str"} + argument_spec["vm_home_storage"] = {"type": "dict"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: default_module.j2 +def build_url(params): + return ( + "https://{vcenter_hostname}" "/api/vcenter/vm-template/library-items" + ).format(**params) + + +async def entry_point(module, session): + + if module.params["state"] == "present": + if "_create" in globals(): + operation = "create" + else: + operation = "update" + elif module.params["state"] == "absent": + operation = "delete" + else: + operation = module.params["state"] + + func = globals()["_" + operation] + + return await func(module.params, session) + + +async def _create(params, session): + + lookup_url = "https://{vcenter_hostname}/api/content/library/item?library_id={library}".format( + **params + ) + per_id_url = "https://{vcenter_hostname}/api/content/library/item".format(**params) + uniquity_keys = ["name"] + comp_func = None + + _json = None + + if params["template_library_item"]: + _json = await get_device_info( + session, build_url(params), params["template_library_item"] + ) + + if not _json and (uniquity_keys or comp_func): + _json = await exists( + params, + session, + url=lookup_url, + uniquity_keys=uniquity_keys, + per_id_url=per_id_url, + comp_func=comp_func, + ) + + if _json: + if "value" not in _json: # 7.0.2+ + _json = {"value": _json} + if "_update" in globals(): + params["template_library_item"] = _json["id"] + return await globals()["_update"](params, session) + + extra_info_url = "https://{vcenter_hostname}/api/vcenter/vm-template/library-items/{id}".format( + **params, id=_json["id"] + ) + async with session.get(extra_info_url) as resp: + if resp.status == 200: + extra_json = await resp.json() + for k, v in extra_json.items(): + _json["value"][k] = v + + return await update_changed_flag(_json, 200, "get") + + payload = prepare_payload(params, PAYLOAD_FORMAT["create"]) + _url = ( + "https://{vcenter_hostname}" "/api/vcenter/vm-template/library-items" + ).format(**params) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + if resp.status == 500: + text = await resp.text() + raise EmbeddedModuleFailure( + f"Request has failed: status={resp.status}, {text}" + ) + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + + if (resp.status in [200, 201]) and "error" not in _json: + if isinstance(_json, str): # 7.0.2 and greater + _id = _json # TODO: fetch the object + elif isinstance(_json, dict) and "value" not in _json: + _id = list(_json["value"].values())[0] + elif isinstance(_json, dict) and "value" in _json: + _id = _json["value"] + _json_device_info = await get_device_info(session, _url, _id) + if _json_device_info: + _json = _json_device_info + + return await update_changed_flag(_json, resp.status, "create") + + +async def _deploy(params, session): + _in_query_parameters = PAYLOAD_FORMAT["deploy"]["query"].keys() + payload = prepare_payload(params, PAYLOAD_FORMAT["deploy"]) + subdevice_type = get_subdevice_type( + "/api/vcenter/vm-template/library-items/{template_library_item}?action=deploy" + ) + if subdevice_type and not params[subdevice_type]: + _json = await exists(params, session, build_url(params)) + if _json: + params[subdevice_type] = _json["id"] + _url = ( + "https://{vcenter_hostname}" + # aa + "/api/vcenter/vm-template/library-items/{template_library_item}?action=deploy" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.post(_url, json=payload, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + if "value" not in _json: # 7.0.2 + _json = {"value": _json} + + return await update_changed_flag(_json, resp.status, "deploy") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vmtemplate_libraryitems_info.py b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vmtemplate_libraryitems_info.py new file mode 100644 index 00000000..72c5dac5 --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/modules/vcenter_vmtemplate_libraryitems_info.py @@ -0,0 +1,219 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2021, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# template: header.j2 +# This module is autogenerated by vmware_rest_code_generator. +# See: https://github.com/ansible-collections/vmware_rest_code_generator +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +DOCUMENTATION = r""" +module: vcenter_vmtemplate_libraryitems_info +short_description: Returns information about a virtual machine template contained + in the library item specified by {@param.name templateLibraryItem} +description: Returns information about a virtual machine template contained in the + library item specified by {@param.name templateLibraryItem} +options: + session_timeout: + description: + - 'Timeout settings for client session. ' + - 'The maximal number of seconds for the whole operation including connection + establishment, request sending and response. ' + - The default value is 300s. + type: float + version_added: 2.1.0 + template_library_item: + description: + - identifier of the library item containing the virtual machine template. Required + with I(state=['get']) + type: str + vcenter_hostname: + description: + - The hostname or IP address of the vSphere vCenter + - If the value is not specified in the task, the value of environment variable + C(VMWARE_HOST) will be used instead. + required: true + type: str + vcenter_password: + description: + - The vSphere vCenter password + - If the value is not specified in the task, the value of environment variable + C(VMWARE_PASSWORD) will be used instead. + required: true + type: str + vcenter_rest_log_file: + description: + - 'You can use this optional parameter to set the location of a log file. ' + - 'This file will be used to record the HTTP REST interaction. ' + - 'The file will be stored on the host that run the module. ' + - 'If the value is not specified in the task, the value of ' + - environment variable C(VMWARE_REST_LOG_FILE) will be used instead. + type: str + vcenter_username: + description: + - The vSphere vCenter username + - If the value is not specified in the task, the value of environment variable + C(VMWARE_USER) will be used instead. + required: true + type: str + vcenter_validate_certs: + default: true + description: + - Allows connection when SSL certificates are not valid. Set to C(false) when + certificates are not trusted. + - If the value is not specified in the task, the value of environment variable + C(VMWARE_VALIDATE_CERTS) will be used instead. + type: bool +author: +- Ansible Cloud Team (@ansible-collections) +version_added: 2.2.0 +requirements: +- vSphere 7.0.2 or greater +- python >= 3.6 +- aiohttp +notes: +- Tested on vSphere 7.0.2 +""" + +EXAMPLES = r""" +""" + +RETURN = r""" +""" + +# This structure describes the format of the data expected by the end-points +PAYLOAD_FORMAT = { + "get": { + "query": {}, + "body": {}, + "path": {"template_library_item": "template_library_item"}, + } +} # pylint: disable=line-too-long + +import json +import socket +from ansible.module_utils.basic import env_fallback + +try: + from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, + ) + from ansible_collections.cloud.common.plugins.module_utils.turbo.module import ( + AnsibleTurboModule as AnsibleModule, + ) + + AnsibleModule.collection_name = "vmware.vmware_rest" +except ImportError: + from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + build_full_device_list, + exists, + gen_args, + get_device_info, + get_subdevice_type, + list_devices, + open_session, + prepare_payload, + update_changed_flag, + session_timeout, +) + + +def prepare_argument_spec(): + argument_spec = { + "vcenter_hostname": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_HOST"]), + ), + "vcenter_username": dict( + type="str", required=True, fallback=(env_fallback, ["VMWARE_USER"]), + ), + "vcenter_password": dict( + type="str", + required=True, + no_log=True, + fallback=(env_fallback, ["VMWARE_PASSWORD"]), + ), + "vcenter_validate_certs": dict( + type="bool", + required=False, + default=True, + fallback=(env_fallback, ["VMWARE_VALIDATE_CERTS"]), + ), + "vcenter_rest_log_file": dict( + type="str", + required=False, + fallback=(env_fallback, ["VMWARE_REST_LOG_FILE"]), + ), + "session_timeout": dict( + type="float", + required=False, + fallback=(env_fallback, ["VMWARE_SESSION_TIMEOUT"]), + ), + } + + argument_spec["template_library_item"] = {"type": "str"} + + return argument_spec + + +async def main(): + required_if = list([]) + + module_args = prepare_argument_spec() + module = AnsibleModule( + argument_spec=module_args, required_if=required_if, supports_check_mode=True + ) + if not module.params["vcenter_hostname"]: + module.fail_json("vcenter_hostname cannot be empty") + if not module.params["vcenter_username"]: + module.fail_json("vcenter_username cannot be empty") + if not module.params["vcenter_password"]: + module.fail_json("vcenter_password cannot be empty") + try: + session = await open_session( + vcenter_hostname=module.params["vcenter_hostname"], + vcenter_username=module.params["vcenter_username"], + vcenter_password=module.params["vcenter_password"], + validate_certs=module.params["vcenter_validate_certs"], + log_file=module.params["vcenter_rest_log_file"], + ) + except EmbeddedModuleFailure as err: + module.fail_json(err.get_message()) + result = await entry_point(module, session) + module.exit_json(**result) + + +# template: info_no_list_module.j2 +def build_url(params): + return ( + "https://{vcenter_hostname}" "/api/vcenter/vm-template/library-items" + ).format(**params) + + +async def entry_point(module, session): + return await _info(module.params, session) + + +async def _info(params, session): + payload_format = list(PAYLOAD_FORMAT.values())[0] + _in_query_parameters = payload_format["query"].keys() + _url = ( + "https://{vcenter_hostname}" "/api/vcenter/vm-template/library-items" + ).format(**params) + gen_args(params, _in_query_parameters) + async with session.get(_url, **session_timeout(params)) as resp: + try: + if resp.headers["Content-Type"] == "application/json": + _json = await resp.json() + except KeyError: + _json = {} + return await update_changed_flag(_json, resp.status, "get") + + +if __name__ == "__main__": + import asyncio + + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(main()) diff --git a/ansible_collections/vmware/vmware_rest/plugins/plugin_utils/lookup.py b/ansible_collections/vmware/vmware_rest/plugins/plugin_utils/lookup.py new file mode 100644 index 00000000..236e718d --- /dev/null +++ b/ansible_collections/vmware/vmware_rest/plugins/plugin_utils/lookup.py @@ -0,0 +1,601 @@ +# Copyright: (c) 2021, Alina Buzachis <@alinabuzachis> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + + +import asyncio +import os + +from ansible.module_utils._text import to_native +from ansible.errors import AnsibleLookupError + +from ansible_collections.cloud.common.plugins.module_utils.turbo.exceptions import ( + EmbeddedModuleFailure, +) +from ansible_collections.vmware.vmware_rest.plugins.module_utils.vmware_rest import ( + open_session, + gen_args, +) + + +INVENTORY = { + "resource_pool": { + "list": { + "query": { + "clusters": "clusters", + "datacenters": "datacenters", + "hosts": "hosts", + "names": "names", + "parent_resource_pools": "parent_resource_pools", + "resource_pools": "resource_pools", + } + } + }, + "datacenter": { + "list": { + "query": { + "datacenters": "datacenters", + "folders": "folders", + "names": "names", + } + } + }, + "folder": { + "list": { + "query": { + "datacenters": "datacenters", + "folders": "folders", + "names": "names", + "parent_folders": "parent_folders", + "type": "type", + } + } + }, + "cluster": { + "list": { + "query": { + "clusters": "clusters", + "datacenters": "datacenters", + "folders": "folders", + "names": "names", + } + } + }, + "host": { + "list": { + "query": { + "clusters": "clusters", + "datacenters": "datacenters", + "folders": "folders", + "hosts": "hosts", + "names": "names", + } + } + }, + "datastore": { + "list": { + "query": { + "datacenters": "datacenters", + "datastores": "datastores", + "folders": "folders", + "names": "names", + "types": "types", + } + } + }, + "vm": { + "list": { + "query": { + "clusters": "clusters", + "datacenters": "datacenters", + "folders": "folders", + "hosts": "hosts", + "names": "names", + "resource_pools": "resource_pools", + "vms": "vms", + } + } + }, + "network": { + "list": { + "query": { + "datacenters": "datacenters", + "folders": "folders", + "names": "names", + "networks": "networks", + "types": "types", + } + } + }, +} + + +def get_credentials(**options): + credentials = {} + credentials["vcenter_hostname"] = options.get("vcenter_hostname") or os.getenv( + "VMWARE_HOST" + ) + credentials["vcenter_username"] = options.get("vcenter_username") or os.getenv( + "VMWARE_USER" + ) + credentials["vcenter_password"] = options.get("vcenter_password") or os.getenv( + "VMWARE_PASSWORD" + ) + credentials["vcenter_validate_certs"] = options.get( + "vcenter_validate_certs" + ) or os.getenv("VMWARE_VALIDATE_CERTS") + credentials["vcenter_rest_log_file"] = options.get( + "vcenter_rest_log_file" + ) or os.getenv("VMWARE_REST_LOG_FILE") + return credentials + + +class Lookup: + def __init__(self, options): + self._options = options + + @classmethod + async def entry_point(cls, terms, options): + session = None + + if not options.get("vcenter_hostname"): + raise AnsibleLookupError("vcenter_hostname cannot be empty") + if not options.get("vcenter_username"): + raise AnsibleLookupError("vcenter_username cannot be empty") + if not options.get("vcenter_password"): + raise AnsibleLookupError("vcenter_password cannot be empty") + + try: + session = await open_session( + vcenter_hostname=options.get("vcenter_hostname"), + vcenter_username=options.get("vcenter_username"), + vcenter_password=options.get("vcenter_password"), + validate_certs=bool(options.get("vcenter_validate_certs")), + log_file=options.get("vcenter_rest_log_file"), + ) + except EmbeddedModuleFailure as e: + raise AnsibleLookupError( + f'Unable to connect to vCenter or ESXi API at {options.get("vcenter_hostname")}: {to_native(e)}' + ) + + lookup = cls(options) + lookup._options["session"] = session + + if not terms: + raise AnsibleLookupError("No object has been specified.") + + task = asyncio.ensure_future(lookup.moid(terms[0])) + + return await task + + async def fetch(self, url): + async with self._options["session"].get(url) as response: + result = await response.json() + return result + + def build_url(self, object_type, params): + try: + _in_query_parameters = INVENTORY[object_type]["list"]["query"].keys() + if object_type == "resource_pool": + object_type = object_type.replace("_", "-") + except KeyError: + raise AnsibleLookupError( + "object_type must be one of [%s]." % ", ".join(list(INVENTORY.keys())) + ) + + return ( + f"https://{self._options['vcenter_hostname']}/api/vcenter/{object_type}" + ) + gen_args(params, _in_query_parameters) + + async def _helper_fetch(self, object_type, filters): + _url = self.build_url(object_type, filters) + return await self.fetch(_url) + + @staticmethod + def ensure_result(result, object_type, object_name=None): + if not result or object_name and object_name not in result[0].values(): + return "" + + def _filter_result(result): + return [obj for obj in result if "%2f" not in obj["name"]] + + result = _filter_result(result) + if result and len(result) > 1: + raise AnsibleLookupError( + "More than one object available: [%s]." + % ", ".join( + list(f"{item['name']} => {item[object_type]}" for item in result) + ) + ) + try: + object_moid = result[0][object_type] + except (TypeError, KeyError, IndexError) as e: + raise AnsibleLookupError(to_native(e)) + return object_moid + + def _init_filter(self): + filters = {} + filters["datacenters"] = self._options["dc_moid"] + return filters + + async def _get_datacenter_moid(self, path): + filters = {} + dc_name = "" + dc_moid = "" + _result = "" + folder_moid = "" + _path = path + + # Retrieve folders MoID if any + folder_moid, _path = await self._get_folder_moid(path, filters) + + if _path: + dc_name = _path[0] + + filters["names"] = dc_name + filters["folders"] = folder_moid + _result = await self._helper_fetch("datacenter", filters) + dc_moid = self.ensure_result(_result, "datacenter", dc_name) + + return dc_moid, _path + + async def _fetch_result(self, object_path, object_type, filters): + _result = "" + obj_moid = "" + visited = [] + _object_path_list = list(object_path) + + _result = await self.recursive_folder_or_rp_moid_search( + object_path, object_type, filters + ) + if _result: + if object_path: + for obj in _result: + if _object_path_list: + if obj["name"] == _object_path_list[0]: + del _object_path_list[0] + else: + visited.append(obj) + if not visited: + obj_moid = [_result[-1]] + else: + obj_moid = _result + return obj_moid, _object_path_list + + async def _get_folder_moid(self, object_path, filters): + object_name = "" + result = "" + _result = "" + _object_path = [] + + if object_path: + _result, _object_path = await self._fetch_result( + object_path, "folder", filters + ) + result = self.ensure_result(_result, "folder") + + if _result and self._options["object_type"] == "folder": + if isinstance(_result, list) and _object_path: + obj_path_set = set(_object_path) + path_set = set([elem["name"] for elem in _result]) + if path_set - obj_path_set and self._options["_terms"][-1] != "/": + return "", _object_path + + if self._options["_terms"][-1] != "/": + object_name = object_path[-1] + + result = self.ensure_result([_result[-1]], "folder", object_name) + + if ( + self._options["_terms"][-1] == "/" + and self._options["object_type"] == "folder" + ): + result = await self.look_inside(result, filters) + + return result, _object_path + + async def _get_host_moid(self, object_path, filters): + host_moid = "" + result = "" + _object_path = [] + + # Host might be inside a cluster + if self._options["object_type"] in ("host", "vm", "network", "datastore"): + filters["names"] = object_path[0] + cluster_moid, _object_path = await self._get_cluster_moid( + object_path, filters + ) + if not cluster_moid: + return "", object_path[1:] + + filters = self._init_filter() + filters["clusters"] = cluster_moid + if _object_path: + filters["names"] = _object_path[0] + else: + filters["names"] = "" + + result = await self._helper_fetch("host", filters) + host_moid = self.ensure_result(result, "host", filters["names"]) + + return host_moid, _object_path[1:] + + async def _helper_get_resource_pool_moid(self, object_path, filters): + result = "" + rp_moid = "" + _object_path = [] + + # Resource pool might be inside a cluster + filters["names"] = object_path[0] + cluster_moid, _object_path = await self._get_cluster_moid(object_path, filters) + if not cluster_moid: + return "", _object_path + + filters = self._init_filter() + filters["clusters"] = cluster_moid + + if _object_path: + result, _object_path = await self._fetch_result( + _object_path, "resource_pool", filters + ) + rp_moid = self.ensure_result(result, "resource_pool") + + if not result and _object_path: + filters = self._init_filter() + filters["names"] = _object_path[0] + filters["clusters"] = cluster_moid + # Resource pool might be inside a host + host_moid, _object_path = await self._get_host_moid(_object_path, filters) + if not host_moid: + return "", _object_path + + filters["hosts"] = host_moid + if _object_path: + filters["names"] = _object_path[0] + result, _object_path = await self._fetch_result( + _object_path, "resource_pool", filters + ) + + if result and self._options["object_type"] == "resource_pool": + if isinstance(result, list) and _object_path: + obj_path_set = set(_object_path) + path_set = set([elem["name"] for elem in result]) + if path_set - obj_path_set and self._options["_terms"][-1] != "/": + return "", _object_path + + if ( + self._options["_terms"][-1] == "/" + and self._options["object_type"] == "resource_pool" + ): + result = await self.look_inside(rp_moid, filters) + return result, _object_path + + result = self.ensure_result(result, "resource_pool") + + return result, _object_path + + async def look_inside(self, pre_object, filters): + result = "" + _result = "" + filters["names"] = "" + object_type = self._options["object_type"] + + if pre_object: + if (object_type == "resource_pool" and "resgroup" in pre_object) or ( + object_type == "folder" and "group" in pre_object + ): + parent_key = f"parent_{object_type}s" + filters[parent_key] = pre_object + + object_key = f"{object_type}s" + filters[object_key] = "" + _result = await self._helper_fetch(object_type, filters) + result = self.ensure_result(_result, object_type) + + return result + + async def _get_subset_moid(self, object_path, filters): + object_name = "" + result = "" + _result = "" + _object_path = [] + + if not object_path: + if self._options["_terms"][-1] != "/": + return "", object_path + else: + if self._options["_terms"][-1] != "/": + object_name = object_path[-1] + + filters["names"] = object_name + _result = await self._helper_fetch(self._options["object_type"], filters) + result = self.ensure_result(_result, self._options["object_type"]) + if not result: + filters["names"] = "" + + if self._options["object_type"] == "vm": + # VM might be in a resource pool + result, _object_path = await self._helper_get_resource_pool_moid( + object_path, filters + ) + if result: + return result + + # Object might be inside a host + host_moid, _object_path = await self._get_host_moid(object_path, filters) + if not host_moid: + return "" + + filters["hosts"] = host_moid + filters["folders"] = "" + filters["names"] = object_name + _result = await self._helper_fetch(self._options["object_type"], filters) + result = self.ensure_result(_result, self._options["object_type"]) + + return result + + async def _get_cluster_moid(self, object_path, filters): + cluster_moid = "" + result = await self._helper_fetch("cluster", filters) + cluster_moid = self.ensure_result(result, "cluster", filters["names"]) + + return cluster_moid, object_path[1:] + + @staticmethod + def replace_space(string): + return string.replace(" ", "%20") if " " in string else string + + async def get_all_objects_path_moid(self, object_path, object_type, filters): + # GET MoID of all the objects specified in the path + filters["names"] = list(set(object_path)) + + if self._options["object_type"] == "vm": + filters["type"] = "VIRTUAL_MACHINE" + elif self._options["object_type"] not in ("resource_pool", "cluster", "folder"): + filters["type"] = self._options[ + "object_type" + ].upper() # HOST, DATASTORE, DATACENTER, NETWORK + + return await self._helper_fetch(object_type, filters) + + async def recursive_folder_or_rp_moid_search( + self, + object_path, + object_type, + filters, + parent_object=None, + objects_moid=None, + result=None, + ): + if result is None: + # GET MoID of all the objects specified in the path + result = [] + objects_moid = await self.get_all_objects_path_moid( + object_path, object_type, filters + ) + if not objects_moid: + return "" + elif len(objects_moid) == 1: + return objects_moid + + return await self.recursive_folder_or_rp_moid_search( + object_path, + object_type, + filters, + objects_moid=objects_moid, + result=result, + ) + parent_key = f"parent_{object_type}s" + filters[parent_key] = "" + + if objects_moid and object_path and objects_moid[0]["name"] == object_path[0]: + # There exists a folder MoID with this name + filters["names"] = object_path[0] + + if parent_object is not None: + filters[parent_key] = parent_object + tasks = [ + asyncio.ensure_future(self._helper_fetch(object_type, filters)) + for parent_object_info in objects_moid + if parent_object_info["name"] == object_path[0] + ] + _result = [await i for i in tasks] + [ + result.append(elem[0]) + for elem in _result + if elem + if _result and elem[0] not in result + ] + else: + _result = await self._helper_fetch(object_type, filters) + if not _result: + return "" + [result.append(elem) for elem in _result if elem not in result] + # Update parent_object + parent_object = result[0][object_type] + return await self.recursive_folder_or_rp_moid_search( + object_path[1:], + object_type, + filters, + parent_object, + objects_moid[1:], + result, + ) + if not object_path or (objects_moid and len(objects_moid) == 0): + # Return result and what left in the path + if not result: + result = objects_moid + return result + + if result: + # Update parent_object + parent_object = result[-1][object_type] + return await self.recursive_folder_or_rp_moid_search( + object_path[1:], + object_type, + filters, + parent_object, + objects_moid[1:], + result, + ) + + async def moid(self, object_path): + folder_moid = "" + result = "" + filters = {} + _path = [] + + if not object_path: + return "" + + # Split object_path for transversal + self._options["_terms"] = object_path + object_path = self.replace_space(object_path) + object_type = self._options["object_type"] + path = tuple(filter(None, object_path.split("/"))) + + # Retrieve datacenter MoID + dc_moid, _path = await self._get_datacenter_moid(path) + if object_type == "datacenter" or not dc_moid: + return dc_moid + self._options["dc_moid"] = dc_moid + filters["datacenters"] = self._options["dc_moid"] + + if _path: + _path = _path[1:] + + # Retrieve folders MoID + folder_moid, _path = await self._get_folder_moid(_path, filters) + if object_type == "folder" or not folder_moid: + return folder_moid + filters["folders"] = folder_moid + + if object_type == "cluster": + if object_path[-1] != "/": + # Save object name + filters["names"] = _path[-1] + else: + filters["names"] = "" + result, _obj_path = await self._get_cluster_moid(_path, filters) + + if object_type in ("datastore", "network"): + filters = self._init_filter() + filters["folders"] = folder_moid + result = await self._get_subset_moid(_path, filters) + + if object_type == "resource_pool": + result, _obj_path = await self._helper_get_resource_pool_moid( + _path, filters + ) + + if object_type == "vm": + result = await self._get_subset_moid(_path, filters) + + if object_type == "host": + result, _obj_path = await self._get_host_moid(_path, filters) + + return result |