summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYunge Zhu <37337818+yungezz@users.noreply.github.com>2018-09-26 17:10:01 -0700
committerJordan Borean <jborean93@gmail.com>2018-09-27 10:10:01 +1000
commit69594c5370cf2be67cf03eaf4d067303e8819a12 (patch)
tree9f7ac76d6e9a6a9269396bfe138868b2965a27d0
parent2fd18c77aef019a34b79b12a58fcbe40272cda8d (diff)
downloadansible-69594c5370cf2be67cf03eaf4d067303e8819a12.tar.gz
add azure_rm_cdnprofile and azure_rm_cdnprofile_facts (#45097)
* add cdn profile with facts * fix merge issue * fix version * fix lint * move cdn client out of azure_rm_common * fix lint * fix helper * fix code bug * fix bug * fix import * fix typo * fix test
-rw-r--r--lib/ansible/modules/cloud/azure/azure_rm_cdnprofile.py303
-rw-r--r--lib/ansible/modules/cloud/azure/azure_rm_cdnprofile_facts.py264
-rw-r--r--packaging/requirements/requirements-azure.txt1
-rw-r--r--test/integration/targets/azure_rm_cdnprofile/aliases4
-rw-r--r--test/integration/targets/azure_rm_cdnprofile/meta/main.yml2
-rw-r--r--test/integration/targets/azure_rm_cdnprofile/tasks/main.yml132
-rw-r--r--test/runner/requirements/integration.cloud.azure.txt1
7 files changed, 707 insertions, 0 deletions
diff --git a/lib/ansible/modules/cloud/azure/azure_rm_cdnprofile.py b/lib/ansible/modules/cloud/azure/azure_rm_cdnprofile.py
new file mode 100644
index 0000000000..5c324ace83
--- /dev/null
+++ b/lib/ansible/modules/cloud/azure/azure_rm_cdnprofile.py
@@ -0,0 +1,303 @@
+#!/usr/bin/python
+#
+# Copyright (c) 2018 Hai Cao, <t-haicao@microsoft.com>, Yunge Zhu <yungez@microsoft.com>
+#
+# 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_cdnprofile
+version_added: "2.8"
+short_description: Manage a Azure CDN profile.
+description:
+ - Create, update and delete a Azure CDN profile.
+
+options:
+ resource_group:
+ description:
+ - Name of a resource group where the CDN profile exists or will be created.
+ required: true
+ name:
+ description:
+ - Name of the CDN profile.
+ required: true
+ location:
+ description:
+ - Valid azure location. Defaults to location of the resource group.
+ sku:
+ description:
+ - The pricing tier, defines a CDN provider, feature list and rate of the CDN profile.
+ - Detailed pricing can be find at U(https://azure.microsoft.com/en-us/pricing/details/cdn/)
+ choices:
+ - standard_verizon
+ - premium_verizon
+ - custom_verizon
+ - standard_akamai
+ - standard_chinacdn
+ state:
+ description:
+ - Assert the state of the CDN profile. Use C(present) to create or update a CDN profile and C(absent) to delete it.
+ default: present
+ choices:
+ - absent
+ - present
+
+extends_documentation_fragment:
+ - azure
+ - azure_tags
+
+author:
+ - "Hai Cao <t-haicao@microsoft.com>"
+ - "Yunge Zhu <yungez@microsoft.com>"
+'''
+
+EXAMPLES = '''
+ - name: Create a CDN profile
+ azure_rm_cdnprofile:
+ resource_group: Testing
+ name: cdntest
+ sku: Standard_Akamai
+ tags:
+ testing: testing
+
+ - name: Delete the CDN profile
+ azure_rm_cdnprofile:
+ resource_group: Testing
+ name: cdntest
+ state: absent
+'''
+RETURN = '''
+id:
+ description: Current state of the CDN profile
+ returned: always
+ type: dict
+ example:
+ id: /subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourcegroups/cdntest/providers/Microsoft.Cdn/profiles/cdntest
+'''
+from ansible.module_utils.azure_rm_common import AzureRMModuleBase
+
+try:
+ from azure.mgmt.cdn.models import Profile, Sku, ErrorResponseException
+ from azure.mgmt.cdn import CdnManagementClient
+except ImportError:
+ # This is handled in azure_rm_common
+ pass
+
+
+def cdnprofile_to_dict(cdnprofile):
+ return dict(
+ id=cdnprofile.id,
+ name=cdnprofile.name,
+ type=cdnprofile.type,
+ location=cdnprofile.location,
+ sku=cdnprofile.sku.name,
+ resource_state=cdnprofile.resource_state,
+ provisioning_state=cdnprofile.provisioning_state,
+ tags=cdnprofile.tags
+ )
+
+
+class AzureRMCdnprofile(AzureRMModuleBase):
+
+ 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'
+ ),
+ state=dict(
+ type='str',
+ default='present',
+ choices=['present', 'absent']
+ ),
+ sku=dict(
+ type='str',
+ choices=['standard_verizon', 'premium_verizon', 'custom_verizon', 'standard_akamai', 'standard_chinacdn']
+ )
+ )
+
+ self.resource_group = None
+ self.name = None
+ self.location = None
+ self.state = None
+ self.tags = None
+ self.sku = None
+
+ self.cdn_client = None
+
+ required_if = [
+ ('state', 'present', ['sku'])
+ ]
+
+ self.results = dict(changed=False)
+
+ super(AzureRMCdnprofile, self).__init__(derived_arg_spec=self.module_arg_spec,
+ supports_check_mode=True,
+ supports_tags=True,
+ required_if=required_if)
+
+ def exec_module(self, **kwargs):
+ """Main module execution method"""
+
+ for key in list(self.module_arg_spec.keys()) + ['tags']:
+ setattr(self, key, kwargs[key])
+
+ self.cdn_client = self.get_cdn_client()
+
+ to_be_updated = False
+
+ resource_group = self.get_resource_group(self.resource_group)
+ if not self.location:
+ self.location = resource_group.location
+
+ response = self.get_cdnprofile()
+
+ if self.state == 'present':
+
+ if not response:
+ self.log("Need to create the CDN profile")
+
+ if not self.check_mode:
+ new_response = self.create_cdnprofile()
+ self.results['id'] = new_response['id']
+
+ self.results['changed'] = True
+
+ else:
+ self.log('Results : {0}'.format(response))
+ update_tags, response['tags'] = self.update_tags(response['tags'])
+
+ if response['provisioning_state'] == "Succeeded":
+ if update_tags:
+ to_be_updated = True
+
+ if to_be_updated:
+ self.log("Need to update the CDN profile")
+
+ if not self.check_mode:
+ new_response = self.update_cdnprofile()
+ self.results['id'] = new_response['id']
+
+ self.results['changed'] = True
+
+ elif self.state == 'absent':
+ if not response:
+ self.fail("CDN profile {0} not exists.".format(self.name))
+ else:
+ self.log("Need to delete the CDN profile")
+ self.results['changed'] = True
+
+ if not self.check_mode:
+ self.delete_cdnprofile()
+ self.results['id'] = response['id']
+
+ return self.results
+
+ def create_cdnprofile(self):
+ '''
+ Creates a Azure CDN profile.
+
+ :return: deserialized Azure CDN profile instance state dictionary
+ '''
+ self.log("Creating the Azure CDN profile instance {0}".format(self.name))
+
+ parameters = Profile(
+ location=self.location,
+ sku=Sku(name=self.sku),
+ tags=self.tags
+ )
+
+ import uuid
+ xid = str(uuid.uuid1())
+
+ try:
+ poller = self.cdn_client.profiles.create(self.resource_group,
+ self.name,
+ parameters,
+ custom_headers={'x-ms-client-request-id': xid}
+ )
+ response = self.get_poller_result(poller)
+ return cdnprofile_to_dict(response)
+ except ErrorResponseException as exc:
+ self.log('Error attempting to create Azure CDN profile instance.')
+ self.fail("Error creating Azure CDN profile instance: {0}.\n Request id: {1}".format(exc.message, xid))
+
+ def update_cdnprofile(self):
+ '''
+ Updates a Azure CDN profile.
+
+ :return: deserialized Azure CDN profile instance state dictionary
+ '''
+ self.log("Updating the Azure CDN profile instance {0}".format(self.name))
+
+ try:
+ poller = self.cdn_client.profiles.update(self.resource_group, self.name, self.tags)
+ response = self.get_poller_result(poller)
+ return cdnprofile_to_dict(response)
+ except ErrorResponseException as exc:
+ self.log('Error attempting to update Azure CDN profile instance.')
+ self.fail("Error updating Azure CDN profile instance: {0}".format(exc.message))
+
+ def delete_cdnprofile(self):
+ '''
+ Deletes the specified Azure CDN profile in the specified subscription and resource group.
+
+ :return: True
+ '''
+ self.log("Deleting the CDN profile {0}".format(self.name))
+ try:
+ poller = self.cdn_client.profiles.delete(
+ self.resource_group, self.name)
+ self.get_poller_result(poller)
+ return True
+ except ErrorResponseException as e:
+ self.log('Error attempting to delete the CDN profile.')
+ self.fail("Error deleting the CDN profile: {0}".format(e.message))
+ return False
+
+ def get_cdnprofile(self):
+ '''
+ Gets the properties of the specified CDN profile.
+
+ :return: deserialized CDN profile state dictionary
+ '''
+ self.log(
+ "Checking if the CDN profile {0} is present".format(self.name))
+ try:
+ response = self.cdn_client.profiles.get(self.resource_group, self.name)
+ self.log("Response : {0}".format(response))
+ self.log("CDN profile : {0} found".format(response.name))
+ return cdnprofile_to_dict(response)
+ except ErrorResponseException:
+ self.log('Did not find the CDN profile.')
+ return False
+
+ def get_cdn_client(self):
+ if not self.cdn_client:
+ self.cdn_client = self.get_mgmt_svc_client(CdnManagementClient,
+ base_url=self._cloud_environment.endpoints.resource_manager,
+ api_version='2017-04-02')
+ return self.cdn_client
+
+
+def main():
+ """Main execution"""
+ AzureRMCdnprofile()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/lib/ansible/modules/cloud/azure/azure_rm_cdnprofile_facts.py b/lib/ansible/modules/cloud/azure/azure_rm_cdnprofile_facts.py
new file mode 100644
index 0000000000..13cea61d60
--- /dev/null
+++ b/lib/ansible/modules/cloud/azure/azure_rm_cdnprofile_facts.py
@@ -0,0 +1,264 @@
+#!/usr/bin/python
+#
+# Copyright (c) 2018 Hai Cao, <t-haicao@microsoft.com>, Yunge Zhu <yungez@microsoft.com>
+#
+# 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_cdnprofile_facts
+
+version_added: "2.8"
+
+short_description: Get Azure CDN profile facts
+
+description:
+ - Get facts for a specific Azure CDN profile or all CDN profiles.
+
+options:
+ name:
+ description:
+ - Limit results to a specific CDN profile.
+ resource_group:
+ description:
+ - The resource group to search for the desired CDN profile
+ tags:
+ description:
+ - Limit results by providing a list of tags. Format tags as 'key' or 'key:value'.
+
+extends_documentation_fragment:
+ - azure
+
+author:
+ - "Hai Cao <t-haicao@microsoft.com>"
+ - "Yunge Zhu <yungez@microsoft.com>"
+'''
+
+EXAMPLES = '''
+ - name: Get facts for one CDN profile
+ azure_rm_cdnprofile_facts:
+ name: Testing
+ resource_group: TestRG
+
+ - name: Get facts for all CDN profiles
+ azure_rm_cdnprofile_facts:
+
+ - name: Get facts by tags
+ azure_rm_cdnprofile_facts:
+ tags:
+ - Environment:Test
+'''
+
+RETURN = '''
+cdnprofiles:
+ description: List of CDN profiles.
+ returned: always
+ type: complex
+ contains:
+ resource_group:
+ description:
+ - Name of a resource group where the CDN profile exists.
+ returned: always
+ type: str
+ sample: testGroup
+ name:
+ description:
+ - Name of the CDN profile.
+ returned: always
+ type: str
+ sample: Testing
+ location:
+ description:
+ - Location of the CDN profile.
+ type: str
+ sample: WestUS
+ id:
+ description:
+ - ID of the CDN profile.
+ type: str
+ sample: /subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourcegroups/cdntest/providers/Microsoft.Cdn/profiles/cdntest
+ provisioning_state:
+ description:
+ - Provisioning status of the profile.
+ type: str
+ sample: Succeeded
+ resource_state:
+ description:
+ - Resource status of the profile.
+ type: str
+ sample: Active
+ sku:
+ description:
+ - The pricing tier, defines a CDN provider, feature list and rate of the CDN profile.
+ type: str
+ sample: standard_verizon
+ type:
+ description:
+ - The type of the CDN profile.
+ type: str
+ sample: Microsoft.Cdn/profiles
+ tags:
+ description:
+ - The tags of the CDN profile.
+ type: list
+ sample: [
+ {"foo": "bar"}
+ ]
+'''
+
+from ansible.module_utils.azure_rm_common import AzureRMModuleBase
+
+try:
+ from azure.mgmt.cdn.models import ErrorResponseException
+ from azure.common import AzureHttpError
+ from azure.mgmt.cdn import CdnManagementClient
+except:
+ # handled in azure_rm_common
+ pass
+
+import re
+
+AZURE_OBJECT_CLASS = 'profiles'
+
+
+class AzureRMCdnprofileFacts(AzureRMModuleBase):
+ """Utility class to get Azure CDN profile facts"""
+
+ def __init__(self):
+
+ self.module_args = dict(
+ name=dict(type='str'),
+ resource_group=dict(type='str'),
+ tags=dict(type='list')
+ )
+
+ self.results = dict(
+ changed=False,
+ cdnprofiles=[]
+ )
+
+ self.name = None
+ self.resource_group = None
+ self.tags = None
+ self.cdn_client = None
+
+ super(AzureRMCdnprofileFacts, self).__init__(
+ derived_arg_spec=self.module_args,
+ supports_tags=False,
+ facts_module=True
+ )
+
+ def exec_module(self, **kwargs):
+
+ for key in self.module_args:
+ setattr(self, key, kwargs[key])
+
+ self.cdn_client = self.get_cdn_client()
+
+ if self.name and not self.resource_group:
+ self.fail("Parameter error: resource group required when filtering by name.")
+
+ if self.name:
+ self.results['cdnprofiles'] = self.get_item()
+ elif self.resource_group:
+ self.results['cdnprofiles'] = self.list_resource_group()
+ else:
+ self.results['cdnprofiles'] = self.list_all()
+
+ return self.results
+
+ def get_item(self):
+ """Get a single Azure CDN profile"""
+
+ self.log('Get properties for {0}'.format(self.name))
+
+ item = None
+ result = []
+
+ try:
+ item = self.cdn_client.profiles.get(
+ self.resource_group, self.name)
+ except ErrorResponseException:
+ pass
+
+ if item and self.has_tags(item.tags, self.tags):
+ result = [self.serialize_cdnprofile(item)]
+
+ return result
+
+ def list_resource_group(self):
+ """Get all Azure CDN profiles within a resource group"""
+
+ self.log('List all Azure CDNs within a resource group')
+
+ try:
+ response = self.cdn_client.profiles.list_by_resource_group(
+ self.resource_group)
+ except AzureHttpError as exc:
+ self.fail('Failed to list all items - {0}'.format(str(exc)))
+
+ results = []
+ for item in response:
+ if self.has_tags(item.tags, self.tags):
+ results.append(self.serialize_cdnprofile(item))
+
+ return results
+
+ def list_all(self):
+ """Get all Azure CDN profiles within a subscription"""
+ self.log('List all CDN profiles within a subscription')
+ try:
+ response = self.cdn_client.profiles.list()
+ except Exception as exc:
+ self.fail("Error listing all items - {0}".format(str(exc)))
+
+ results = []
+ for item in response:
+ if self.has_tags(item.tags, self.tags):
+ results.append(self.serialize_cdnprofile(item))
+ return results
+
+ def serialize_cdnprofile(self, cdnprofile):
+ '''
+ Convert a CDN profile object to dict.
+ :param cdn: CDN profile object
+ :return: dict
+ '''
+ result = self.serialize_obj(cdnprofile, AZURE_OBJECT_CLASS)
+
+ new_result = {}
+ new_result['id'] = cdnprofile.id
+ new_result['resource_group'] = re.sub('\\/.*', '', re.sub('.*resourcegroups\\/', '', result['id']))
+ new_result['name'] = cdnprofile.name
+ new_result['type'] = cdnprofile.type
+ new_result['location'] = cdnprofile.location
+ new_result['resource_state'] = cdnprofile.resource_state
+ new_result['sku'] = cdnprofile.sku.name
+ new_result['provisioning_state'] = cdnprofile.provisioning_state
+ new_result['tags'] = cdnprofile.tags
+ return new_result
+
+ def get_cdn_client(self):
+ if not self.cdn_client:
+ self.cdn_client = self.get_mgmt_svc_client(CdnManagementClient,
+ base_url=self._cloud_environment.endpoints.resource_manager,
+ api_version='2017-04-02')
+ return self.cdn_client
+
+
+def main():
+ """Main module execution code path"""
+
+ AzureRMCdnprofileFacts()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/packaging/requirements/requirements-azure.txt b/packaging/requirements/requirements-azure.txt
index 02e37156de..78ef8a48fd 100644
--- a/packaging/requirements/requirements-azure.txt
+++ b/packaging/requirements/requirements-azure.txt
@@ -4,6 +4,7 @@ azure-cli-core==2.0.35
azure-cli-nspkg==3.0.2
azure-common==1.1.11
azure-mgmt-batch==4.1.0
+azure.mgmt.cdn==3.0.0
azure-mgmt-compute==3.0.0
azure-mgmt-containerinstance==0.4.0
azure-mgmt-containerregistry==2.0.0
diff --git a/test/integration/targets/azure_rm_cdnprofile/aliases b/test/integration/targets/azure_rm_cdnprofile/aliases
new file mode 100644
index 0000000000..13fc9b5873
--- /dev/null
+++ b/test/integration/targets/azure_rm_cdnprofile/aliases
@@ -0,0 +1,4 @@
+cloud/azure
+shippable/azure/group4
+destructive
+azure_rm_cdnprofile_facts \ No newline at end of file
diff --git a/test/integration/targets/azure_rm_cdnprofile/meta/main.yml b/test/integration/targets/azure_rm_cdnprofile/meta/main.yml
new file mode 100644
index 0000000000..95e1952f98
--- /dev/null
+++ b/test/integration/targets/azure_rm_cdnprofile/meta/main.yml
@@ -0,0 +1,2 @@
+dependencies:
+ - setup_azure
diff --git a/test/integration/targets/azure_rm_cdnprofile/tasks/main.yml b/test/integration/targets/azure_rm_cdnprofile/tasks/main.yml
new file mode 100644
index 0000000000..1e79235dce
--- /dev/null
+++ b/test/integration/targets/azure_rm_cdnprofile/tasks/main.yml
@@ -0,0 +1,132 @@
+- name: Prepare random number
+ set_fact:
+ cdnprofilename: "cdnprofile{{ resource_group | hash('md5') | truncate(7, True, '') }}{{ 1000 | random }}"
+ run_once: yes
+
+
+- name: Create a CDN profile(check mode)
+ azure_rm_cdnprofile:
+ resource_group: "{{ resource_group }}"
+ name: "{{ cdnprofilename }}"
+ sku: standard_akamai
+ tags:
+ testing: testing
+ delete: on-exit
+ foo: bar
+ check_mode: yes
+
+- name: Check there is no CDN profile created
+ azure_rm_cdnprofile_facts:
+ resource_group: "{{ resource_group }}"
+ name: "{{ cdnprofilename }}"
+ register: fact
+
+- name: Check there is no CDN profile created
+ assert: { that: "{{ fact.cdnprofiles | length }} == 0" }
+
+- name: Create a CDN profile
+ azure_rm_cdnprofile:
+ resource_group: "{{ resource_group }}"
+ name: "{{ cdnprofilename }}"
+ sku: standard_akamai
+ tags:
+ testing: testing
+ delete: on-exit
+ foo: bar
+ register: output
+
+- name: Assert the CDN profile is well created
+ assert:
+ that:
+ - output.changed
+ - output.id != ''
+
+- name: Gather CDN profile facts
+ azure_rm_cdnprofile_facts:
+ resource_group: "{{ resource_group }}"
+ name: "{{ cdnprofilename }}"
+ register: fact
+
+- name: Assert fact returns the created one
+ assert:
+ that:
+ - "fact.cdnprofiles | length == 1"
+ - fact.cdnprofiles[0].sku == 'Standard_Akamai'
+ - fact.cdnprofiles[0].tags.foo == 'bar'
+
+- name: Create a CDN profile (idempotent)
+ azure_rm_cdnprofile:
+ resource_group: "{{ resource_group }}"
+ name: "{{ cdnprofilename }}"
+ sku: standard_akamai
+ tags:
+ testing: testing
+ delete: on-exit
+ foo: bar
+ register: output
+
+- name: Assert idempotent
+ assert:
+ that:
+ - not output.changed
+
+- name: Update the CDN profile
+ azure_rm_cdnprofile:
+ resource_group: "{{ resource_group }}"
+ name: "{{ cdnprofilename }}"
+ sku: standard_akamai
+ tags:
+ testing: testing
+ delete: on-exit
+ foo: bar
+ baz: qux
+ register: output
+
+- name: Assert the CDN profile is updated
+ assert:
+ that:
+ - output.changed
+
+- name: Delete the CDN profile(check mode)
+ azure_rm_cdnprofile:
+ resource_group: "{{ resource_group }}"
+ name: "{{ cdnprofilename }}"
+ state: absent
+ check_mode: yes
+
+- name: Gather CDN profile facts
+ azure_rm_cdnprofile_facts:
+ resource_group: "{{ resource_group }}"
+ name: "{{ cdnprofilename }}"
+ register: fact
+
+- name: Assert the CDN is still there
+ assert:
+ that:
+ - "fact.cdnprofiles | length == 1"
+ - fact.cdnprofiles[0].sku == 'Standard_Akamai'
+ - fact.cdnprofiles[0].tags.foo == 'bar'
+ - fact.cdnprofiles[0].tags.baz == 'qux'
+
+- name: Delete the CDN profile
+ azure_rm_cdnprofile:
+ resource_group: "{{ resource_group }}"
+ name: "{{ cdnprofilename }}"
+ state: absent
+ register: output
+
+- name: Assert the CDN profile is well deleted
+ assert:
+ that:
+ - output.changed
+
+- name: Get CDN profile fact
+ azure_rm_cdnprofile_facts:
+ resource_group: "{{ resource_group }}"
+ name: "{{ cdnprofilename }}"
+ register: fact
+
+- name: Assert fact returns empty
+ assert:
+ that:
+ - "fact.cdnprofiles | length == 0"
diff --git a/test/runner/requirements/integration.cloud.azure.txt b/test/runner/requirements/integration.cloud.azure.txt
index 02e37156de..78ef8a48fd 100644
--- a/test/runner/requirements/integration.cloud.azure.txt
+++ b/test/runner/requirements/integration.cloud.azure.txt
@@ -4,6 +4,7 @@ azure-cli-core==2.0.35
azure-cli-nspkg==3.0.2
azure-common==1.1.11
azure-mgmt-batch==4.1.0
+azure.mgmt.cdn==3.0.0
azure-mgmt-compute==3.0.0
azure-mgmt-containerinstance==0.4.0
azure-mgmt-containerregistry==2.0.0