#!/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: content_subscribedlibrary
short_description: Creates a new subscribed library
description: 'Creates a new subscribed library. '
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: b8a2a2e3-2314-43cd-a871-6ede0f429751.
            This token can be used to guarantee idempotent creation.'
        - If not specified creation is not idempotent.
        type: str
    creation_time:
        description:
        - The date and time when this library was created.
        - This field is not used for the create operation. It will always be present
            in the result of the get or list operations. It is not used for the update
            operation.
        type: str
    description:
        description:
        - A human-readable description for this library.
        - This field is optional for the create operation. Leaving it unset during
            creation will result in an empty string value. It will always be present
            in the result of a get or list operation. It is optional for the update
            operation. Leaving it unset during update indicates that the description
            should be left unchanged.
        type: str
    id:
        description:
        - An identifier which uniquely identifies this LibraryModel.
        - This field is not used for the create operation. It will not be present
            in the result of the get or list operations. It is not used for the update
            operation.
        - '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.content_library_info). '
        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.'
        - ''
        - This field is not used for the create operation. It will always be present
            in the result of the get or list operations. It is not used for the update
            operation.
        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 unset for
            a local library.'
        - ''
        - This field is not used for the create operation. It is optional in the result
            of the get or list operations. It is not used for the update operation.
        type: str
    library_id:
        description:
        - Identifier of the subscribed library whose content should be evicted.
        - The parameter must be the id of a resource returned by M(vmware.vmware_rest.content_library_info).
            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.'
        - ''
        - This field must be provided for the create operation. It will always be
            present in the result of the get or list operations. It is optional for
            the update operation.
        type: str
    optimization_info:
        description:
        - Defines various optimizations and optimization parameters applied to this
            library.
        - This field is optional for the create operation. It is optional in the result
            of the get or list operations. It is optional for the update operation.
        - 'Valid attributes are:'
        - ' - C(optimize_remote_publishing) (bool): If set to 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 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).'
        - ''
        - This field is optional for the create operation. If not specified for the
            create, the default is for the library to not be optmized for specific
            use case. It is not used for the update operation. (['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 PublishInfo defines where and how the metadata for this local library
            is accessible. A local library is only published publically if PublishInfo.published
            is true.'
        - ''
        - This field is optional for the create and update operations. If not specified
            during creation, the default is for the library to not be published. If
            not specified during update, the field is left unchanged.
        - 'Valid attributes are:'
        - ' - C(authentication_method) (str): This option 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.'
        - This field is required for the LocalLibrary.create operation. It is optional
            for the LocalLibrary.update operation, and if unset the value will not
            be changed. When the existing authentication method is BASIC and the local
            library is published, the PublishInfo.current-password field is required
            before turning off publishing. This field will always be present in the
            results of the LocalLibrary.get operation. (['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 SubscriptionInfo.subscription-url property
            when creating a subscribed library.'
        - ''
        - This field is not used for the create operation. It will always be present
            in the result of the get or list operations. It is not used for the update
            operation. (['present'])
        - ' - C(user_name) (str): The username to require for authentication.'
        - This field is optional for the LocalLibrary.create and LocalLibrary.update
            operations. When the authentication method is NONE, the username can be
            left unset. When the authentication method is BASIC, the username is ignored
            in the current release. It defaults to "vcsp". It is preferable to leave
            this unset. If specified, it must be set to "vcsp". (['present'])
        - ' - C(password) (str): The new password to require for authentication.'
        - This field is optional for the LocalLibrary.create operation. When the authentication
            method is NONE, the password can be left unset. When the authentication
            method is BASIC, the password should be a non-empty string. This field
            is optional for the LocalLibrary.update operation. Leaving it unset during
            update indicates that the password is not changed. When the password is
            changed, the PublishInfo.current-password field is required. This field
            is not used for the LocalLibrary.get operation. (['present'])
        - ' - C(current_password) (str): The current password to verify. This field
            is available starting in vSphere 6.7.'
        - This field is unused for the LocalLibrary.create operation. This field is
            optional for the LocalLibrary.update operation. When the existing authentication
            method is NONE, the current password can be left unset. When the existing
            authentication method is BASIC, the current password is verified before
            applying the new PublishInfo.password, turning off authentication, or
            unpublishing the library. This field is not used for the LocalLibrary.get
            operation. (['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 SubscriptionInfo.subscription-url.
            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.'
        - ''
        - This field is optional for the create operation. It will always be present
            in the result of the get or list operations. It is optional for the update
            operation. (['present'])
        type: dict
    security_policy_id:
        description:
        - 'Represents the security policy applied to this library. '
        - ' Setting the field will make the library secure. This field is ignored
            in update operation if LibraryModel.unset-security-policy-id is set to
            true.'
        - ''
        - This field is optional for the create and update operations. If not set
            in create operation, the library will be insecure. If not specified in
            update operation, the field is left unchanged.
        - '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.content_library_info). '
        type: str
    server_guid:
        description:
        - The unique identifier of the vCenter server where the library exists.
        - This field is optional for the create operation. It will always be present
            in the result of the get or list operations. It is not used for the update
            operation.
        - '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). '
        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 StorageBacking 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.'
        - ''
        - This field must be provided for the create operation. It will always be
            present in the result of the get or list operations. It is not used for
            the update operation.
        - 'Valid attributes are:'
        - ' - C(type) (str): This option specifies the type of the StorageBacking.
            ([''present''])'
        - '   - Accepted values:'
        - '     - DATASTORE'
        - '     - OTHER'
        - ' - C(datastore_id) (str): Identifier of the datastore used to store the
            content in the library.'
        - This field is optional and it is only relevant when the value of StorageBacking.type
            is 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).
            (['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 '
        - ''
        - '   - nfs://server/path?version=4 (for vCenter Server Appliance only) -
            Specifies an NFS Version 4 server.'
        - '   - nfs://server/path (for vCenter Server Appliance only) - Specifies
            an NFS Version 3 server. The nfs://server:/path format is also supported.'
        - '   - smb://server/path - Specifies an SMB server or Windows share.'
        - '  '
        - ' vSphere 6.0 Update 1 '
        - ''
        - '   - nfs://server:/path (for vCenter Server Appliance only)'
        - '   - file://unc-server/path (for vCenter Server for Windows only)'
        - '   - 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.'
        - '  '
        - ' vSphere 6.0 '
        - ''
        - '   - nfs://server:/path (for vCenter Server Appliance only)'
        - '   - file://unc-server/path (for vCenter Server for Windows only)'
        - '   - file:///path - Local file URIs are supported but strongly discouraged
            because it may interfere with the performance of vCenter Server.'
        - ' '
        - This field is optional and it is only relevant when the value of StorageBacking.type
            is OTHER. (['present'])
        elements: dict
        type: list
    subscription_info:
        description:
        - 'Defines the subscription behavior for this Library. '
        - ' The SubscriptionInfo 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
            SubscriptionInfo.automatic-sync-enabled to false will halt subscription
            but will not remove existing cached data.'
        - ''
        - This field is optional for the create and update operations. If not specified
            during creation, a default will be created without an active subscription.
            If not specified during update, the field is left unchanged.
        - '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 ConfigurationModel.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 SubscribedLibrary.sync or SubscribedItem.sync. In
            other words, manual synchronization is still available even when automatic
            synchronization is disabled.'
        - This field must be provided for the create operation. It will always be
            present in the result of the get or list operations. It is optional for
            the update operation. (['present', 'probe'])
        - ' - C(on_demand) (bool): Indicates whether a library item''s content will
            be synchronized only on demand. '
        - ' If this is set to 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 SubscribedItem.sync call with forceSyncContent set to true.
            Once content has been synchronized, the content can removed with the SubscribedItem.evict
            call. '
        - ''
        - ' If this value is set to false, all content will be synchronized in advance.'
        - ''
        - This field must be provided for the create operation. It will always be
            present in the result of the get or list operations. It is optional for
            the update operation. (['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.'
        - ''
        - This field is optional for the create operation. It will not be present
            in the result of the get or list operations. It is optional for the update
            operation. (['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 unset. The specified sslThumbprint will not be checked for SSL
            certificate validation if {SubscriptionInfo#sslCertificate} is also set.'
        - ''
        - This field is optional for the create operation. It will not be present
            in the result of the get or list operations. It is optional for the update
            operation. (['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 PublishInfo.publish-url of the published library (for
            example, https://server/path/lib.json). '
        - ''
        - ' If the source content comes from a published library with PublishInfo.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 '
        - ''
        - '   - ds:///vmfs/volumes/{uuid}/mylibrary/lib.json (for datastore)'
        - '   - nfs://server/path/mylibrary/lib.json (for NFSv3 server on vCenter
            Server Appliance)'
        - '   - nfs://server/path/mylibrary/lib.json?version=4 (for NFSv4 server on
            vCenter Server Appliance) '
        - '   - smb://server/path/mylibrary/lib.json (for SMB server)'
        - '  '
        - ' vSphere 6.0 '
        - ''
        - '   - file://server/mylibrary/lib.json (for UNC server on vCenter Server
            for Windows)'
        - '   - file:///path/mylibrary/lib.json (for local file system)'
        - '  '
        - ' 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 StorageBacking.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.'
        - ''
        - This field must be provided for the create operation. It will always be
            present in the result of the get or list operations. It is optional for
            the update operation. (['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.'
        - ''
        - This field is optional for the create operation. It is optional in the result
            of the get or list operations. It is optional for the update operation.
            (['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.'
        - This field is optional for the create operation. It is optional in the result
            of the get or list operations. It is optional for the update operation.
            (['present', 'probe'])
        - '   - Accepted keys:'
        - '     - source_library (string): Identifier of the published library.'
        - This field must be provided for the create operation. It will always be
            present in the result of the get or list operations. It is optional for
            the update operation.
        - '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.content_library_info). '
        - '     - subscription (string): Identifier of the subscription associated
            with the subscribed library.'
        - This field must be provided for the create operation. It will always be
            present in the result of the get or list operations. It is optional for
            the update operation.
        - '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.content_library_subscriptions_info). '
        type: dict
    type:
        choices:
        - LOCAL
        - SUBSCRIBED
        description:
        - 'The I(library_type) enumerated type defines the type of a LibraryModel. '
        - ' The type of a library can be used to determine which additional services
            can be performed with a library.'
        type: str
    unset_security_policy_id:
        description:
        - 'This represents the intent of the change to LibraryModel.security-policy-id
            in update operation. '
        - ' If this field is set to true, any security policy applied to the library
            will be removed. If this field is set to false, any security policy applied
            to library will be changed to the value specified in LibraryModel.security-policy-id,
            if any.'
        - ''
        - This field is optional for the update operation. If unset, any existing
            security policy will be changed to the value specified in LibraryModel.security-policy-id,
            if any.
        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 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
    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.'
        - ''
        - This field is not used for the create operation. It will always be present
            in the result of a get or list operation. It is optional for the update
            operation. Leaving it unset during update indicates that you do not need
            to detect concurrent updates.
        type: str
author:
- Ansible Cloud Team (@ansible-collections)
version_added: 2.0.0
requirements:
- vSphere 7.0.3 or greater
- python >= 3.6
- aiohttp
notes:
- Tested on vSphere 7.0.3
"""

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: 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-11-23T20:06:05.189Z'
      description: ''
      id: 8b4e355e-a463-44f1-9b04-d0786a49cc7d
      last_modified_time: '2022-11-23T20:06:05.189Z'
      last_sync_time: '2022-11-23T20:06:07.717Z'
      name: sub_lib
      server_guid: 52fb0b5e-ffc3-465b-bf4f-e4e6d5423cf5
      storage_backings:
      - datastore_id: datastore-1065
        type: DATASTORE
      subscription_info:
        authentication_method: NONE
        automatic_sync_enabled: 0
        on_demand: 1
        subscription_url: https://vcenter.test:443/cls/vcsp/lib/a66d5c73-57f8-4a3a-9361-292a55f68516/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: 8b4e355e-a463-44f1-9b04-d0786a49cc7d
        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: /tmp/vmware_rest.log
        vcenter_username: administrator@vsphere.local
        vcenter_validate_certs: 0
        version: null
    item:
      creation_time: '2022-11-23T20:06:05.189Z'
      description: ''
      id: 8b4e355e-a463-44f1-9b04-d0786a49cc7d
      last_modified_time: '2022-11-23T20:06:05.189Z'
      last_sync_time: '2022-11-23T20:06:07.717Z'
      name: sub_lib
      server_guid: 52fb0b5e-ffc3-465b-bf4f-e4e6d5423cf5
      storage_backings:
      - datastore_id: datastore-1065
        type: DATASTORE
      subscription_info:
        authentication_method: NONE
        automatic_sync_enabled: 0
        on_demand: 1
        subscription_url: https://vcenter.test:443/cls/vcsp/lib/a66d5c73-57f8-4a3a-9361-292a55f68516/lib.json
      type: SUBSCRIBED
      version: '4'
    value: {}
  type: list
"""


# This structure describes the format of the data expected by the end-points
PAYLOAD_FORMAT = {
    "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",
            "security_policy_id": "security_policy_id",
            "server_guid": "server_guid",
            "storage_backings": "storage_backings",
            "subscription_info": "subscription_info",
            "type": "type",
            "unset_security_policy_id": "unset_security_policy_id",
            "version": "version",
        },
        "path": {},
    },
    "delete": {"query": {}, "body": {}, "path": {"library_id": "library_id"}},
    "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",
            "security_policy_id": "security_policy_id",
            "server_guid": "server_guid",
            "storage_backings": "storage_backings",
            "subscription_info": "subscription_info",
            "type": "type",
            "unset_security_policy_id": "unset_security_policy_id",
            "version": "version",
        },
        "path": {"library_id": "library_id"},
    },
    "probe": {
        "query": {},
        "body": {"subscription_info": "subscription_info"},
        "path": {},
    },
    "evict": {"query": {}, "body": {}, "path": {"library_id": "library_id"}},
}  # 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["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["security_policy_id"] = {"type": "str"}
    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["unset_security_policy_id"] = {"type": "bool"}
    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.new_event_loop()
    try:
        asyncio.set_event_loop(current_loop)
        current_loop.run_until_complete(main())
    finally:
        current_loop.close()
