diff --git a/plugins/modules/azure_rm_recoveryservicesvault.py b/plugins/modules/azure_rm_recoveryservicesvault.py new file mode 100644 index 000000000..53e200c19 --- /dev/null +++ b/plugins/modules/azure_rm_recoveryservicesvault.py @@ -0,0 +1,319 @@ +#!/usr/bin/python +# +# Copyright (c) 2020 Suyeb Ansari (@suyeb786) +# +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], + 'supported_by': 'community'} + +DOCUMENTATION = \ + ''' +--- +module: azure_rm_recoveryservicesvault +version_added: '1.1.0' +short_description: Create and Delete Azure Recovery Services vault +description: + - Create or Delete Azure Recovery Services vault. +options: + resource_group: + description: + - The name of the resource group. + required: true + type: str + name: + description: + - The name of the Azure Recovery Service Vault. + required: true + type: str + location: + description: + - Azure Resource location. + required: true + type: str + state: + description: + - Assert the state of the protection item. + - Use C(present) for Creating Azure Recovery Service Vault. + - Use C(absent) for Deleting Azure Recovery Service Vault. + default: present + type: str + choices: + - present + - absent +extends_documentation_fragment: + - azure.azcollection.azure + - azure.azcollection.azure_tags +author: + - Suyeb Ansari (@suyeb786) +''' + +EXAMPLES = ''' + - name: Create/Update Azure Recovery Service vault + azure_rm_recoveryservicesvault: + resource_group: 'myResourceGroup' + name: 'testVault' + location: 'westeurope' + state: 'present' + - name: Delete Recovery Service Vault + azure_rm_recoveryservicesvault: + resource_group: 'myResourceGroup' + name: 'testVault' + location: 'westeurope' + state: 'absent' +''' + +RETURN = ''' +response: + description: + - The response about the current state of the recovery services vault. + returned: always + type: complex + contains: + etag: + description: + - A unique read-only string that changes whenever the resource create. + returned: always + type: str + sample: "datetime'2020-09-16T02%3A44%3A27.834293Z'" + id: + description: + - Resource ID. + returned: always + type: str + sample: "/subscriptions/xxxxxxx/resourceGroups/resourcegroup_name/ \ + providers/Microsoft.RecoveryServices/vaults/rev_name" + location: + description: + - The location of the resource. + returned: always + type: str + sample: "eastus" + name: + description: + - Name of the recovery services vault name. + returned: always + type: str + sample: revault_name + properties: + description: + - The recovery service vault properties. + returned: always + type: dict + sample: { + "privateEndpointStateForBackup": "None", + "privateEndpointStateForSiteRecovery": "None", + "provisioningState": "Succeeded" + } + sku: + description: + - The sku type of the recovery service vault. + returned: always + type: str + sample: Standard + type: + description: + - The type of the recovery service vault. + returned: always + type: str + sample: "Microsoft.RecoveryServices/vaults" +''' + +from ansible_collections.azure.azcollection.plugins.module_utils.azure_rm_common_rest import GenericRestClient +from ansible_collections.azure.azcollection.plugins.module_utils.azure_rm_common_ext import AzureRMModuleBaseExt +import re +import json +import time + +try: + from msrestazure.azure_exceptions import CloudError +except ImportError: + # This is handled in azure_rm_common + pass + + +class AzureRMRecoveryServicesVault(AzureRMModuleBaseExt): + def __init__(self): + self.module_arg_spec = dict( + resource_group=dict( + type='str', + required=True + ), + name=dict( + type='str', + required=True + ), + location=dict( + type='str', + required=True + ), + state=dict( + type='str', + default='present', + choices=['present', 'absent'] + ) + ) + + self.resource_group = None + self.name = None + self.location = None + self.state = None + + self.results = dict(changed=False) + self.mgmt_client = None + self.url = None + self.status_code = [200, 201, 202, 204] + + self.body = {} + self.query_parameters = {} + self.query_parameters['api-version'] = None + self.header_parameters = {} + self.header_parameters['Content-Type'] = 'application/json; charset=utf-8' + + super(AzureRMRecoveryServicesVault, self).__init__(derived_arg_spec=self.module_arg_spec, + supports_check_mode=True, + supports_tags=True + ) + + def get_api_version(self): + return '2016-06-01' + + def get_url(self): + if self.state == 'present' or self.state == 'absent': + return '/subscriptions/' \ + + self.subscription_id \ + + '/resourceGroups/' \ + + self.resource_group \ + + '/providers/Microsoft.RecoveryServices' \ + + '/vaults' + '/' \ + + self.name + + def get_body(self): + if self.state == 'present': + return { + "properties": {}, + "sku": { + "name": "Standard" + }, + "location": self.location + } + else: + return {} + + def exec_module(self, **kwargs): + for key in list(self.module_arg_spec.keys()): + if hasattr(self, key): + setattr(self, key, kwargs[key]) + elif kwargs[key] is not None: + self.body[key] = kwargs[key] + + self.inflate_parameters(self.module_arg_spec, self.body, 0) + + self.query_parameters['api-version'] = self.get_api_version() + self.url = self.get_url() + self.body = self.get_body() + old_response = None + response = None + + self.mgmt_client = self.get_mgmt_svc_client(GenericRestClient, + base_url=self._cloud_environment.endpoints.resource_manager) + + old_response = self.get_resource() + + changed = False + if self.state == 'present': + if old_response is False: + changed = True + response = self.create_recovery_service_vault() + else: + changed = False + response = old_response + if self.state == 'absent': + changed = True + response = self.delete_recovery_service_vault() + + self.results['response'] = response + self.results['changed'] = changed + + return self.results + + def create_recovery_service_vault(self): + # self.log('Creating Recovery Service Vault Name {0}'.format(self.)) + try: + response = self.mgmt_client.query( + self.url, + 'PUT', + self.query_parameters, + self.header_parameters, + self.body, + self.status_code, + 600, + 30, + ) + except CloudError as e: + self.log('Error in creating Azure Recovery Service Vault.') + self.fail('Error in creating Azure Recovery Service Vault {0}'.format(str(e))) + + try: + response = json.loads(response.text) + except Exception: + response = {'text': response.text} + + return response + + def delete_recovery_service_vault(self): + # self.log('Deleting Recovery Service Vault {0}'.format(self.)) + try: + response = self.mgmt_client.query( + self.url, + 'DELETE', + self.query_parameters, + self.header_parameters, + None, + self.status_code, + 600, + 30, + ) + except CloudError as e: + self.log('Error attempting to delete Azure Recovery Service Vault.') + self.fail('Error while deleting Azure Recovery Service Vault: {0}'.format(str(e))) + + try: + response = json.loads(response.text) + except Exception: + response = {'text': response.text} + return response + + def get_resource(self): + # self.log('Get Recovery Service Vault Name {0}'.format(self.)) + found = False + try: + response = self.mgmt_client.query( + self.url, + 'GET', + self.query_parameters, + self.header_parameters, + None, + self.status_code, + 600, + 30, + ) + found = True + except CloudError as e: + self.log('Recovery Service Vault Does not exist.') + if found is True: + response = json.loads(response.text) + return response + else: + return False + + +def main(): + AzureRMRecoveryServicesVault() + + +if __name__ == '__main__': + main() diff --git a/plugins/modules/azure_rm_recoveryservicesvault_info.py b/plugins/modules/azure_rm_recoveryservicesvault_info.py new file mode 100644 index 000000000..de2793952 --- /dev/null +++ b/plugins/modules/azure_rm_recoveryservicesvault_info.py @@ -0,0 +1,214 @@ +#!/usr/bin/python +# +# Copyright (c) 2020 Suyeb Ansari (@suyeb786) +# +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], + 'supported_by': 'community'} + +DOCUMENTATION = \ + ''' +--- +module: azure_rm_recoveryservicesvault_info +version_added: '1.1.0' +short_description: Get Azure Recovery Services vault Details +description: + - Get Azure Recovery Services vault Details. +options: + resource_group: + description: + - The name of the resource group. + required: true + type: str + name: + description: + - The name of the Azure Recovery Service Vault. + required: true + type: str +extends_documentation_fragment: + - azure.azcollection.azure + - azure.azcollection.azure_tags +author: + - Suyeb Ansari (@suyeb786) +''' + +EXAMPLES = ''' + - name: Get Azure Recovery Services Vault Details. + azure_rm_recoveryservicesvault_info: + resource_group: 'myResourceGroup' + name: 'testVault' +''' + +RETURN = ''' +response: + description: + - The response about the current state of the recovery services vault. + returned: always + type: complex + contains: + etag: + description: + - A unique read-only string that changes whenever the resource create. + returned: always + type: str + sample: "datetime'2020-09-16T02%3A44%3A27.834293Z'" + id: + description: + - Resource ID. + returned: always + type: str + sample: "/subscriptions/xxxxxxx/resourceGroups/resourcegroup_name/ \ + providers/Microsoft.RecoveryServices/vaults/rev_name" + location: + description: + - The location of the resource. + returned: always + type: str + sample: "eastus" + name: + description: + - Name of the recovery services vault name. + returned: always + type: str + sample: revault_name + properties: + description: + - The recovery service vault properties. + returned: always + type: dict + sample: { + "privateEndpointStateForBackup": "None", + "privateEndpointStateForSiteRecovery": "None", + "provisioningState": "Succeeded" + } + sku: + description: + - The sku type of the recovery service vault. + returned: always + type: str + sample: Standard + type: + description: + - The type of the recovery service vault. + returned: always + type: str + sample: "Microsoft.RecoveryServices/vaults" +''' + +from ansible_collections.azure.azcollection.plugins.module_utils.azure_rm_common_rest import GenericRestClient +from ansible_collections.azure.azcollection.plugins.module_utils.azure_rm_common_ext import AzureRMModuleBaseExt +import re +import json +import time + +try: + from msrestazure.azure_exceptions import CloudError +except ImportError: + # This is handled in azure_rm_common + pass + + +class AzureRMRecoveryServicesVaultInfo(AzureRMModuleBaseExt): + def __init__(self): + self.module_arg_spec = dict( + resource_group=dict( + type='str', + required=True + ), + name=dict( + type='str', + required=True + ) + ) + + self.resource_group = None + self.name = None + + self.body = {} + self.results = dict(changed=False) + self.mgmt_client = None + self.url = None + self.status_code = [200, 201, 202, 204] + + self.query_parameters = {} + self.query_parameters['api-version'] = None + self.header_parameters = {} + self.header_parameters['Content-Type'] = 'application/json; charset=utf-8' + + super(AzureRMRecoveryServicesVaultInfo, self).__init__(derived_arg_spec=self.module_arg_spec, + supports_check_mode=True, + supports_tags=True + ) + + def get_api_version(self): + return '2016-06-01' + + def get_url(self): + return '/subscriptions/' \ + + self.subscription_id \ + + '/resourceGroups/' \ + + self.resource_group \ + + '/providers/Microsoft.RecoveryServices' \ + + '/vaults' + '/' \ + + self.name + + def exec_module(self, **kwargs): + for key in list(self.module_arg_spec.keys()): + if hasattr(self, key): + setattr(self, key, kwargs[key]) + elif kwargs[key] is not None: + self.body[key] = kwargs[key] + + self.inflate_parameters(self.module_arg_spec, self.body, 0) + + self.query_parameters['api-version'] = self.get_api_version() + self.url = self.get_url() + old_response = None + response = None + + self.mgmt_client = self.get_mgmt_svc_client(GenericRestClient, + base_url=self._cloud_environment.endpoints.resource_manager) + + changed = True + response = self.get_recovery_service_vault_info() + + self.results['response'] = response + self.results['changed'] = changed + + return self.results + + def get_recovery_service_vault_info(self): + # self.log('Get Recovery Service Vault Details {0}'.format(self.)) + try: + response = self.mgmt_client.query( + self.url, + 'GET', + self.query_parameters, + self.header_parameters, + None, + self.status_code, + 600, + 30, + ) + except CloudError as e: + self.log('Error in fetching Azure Recovery Service Vault Details.') + self.fail('Error in fetching Azure Recovery Service Vault Details {0}'.format(str(e))) + + try: + response = json.loads(response.text) + except Exception: + response = {'text': response.text} + + return response + + +def main(): + AzureRMRecoveryServicesVaultInfo() + + +if __name__ == '__main__': + main() diff --git a/pr-pipelines.yml b/pr-pipelines.yml index ef48d112c..4ca85f820 100644 --- a/pr-pipelines.yml +++ b/pr-pipelines.yml @@ -73,6 +73,7 @@ parameters: - "azure_rm_virtualnetworkgateway" - "azure_rm_virtualnetworkeepring" - "azure_rm_backupazurevm" + - "azure_rm_recoveryservicesvault" - "azure_rm_webapp" - "azure_rm_workspace" - "inventory_azure" diff --git a/tests/integration/targets/azure_rm_recoveryservicesvault/aliases b/tests/integration/targets/azure_rm_recoveryservicesvault/aliases new file mode 100644 index 000000000..cc941b59c --- /dev/null +++ b/tests/integration/targets/azure_rm_recoveryservicesvault/aliases @@ -0,0 +1,3 @@ +cloud/azure +shippable/azure/group12 +destructive diff --git a/tests/integration/targets/azure_rm_recoveryservicesvault/meta/main.yml b/tests/integration/targets/azure_rm_recoveryservicesvault/meta/main.yml new file mode 100644 index 000000000..95e1952f9 --- /dev/null +++ b/tests/integration/targets/azure_rm_recoveryservicesvault/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: + - setup_azure diff --git a/tests/integration/targets/azure_rm_recoveryservicesvault/tasks/main.yml b/tests/integration/targets/azure_rm_recoveryservicesvault/tasks/main.yml new file mode 100644 index 000000000..fc92da931 --- /dev/null +++ b/tests/integration/targets/azure_rm_recoveryservicesvault/tasks/main.yml @@ -0,0 +1,55 @@ +- name: Fix resource prefix + set_fact: + name: "revault{{ resource_group | hash('md5') | truncate(22, True, '') }}" + location: "eastus" + +- name: Create Azure Recovery Service vault + azure_rm_recoveryservicesvault: + resource_group: "{{ resource_group }}" + name: "{{ name }}" + location: "{{ location }}" + state: "present" + register: output + +- name: Assert that output has changed + assert: + that: + - output.changed + +- name: Create Azure Recovery Service vault (idempotent) + azure_rm_recoveryservicesvault: + resource_group: "{{ resource_group }}" + name: "{{ name }}" + location: "{{ location }}" + state: "present" + register: output + +- name: Assert that output has no changed + assert: + that: + - not output.changed + +- name: Get Azure Recovery Service Vault Details + azure_rm_recoveryservicesvault_info: + resource_group: "{{ resource_group }}" + name: "{{ name }}" + register: output + +- name: Assert that output has changed + assert: + that: + - output.response.id != None + - output.response.name != None + +- name: Delete Azure Recovery Service vault + azure_rm_recoveryservicesvault: + resource_group: "{{ resource_group }}" + name: "{{ name }}" + location: "{{ location }}" + state: "absent" + register: output + +- name: Assert that output has changed + assert: + that: + - output.changed diff --git a/tests/sanity/ignore-2.10.txt b/tests/sanity/ignore-2.10.txt index f6d4126c5..30930f8c5 100644 --- a/tests/sanity/ignore-2.10.txt +++ b/tests/sanity/ignore-2.10.txt @@ -711,5 +711,9 @@ plugins/modules/azure_rm_backupazurevm.py validate-modules:required_if-requireme plugins/modules/azure_rm_backupazurevm.py validate-modules:required_if-unknown-key plugins/modules/azure_rm_backupazurevm_info.py validate-modules:required_if-requirements-unknown plugins/modules/azure_rm_backupazurevm_info.py validate-modules:required_if-unknown-key +plugins/modules/azure_rm_recoveryservicesvault.py validate-modules:required_if-requirements-unknown +plugins/modules/azure_rm_recoveryservicesvault.py validate-modules:required_if-unknown-key +plugins/modules/azure_rm_recoveryservicesvault_info.py validate-modules:required_if-requirements-unknown +plugins/modules/azure_rm_recoveryservicesvault_info.py validate-modules:required_if-unknown-key tests/utils/shippable/check_matrix.py replace-urlopen tests/utils/shippable/timing.py shebang diff --git a/tests/sanity/ignore-2.11.txt b/tests/sanity/ignore-2.11.txt index 89002049d..6f8dac3f5 100644 --- a/tests/sanity/ignore-2.11.txt +++ b/tests/sanity/ignore-2.11.txt @@ -711,5 +711,9 @@ plugins/modules/azure_rm_backupazurevm.py validate-modules:required_if-requireme plugins/modules/azure_rm_backupazurevm.py validate-modules:required_if-unknown-key plugins/modules/azure_rm_backupazurevm_info.py validate-modules:required_if-requirements-unknown plugins/modules/azure_rm_backupazurevm_info.py validate-modules:required_if-unknown-key +plugins/modules/azure_rm_recoveryservicesvault.py validate-modules:required_if-requirements-unknown +plugins/modules/azure_rm_recoveryservicesvault.py validate-modules:required_if-unknown-key +plugins/modules/azure_rm_recoveryservicesvault_info.py validate-modules:required_if-requirements-unknown +plugins/modules/azure_rm_recoveryservicesvault_info.py validate-modules:required_if-unknown-key tests/utils/shippable/check_matrix.py replace-urlopen tests/utils/shippable/timing.py shebang