#!/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 using the ansible.content_builder.
# See: https://github.com/ansible-community/ansible.content_builder


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.
        - If unset, will be generated.
        type: str
    boot:
        description:
        - Boot configuration.
        - If unset, guest-specific default values will be used.
        - 'Valid attributes are:'
        - ' - C(type) (str): This option 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.'
        - If unset, defaults to value that is recommended for the guest OS and is
            supported for the virtual hardware version. (['present'])
        - ' - C(network_protocol) (str): This option defines the valid network boot
            protocols supported when booting a virtual machine with 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.'
        - If unset, default value is 0. (['present'])
        - ' - C(retry) (bool): Flag indicating whether the virtual machine should
            automatically retry the boot process after a failure.'
        - If unset, default value is false. (['present'])
        - ' - C(retry_delay) (int): Delay in milliseconds before retrying the boot
            process after a failure; applicable only when I(retry) is true.'
        - If unset, default value is 10000. (['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.'
        - If unset, the value is unchanged. (['present'])
        type: dict
    boot_devices:
        description:
        - Boot device configuration.
        - If unset, a server-specific boot sequence will be used.
        - 'Valid attributes are:'
        - ' - C(type) (str): This option 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.
        - If unset, no CD-ROM devices will be created.
        - 'Valid attributes are:'
        - ' - C(type) (str): This option 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.'
        - If unset, the server will choose an available address; if none is available,
            the request will fail. (['present'])
        - '   - Accepted keys:'
        - '     - primary (boolean): Flag specifying whether the device should be
            attached to the primary or secondary IDE adapter of the virtual machine.'
        - If unset, the server will choose a adapter with an available connection.
            If no IDE connections are available, the request will be rejected.
        - '     - master (boolean): Flag specifying whether the device should be the
            master or slave device on the IDE adapter.'
        - If unset, the server will choose an available connection type. If no IDE
            connections are available, the request will be rejected.
        - ' - C(sata) (dict): Address for attaching the device to a virtual SATA adapter.'
        - If unset, the server will choose an available address; if none is available,
            the request will fail. (['present'])
        - '   - Accepted keys:'
        - '     - bus (integer): Bus number of the adapter to which the device should
            be attached.'
        - '     - unit (integer): Unit number of the device.'
        - If unset, the server will choose an available unit number on the specified
            adapter. If there are no available connections on the adapter, the request
            will be rejected.
        - ' - C(backing) (dict): Physical resource backing for the virtual CD-ROM
            device.'
        - If unset, defaults to automatic detection of a suitable host device. (['present'])
        - '   - Accepted keys:'
        - '     - type (string): This option 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.'
        - This field is optional and it is only relevant when the value of I(type)
            is ISO_FILE.
        - '     - host_device (string): Name of the device that should be used as
            the virtual CD-ROM device backing.'
        - If unset, the virtual CD-ROM device will be configured to automatically
            detect a suitable host device.
        - '     - device_access_type (string): This option 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.'
        - Defaults to false if unset. (['present'])
        - ' - C(allow_guest_control) (bool): Flag indicating whether the guest can
            connect and disconnect the device.'
        - Defaults to false if unset. (['present'])
        elements: dict
        type: list
    cpu:
        description:
        - CPU configuration.
        - If unset, guest-specific default values will be used.
        - '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 I(hot_add_enabled) is true, and may only be decreased if
            I(hot_remove_enabled) is true.'
        - ''
        - If unset, the value is unchanged. (['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.'
        - If unset, the value is unchanged. (['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.'
        - ''
        - If unset, the value is unchanged. (['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.'
        - ''
        - If unset, the value is unchanged. (['present'])
        type: dict
    datastore:
        description:
        - Identifier of the datastore on which the virtual machine's configuration
            state is stored.
        - If unset, I(path) must also be unset and I(datastore_path) must be set.
        - 'When clients pass a value of this structure as a parameter, the field must
            be the id of a resource returned by M(vmware.vmware_rest.vcenter_datastore_info). '
        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".
        - If unset, both I(datastore) and I(path) must be set.
        type: str
    disconnect_all_nics:
        description:
        - Indicates whether all NICs on the destination virtual machine should be
            disconnected from the newtwork
        - If unset, connection status of all NICs on the destination virtual machine
            will be the same as on the source virtual machine.
        type: bool
    disks:
        description:
        - Individual disk relocation map.
        - If unset, all disks will migrate to the datastore specified in the I(datastore)
            field of I()
        - 'When clients pass a value of this structure as a parameter, the key in
            the field map must be the id of a resource returned by M(vmware.vmware_rest.vcenter_vm_hardware_disk). '
        - 'Valid attributes are:'
        - ' - C(type) (str): This option 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'
        - '     - NVME'
        - '     - SATA'
        - '     - SCSI'
        - ' - C(ide) (dict): Address for attaching the device to a virtual IDE adapter.'
        - If unset, the server will choose an available address; if none is available,
            the request will fail. (['present'])
        - '   - Accepted keys:'
        - '     - primary (boolean): Flag specifying whether the device should be
            attached to the primary or secondary IDE adapter of the virtual machine.'
        - If unset, the server will choose a adapter with an available connection.
            If no IDE connections are available, the request will be rejected.
        - '     - master (boolean): Flag specifying whether the device should be the
            master or slave device on the IDE adapter.'
        - If unset, the server will choose an available connection type. If no IDE
            connections are available, the request will be rejected.
        - ' - C(scsi) (dict): Address for attaching the device to a virtual SCSI adapter.'
        - If unset, the server will choose an available address; if none is available,
            the request will fail. (['present'])
        - '   - Accepted keys:'
        - '     - bus (integer): Bus number of the adapter to which the device should
            be attached.'
        - '     - unit (integer): Unit number of the device.'
        - If unset, the server will choose an available unit number on the specified
            adapter. If there are no available connections on the adapter, the request
            will be rejected.
        - ' - C(sata) (dict): Address for attaching the device to a virtual SATA adapter.'
        - If unset, the server will choose an available address; if none is available,
            the request will fail. (['present'])
        - '   - Accepted keys:'
        - '     - bus (integer): Bus number of the adapter to which the device should
            be attached.'
        - '     - unit (integer): Unit number of the device.'
        - If unset, the server will choose an available unit number on the specified
            adapter. If there are no available connections on the adapter, the request
            will be rejected.
        - ' - C(nvme) (dict): Address for attaching the device to a virtual NVMe adapter.'
        - If unset, the server will choose an available address; if none is available,
            the request will fail. (['present'])
        - '   - Accepted keys:'
        - '     - bus (integer): Bus number of the adapter to which the device should
            be attached.'
        - '     - unit (integer): Unit number of the device.'
        - If unset, the server will choose an available unit number on the specified
            adapter. If there are no available connections on the adapter, the request
            will be rejected.
        - ' - C(backing) (dict): Existing physical resource backing for the virtual
            disk. Exactly one of I(backing) or I(new_vmdk) must be specified.'
        - If unset, the virtual disk will not be connected to an existing backing.
            (['present'])
        - '   - Accepted keys:'
        - '     - type (string): This option 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.'
        - This field is optional and it is only relevant when the value of I(type)
            is VMDK_FILE.
        - ' - C(new_vmdk) (dict): Specification for creating a new VMDK backing for
            the virtual disk. Exactly one of I(backing) or I(new_vmdk) must be specified.'
        - If unset, a new VMDK backing will not be created. (['present'])
        - '   - Accepted keys:'
        - '     - name (string): Base name of the VMDK file. The name should not include
            the ''.vmdk'' file extension.'
        - If unset, a name (derived from the name of the virtual machine) will be
            chosen by the server.
        - '     - capacity (integer): Capacity of the virtual disk backing in bytes.'
        - If unset, defaults to a guest-specific capacity.
        - '     - storage_policy (object): The I(storage_policy_spec) structure contains
            information about the storage policy that is to be associated the with
            VMDK file.'
        - 'If unset the default storage policy of the target datastore (if applicable)
            is applied. Currently a default storage policy is only supported by object
            based datastores : VVol & vSAN. For non- object datastores, if unset then
            no storage policy would be associated with the VMDK file.'
        elements: dict
        type: list
    disks_to_remove:
        description:
        - Set of Disks to Remove.
        - If unset, all disks will be copied. If the same identifier is in I(disks_to_update)
            InvalidArgument fault 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.vcenter_vm_hardware_disk).
        elements: str
        type: list
    disks_to_update:
        description:
        - Map of Disks to Update.
        - If unset, all disks will copied to the datastore specified in the I(datastore)
            field of I() If the same identifier is in I(disks_to_remove) InvalidArgument
            fault will be thrown.
        - 'When clients pass a value of this structure as a parameter, the key in
            the field map must be the id of a resource returned by M(vmware.vmware_rest.vcenter_vm_hardware_disk). '
        type: dict
    floppies:
        description:
        - List of floppy drives.
        - If unset, no floppy drives will be created.
        - 'Valid attributes are:'
        - ' - C(backing) (dict): Physical resource backing for the virtual floppy
            drive.'
        - If unset, defaults to automatic detection of a suitable host device. (['present'])
        - '   - Accepted keys:'
        - '     - type (string): This option 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.'
        - This field is optional and it is only relevant when the value of I(type)
            is IMAGE_FILE.
        - '     - host_device (string): Name of the device that should be used as
            the virtual floppy drive backing.'
        - If unset, the virtual floppy drive will be configured to automatically detect
            a suitable host device.
        - ' - C(start_connected) (bool): Flag indicating whether the virtual device
            should be connected whenever the virtual machine is powered on.'
        - Defaults to false if unset. (['present'])
        - ' - C(allow_guest_control) (bool): Flag indicating whether the guest can
            connect and disconnect the device.'
        - Defaults to false if unset. (['present'])
        elements: dict
        type: list
    guest_OS:
        choices:
        - ALMALINUX_64
        - 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_22_64
        - DARWIN_23_64
        - DARWIN_64
        - DEBIAN_10
        - DEBIAN_10_64
        - DEBIAN_11
        - DEBIAN_11_64
        - DEBIAN_12
        - DEBIAN_12_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_14
        - FREEBSD_14_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_6X_LINUX
        - OTHER_6X_LINUX_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
        - ROCKYLINUX_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
        - VMKERNEL_8
        - VMWARE_PHOTON_64
        - WINDOWS_11_64
        - WINDOWS_12_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
        - WINDOWS_SERVER_2025
        - 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 GuestOS enumerated type 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.
        - If unset, the guest operating system is not customized after clone.
        - 'Valid attributes are:'
        - ' - C(name) (str): Name of the customization specification.'
        - If unset, no guest customization is performed. (['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
        - VMX_20
        - VMX_21
        description:
        - The I(version) enumerated type 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.
        - If unset, guest-specific default values will be used.
        - '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 I(hot_add_enabled)
            is true, and the new memory size must satisfy the constraints specified
            by I(hot_add_increment_size_mib) and I()'
        - ''
        - If unset, the value is unchanged. (['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.'
        - ''
        - If unset, the value is unchanged. (['present'])
        type: dict
    name:
        description:
        - Virtual machine name.
        - If unset, the display name from the virtual machine's configuration file
            will be used.
        type: str
    nics:
        description:
        - List of Ethernet adapters.
        - If unset, no Ethernet adapters will be created.
        - 'Valid attributes are:'
        - ' - C(type) (str): This option 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.'
        - If unset, UPT will not be enabled on the newly-created virtual Ethernet
            adapter. (['present'])
        - ' - C(mac_type) (str): This option defines the valid MAC address origins
            for a virtual Ethernet adapter. ([''present''])'
        - '   - Accepted values:'
        - '     - ASSIGNED'
        - '     - GENERATED'
        - '     - MANUAL'
        - ' - C(mac_address) (str): MAC address.'
        - Workaround for PR1459647 (['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.'
        - If unset, the server will choose an available address when the virtual machine
            is powered on. (['present'])
        - ' - C(wake_on_lan_enabled) (bool): Flag indicating whether wake-on-LAN is
            enabled on this virtual Ethernet adapter.'
        - Defaults to false if unset. (['present'])
        - ' - C(backing) (dict): Physical resource backing for the virtual Ethernet
            adapter.'
        - If unset, the system may try to find an appropriate backing. If one is not
            found, the request will fail. (['present'])
        - '   - Accepted keys:'
        - '     - type (string): This option 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.'
        - This field is optional and it is only relevant when the value of I(type)
            is one of STANDARD_PORTGROUP, DISTRIBUTED_PORTGROUP, or OPAQUE_NETWORK.
        - 'When clients pass a value of this structure as a parameter, the field must
            be the id of a resource returned by M(vmware.vmware_rest.vcenter_network_info). '
        - '     - 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.'
        - May be used to specify a port when the network specified on the I(network)
            field is a static or early binding distributed portgroup. If unset, the
            port will be automatically assigned to the Ethernet adapter based on the
            policy embodied by the portgroup type.
        - ' - C(start_connected) (bool): Flag indicating whether the virtual device
            should be connected whenever the virtual machine is powered on.'
        - Defaults to false if unset. (['present'])
        - ' - C(allow_guest_control) (bool): Flag indicating whether the guest can
            connect and disconnect the device.'
        - Defaults to false if unset. (['present'])
        elements: dict
        type: list
    nics_to_update:
        description:
        - Map of NICs to update.
        - If unset, no NICs will be updated.
        - 'When clients pass a value of this structure as a parameter, the key in
            the field map must be the id of a resource returned by M(vmware.vmware_rest.vcenter_vm_hardware_ethernet). '
        type: dict
    nvme_adapters:
        description:
        - List of NVMe adapters.
        - If unset, any adapters necessary to connect the virtual machine's storage
            devices will be created; this includes any devices that explicitly specify
            a NVMe host bus adapter, as well as any devices that do not specify a
            host bus adapter if the guest's preferred adapter type is NVMe.
        - 'Valid attributes are:'
        - ' - C(bus) (int): NVMe bus number.'
        - If unset, the server will choose an available bus number; if none is available,
            the request will fail. (['present'])
        - ' - C(pci_slot_number) (int): Address of the NVMe adapter on the PCI bus.'
        - If unset, the server will choose an available address when the virtual machine
            is powered on. (['present'])
        elements: dict
        type: list
    parallel_ports:
        description:
        - List of parallel ports.
        - If unset, no parallel ports will be created.
        - 'Valid attributes are:'
        - ' - C(backing) (dict): Physical resource backing for the virtual parallel
            port.'
        - If unset, defaults to automatic detection of a suitable host device. (['present'])
        - '   - Accepted keys:'
        - '     - type (string): This option 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.'
        - This field is optional and it is only relevant when the value of I(type)
            is FILE.
        - '     - host_device (string): Name of the device that should be used as
            the virtual parallel port backing.'
        - If unset, the virtual parallel port will be configured to automatically
            detect a suitable host device.
        - ' - C(start_connected) (bool): Flag indicating whether the virtual device
            should be connected whenever the virtual machine is powered on.'
        - Defaults to false if unset. (['present'])
        - ' - C(allow_guest_control) (bool): Flag indicating whether the guest can
            connect and disconnect the device.'
        - Defaults to false if unset. (['present'])
        elements: dict
        type: list
    parallel_ports_to_update:
        description:
        - Map of parallel ports to Update.
        - If unset, no parallel ports will be updated.
        - 'When clients pass a value of this structure as a parameter, the key in
            the field map must be the id of a resource returned by M(vmware.vmware_rest.vcenter_vm_hardware_parallel). '
        type: dict
    path:
        description:
        - 'Path to the virtual machine''s configuration file on the datastore corresponding
            to {@link #datastore).'
        - If unset, I(datastore) must also be unset and I(datastore_path) must be
            set.
        type: str
    placement:
        description:
        - Virtual machine placement information.
        - If this field is unset, the system will use the values from the source virtual
            machine. If specified, each field will be used for placement. If the fields
            result in disjoint placement the operation will fail. If the fields along
            with the other existing placement of the virtual machine result in disjoint
            placement the operation will fail.
        - 'Valid attributes are:'
        - ' - C(folder) (str): Virtual machine folder into which the virtual machine
            should be placed.'
        - If this field is unset, the virtual machine will stay in the current folder.
        - When clients pass a value of this structure as a parameter, the field must
            be the id of a resource returned by M(vmware.vmware_rest.vcenter_folder_info).
            (['clone', 'instant_clone', 'present', 'register', 'relocate'])
        - ' - C(resource_pool) (str): Resource pool into which the virtual machine
            should be placed.'
        - If this field is unset, the virtual machine will stay in the current resource
            pool.
        - When clients pass a value of this structure as a parameter, the field must
            be the id of a resource returned by M(vmware.vmware_rest.vcenter_resourcepool_info).
            (['clone', 'instant_clone', 'present', 'register', 'relocate'])
        - ' - C(host) (str): Host onto which the virtual machine should be placed. '
        - ' If I(host) and I(resource_pool) are both specified, I(resource_pool) must
            belong to I(host). '
        - ''
        - ' If I(host) and I(cluster) are both specified, I(host) must be a member
            of I(cluster).'
        - ''
        - If this field is unset, if I(resource_pool) is unset, the virtual machine
            will remain on the current host. if I(resource_pool) is set, and the target
            is a standalone host, the host is used. if I(resource_pool) is set, and
            the target is a DRS cluster, a host will be picked by DRS. if I(resource_pool)
            is set, and the target is a cluster without DRS, InvalidArgument will
            be thrown.
        - When clients pass a value of this structure as a parameter, the field must
            be the id of a resource returned by M(vmware.vmware_rest.vcenter_host_info).
            (['clone', 'present', 'register', 'relocate'])
        - ' - C(cluster) (str): Cluster into which the virtual machine should be placed. '
        - ' If I(cluster) and I(resource_pool) are both specified, I(resource_pool)
            must belong to I(cluster). '
        - ''
        - ' If I(cluster) and I(host) are both specified, I(host) must be a member
            of I(cluster).'
        - ''
        - If I(resource_pool) or I(host) is specified, it is recommended that this
            field be unset.
        - When clients pass a value of this structure as a parameter, the field must
            be the id of a resource returned by M(vmware.vmware_rest.vcenter_cluster_info).
            (['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.'
        - If this field is unset, the virtual machine will remain on the current datastore.
        - When clients pass a value of this structure as a parameter, the field must
            be the id of a resource returned by M(vmware.vmware_rest.vcenter_datastore_info).
            (['clone', 'instant_clone', 'present', 'relocate'])
        type: dict
    power_on:
        description:
        - Attempt to perform a I(power_on) after clone.
        - If unset, the virtual machine will not be powered on.
        type: bool
    sata_adapters:
        description:
        - List of SATA adapters.
        - If unset, any adapters necessary to connect the virtual machine's storage
            devices will be created; this includes any devices that explicitly specify
            a SATA host bus adapter, as well as any devices that do not specify a
            host bus adapter if the guest's preferred adapter type is SATA.
        - 'Valid attributes are:'
        - ' - C(type) (str): This option defines the valid emulation types for a virtual
            SATA adapter. ([''present''])'
        - '   - Accepted values:'
        - '     - AHCI'
        - ' - C(bus) (int): SATA bus number.'
        - If unset, the server will choose an available bus number; if none is available,
            the request will fail. (['present'])
        - ' - C(pci_slot_number) (int): Address of the SATA adapter on the PCI bus.'
        - If unset, the server will choose an available address when the virtual machine
            is powered on. (['present'])
        elements: dict
        type: list
    scsi_adapters:
        description:
        - List of SCSI adapters.
        - If unset, any adapters necessary to connect the virtual machine's storage
            devices will be created; this includes any devices that explicitly specify
            a SCSI host bus adapter, as well as any devices that do not specify a
            host bus adapter if the guest's preferred adapter type is SCSI. The type
            of the SCSI adapter will be a guest-specific default type.
        - 'Valid attributes are:'
        - ' - C(type) (str): This option defines the valid emulation types for a virtual
            SCSI adapter. ([''present''])'
        - '   - Accepted values:'
        - '     - BUSLOGIC'
        - '     - LSILOGIC'
        - '     - LSILOGICSAS'
        - '     - PVSCSI'
        - ' - C(bus) (int): SCSI bus number.'
        - If unset, the server will choose an available bus number; if none is available,
            the request will fail. (['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.'
        - If unset, the server will choose an available address when the virtual machine
            is powered on. (['present'])
        - ' - C(sharing) (str): This option 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.
        - If unset, no serial ports will be created.
        - '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.'
        - If unset, defaults to false. (['present'])
        - ' - C(backing) (dict): Physical resource backing for the virtual serial
            port.'
        - If unset, defaults to automatic detection of a suitable host device. (['present'])
        - '   - Accepted keys:'
        - '     - type (string): This option 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.'
        - This field is optional and it is only relevant when the value of I(type)
            is FILE.
        - '     - host_device (string): Name of the device backing the virtual serial
            port. '
        - ''
        - ''
        - If unset, the virtual serial port will be configured to automatically detect
            a suitable host device.
        - '     - pipe (string): Name of the pipe backing the virtual serial port.'
        - This field is optional and it is only relevant when the value of I(type)
            is one of PIPE_SERVER or PIPE_CLIENT.
        - '     - 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.'
        - If unset, defaults to false.
        - '     - network_location (string): URI specifying the location of the network
            service backing the virtual serial port. '
        - '   - If I(type) is 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.'
        - '   - If I(type) is NETWORK_CLIENT, this field is the location used by the
            virtual machine to connect to the remote server.'
        - ' '
        - This field is optional and it is only relevant when the value of I(type)
            is one of NETWORK_SERVER or NETWORK_CLIENT.
        - '     - 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.'
        - If unset, no proxy service should be used.
        - ' - C(start_connected) (bool): Flag indicating whether the virtual device
            should be connected whenever the virtual machine is powered on.'
        - Defaults to false if unset. (['present'])
        - ' - C(allow_guest_control) (bool): Flag indicating whether the guest can
            connect and disconnect the device.'
        - Defaults to false if unset. (['present'])
        elements: dict
        type: list
    serial_ports_to_update:
        description:
        - Map of serial ports to Update.
        - If unset, no serial ports will be updated.
        - 'When clients pass a value of this structure as a parameter, the key in
            the field map must be the id of a resource returned by M(vmware.vmware_rest.vcenter_vm_hardware_serial). '
        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.
        - When clients pass a value of this structure as a parameter, the field must
            be the id of a resource returned by M(vmware.vmware_rest.vcenter_vm_info).
            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 I(storage_policy_spec) structure contains information about the storage
            policy that is to be associated with the virtual machine home (which contains
            the configuration and log files).
        - 'If unset the datastore default storage policy (if applicable) is applied.
            Currently a default storage policy is only supported by object datastores
            : VVol and vSAN. For non-object datastores, if unset then no storage policy
            would be associated with the virtual machine home. Required with I(state=[''present''])'
        - 'Valid attributes are:'
        - ' - C(policy) (str): Identifier of the storage policy which should be associated
            with the virtual machine.'
        - When clients pass a value of this structure as a parameter, the field must
            be the id of a resource returned by M(vmware.vmware_rest.vcenter_storage_policies_info).
            (['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 runs 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.
        - The parameter must be the id of a resource returned by M(vmware.vmware_rest.vcenter_vm_info).
            Required with I(state=['absent', 'relocate', 'unregister'])
        type: str
author:
- Ansible Cloud Team (@ansible-collections)
version_added: 0.1.0
requirements:
- vSphere 7.0.3 or greater
- python >= 3.6
- aiohttp
notes:
- Tested on vSphere 7.0.3
"""

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: RHEL_7_64
    hardware_version: VMX_11
    memory:
      hot_add_enabled: true
      size_MiB: 1024
  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/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: nfs_lib

- name: Get the list of items of the NFS library
  vmware.vmware.content_library_item_info:
    library_id: '{{ nfs_lib.id }}'
  register: lib_items

- name: Use the name to identify the item
  set_fact:
    my_template_item: "{{ lib_items.value | selectattr('name', 'equalto', 'golden-template')|first }}"

- name: Deploy a new VM based on the template
  vmware.vmware_rest.vcenter_vmtemplate_libraryitems:
    name: vm-from-template
    library: '{{ nfs_lib.id }}'
    template_library_item: '{{ my_template_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

- 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: 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: Set my_virtual_machine_folder
  ansible.builtin.set_fact:
    my_virtual_machine_folder: '{{ my_folders.value|first }}'

- 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
"""
RETURN = r"""
# content generated by the update_return_section callback# task: Create an instant clone of a VM
id:
  description: moid of the resource
  returned: On success
  sample: vm-1104
  type: str
value:
  description: Create an instant clone of a VM
  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_vm2/test_vm2_2.vmdk'
        capacity: 16106127360
        label: Hard disk 1
        sata:
          bus: 0
          unit: 0
        type: SATA
      '16001':
        backing:
          type: VMDK_FILE
          vmdk_file: '[local] test_vm2/test_vm2_1.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: 4231bf8b-3cb4-3a3f-1bfb-18c857ce95b6
      instance_uuid: 5031b322-6030-a020-8e73-1a9ad0fd03ce
      name: test_vm2
    instant_clone_frozen: 0
    memory:
      hot_add_enabled: 1
      hot_add_increment_size_MiB: 128
      hot_add_limit_MiB: 3072
      size_MiB: 1024
    name: test_vm2
    nics:
      '4000':
        allow_guest_control: 0
        backing:
          network: network-1095
          network_name: VM Network
          type: STANDARD_PORTGROUP
        label: Network adapter 1
        mac_address: 00:50:56:b1:26:0c
        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_ON
    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 = {
    "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",
            "nvme_adapters": "nvme_adapters",
            "parallel_ports": "parallel_ports",
            "placement": "placement",
            "sata_adapters": "sata_adapters",
            "scsi_adapters": "scsi_adapters",
            "serial_ports": "serial_ports",
            "storage_policy": "storage_policy",
        },
        "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": {},
    },
    "delete": {"query": {}, "body": {}, "path": {"vm": "vm"}},
    "relocate": {
        "query": {},
        "body": {"disks": "disks", "placement": "placement"},
        "path": {"vm": "vm"},
    },
    "unregister": {"query": {}, "body": {}, "path": {"vm": "vm"}},
    "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": {},
    },
    "register": {
        "query": {},
        "body": {
            "datastore": "datastore",
            "datastore_path": "datastore_path",
            "name": "name",
            "path": "path",
            "placement": "placement",
        },
        "path": {},
    },
}  # pylint: disable=line-too-long

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 (
    exists,
    gen_args,
    get_device_info,
    get_subdevice_type,
    open_session,
    prepare_payload,
    session_timeout,
    update_changed_flag,
)


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": [
            "ALMALINUX_64",
            "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_22_64",
            "DARWIN_23_64",
            "DARWIN_64",
            "DEBIAN_10",
            "DEBIAN_10_64",
            "DEBIAN_11",
            "DEBIAN_11_64",
            "DEBIAN_12",
            "DEBIAN_12_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_14",
            "FREEBSD_14_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_6X_LINUX",
            "OTHER_6X_LINUX_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",
            "ROCKYLINUX_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",
            "VMKERNEL_8",
            "VMWARE_PHOTON_64",
            "WINDOWS_11_64",
            "WINDOWS_12_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",
            "WINDOWS_SERVER_2025",
            "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",
            "VMX_20",
            "VMX_21",
        ],
    }
    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["nvme_adapters"] = {"type": "list", "elements": "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):
        search_filter = ""

        if "name" not in params:
            return
        async with session.get(f"{url}?names={params['name']}{search_filter}") 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):
        search_filter = ""

        if "name" not in params:
            return
        async with session.get(f"{url}?names={params['name']}{search_filter}") 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):
        search_filter = ""

        if "name" not in params:
            return
        async with session.get(f"{url}?names={params['name']}{search_filter}") 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.new_event_loop()
    try:
        asyncio.set_event_loop(current_loop)
        current_loop.run_until_complete(main())
    finally:
        current_loop.close()
