From 3e2e67c677bcb537027a955b0d38da81de09e5cf Mon Sep 17 00:00:00 2001 From: Yuwei Zhou Date: Fri, 11 Jan 2019 13:36:50 +0800 Subject: [PATCH] Add support for idle_timeout, version and ipTags, curated in facts module (#48923) --- .../cloud/azure/azure_rm_publicipaddress.py | 82 +++++++-- .../azure/azure_rm_publicipaddress_facts.py | 169 ++++++++++++++---- .../azure_rm_publicipaddress/tasks/main.yml | 15 +- 3 files changed, 221 insertions(+), 45 deletions(-) diff --git a/lib/ansible/modules/cloud/azure/azure_rm_publicipaddress.py b/lib/ansible/modules/cloud/azure/azure_rm_publicipaddress.py index aef04915090..5d551cc8dc2 100644 --- a/lib/ansible/modules/cloud/azure/azure_rm_publicipaddress.py +++ b/lib/ansible/modules/cloud/azure/azure_rm_publicipaddress.py @@ -36,9 +36,11 @@ options: - Control whether the assigned Public IP remains permanently assigned to the object. If not set to 'Static', the IP address my changed anytime an associated virtual machine is power cycled. choices: - - Dynamic + - dynamic + - static - Static - default: Dynamic + - Dynamic + default: dynamic domain_name: description: - The customizable portion of the FQDN assigned to public IP address. This is an explicit setting. If @@ -64,9 +66,29 @@ options: description: - The public IP address SKU. choices: + - basic + - standard - Basic - Standard version_added: 2.6 + ip_tags: + description: + - List of IpTag associated with the public IP address. + - Each element should contain type:value pair. + version_added: 2.8 + idle_timeout: + description: + - Idle timeout in minutes. + type: int + version_added: 2.8 + version: + description: + - The public IP address version. + choices: + - ipv4 + - ipv6 + default: ipv4 + version_added: 2.8 extends_documentation_fragment: - azure @@ -82,7 +104,7 @@ EXAMPLES = ''' azure_rm_publicipaddress: resource_group: testing name: my_public_ip - allocation_method: Static + allocation_method: static domain_name: foobar - name: Delete public ip @@ -105,13 +127,14 @@ state: "location": "westus", "name": "publicip002", "provisioning_state": "Succeeded", - "public_ip_allocation_method": "Static", + "public_ip_allocation_method": "static", "tags": {}, "type": "Microsoft.Network/publicIPAddresses" } ''' from ansible.module_utils.azure_rm_common import AzureRMModuleBase +from ansible.module_utils._text import to_native try: from msrestazure.azure_exceptions import CloudError @@ -126,7 +149,8 @@ def pip_to_dict(pip): type=pip.type, location=pip.location, tags=pip.tags, - public_ip_allocation_method=pip.public_ip_allocation_method, + public_ip_allocation_method=pip.public_ip_allocation_method.lower(), + public_ip_address_version=pip.public_ip_address_version.lower(), dns_settings=dict(), ip_address=pip.ip_address, idle_timeout_in_minutes=pip.idle_timeout_in_minutes, @@ -138,9 +162,17 @@ def pip_to_dict(pip): result['dns_settings']['domain_name_label'] = pip.dns_settings.domain_name_label result['dns_settings']['fqdn'] = pip.dns_settings.fqdn result['dns_settings']['reverse_fqdn'] = pip.dns_settings.reverse_fqdn + if pip.ip_tags: + result['ip_tags'] = [dict(type=to_native(x.ip_tag_type), value=to_native(x.tag)) for x in pip.ip_tags] return result +ip_tag_spec = dict( + type=dict(type='str', required=True), + value=dict(type='str', required=True) +) + + class AzureRMPublicIPAddress(AzureRMModuleBase): def __init__(self): @@ -150,9 +182,12 @@ class AzureRMPublicIPAddress(AzureRMModuleBase): name=dict(type='str', required=True), state=dict(type='str', default='present', choices=['present', 'absent']), location=dict(type='str'), - allocation_method=dict(type='str', default='Dynamic', choices=['Dynamic', 'Static']), + version=dict(type='str', default='ipv4', choices=['ipv4', 'ipv6']), + allocation_method=dict(type='str', default='dynamic', choices=['Dynamic', 'Static', 'dynamic', 'static']), domain_name=dict(type='str', aliases=['domain_name_label']), - sku=dict(type='str', choices=['Basic', 'Standard']) + sku=dict(type='str', choices=['Basic', 'Standard', 'basic', 'standard']), + ip_tags=dict(type='list', elements='dict', options=ip_tag_spec), + idle_timeout=dict(type='int') ) self.resource_group = None @@ -163,6 +198,9 @@ class AzureRMPublicIPAddress(AzureRMModuleBase): self.allocation_method = None self.domain_name = None self.sku = None + self.version = None + self.ip_tags = None + self.idle_timeout = None self.results = dict( changed=False, @@ -181,6 +219,11 @@ class AzureRMPublicIPAddress(AzureRMModuleBase): changed = False pip = None + # capitalize the sku and allocation_method. basic => Basic, Basic => Basic. + self.allocation_method = self.allocation_method.capitalize() if self.allocation_method else None + self.sku = self.sku.capitalize() if self.sku else None + self.version = 'IPv4' if self.version == 'ipv4' else 'IPv6' + resource_group = self.get_resource_group(self.resource_group) if not self.location: # Set default location @@ -198,7 +241,7 @@ class AzureRMPublicIPAddress(AzureRMModuleBase): changed = True results['dns_settings']['domain_name_label'] = self.domain_name - if self.allocation_method != results['public_ip_allocation_method']: + if self.allocation_method.lower() != results['public_ip_allocation_method'].lower(): self.log("CHANGED: allocation_method") changed = True results['public_ip_allocation_method'] = self.allocation_method @@ -208,6 +251,21 @@ class AzureRMPublicIPAddress(AzureRMModuleBase): changed = True results['sku'] = self.sku + if self.version.lower() != results['public_ip_address_version'].lower(): + self.log("CHANGED: version") + changed = True + results['public_ip_address_version'] = self.version + + if self.idle_timeout and self.idle_timeout != results['idle_timeout_in_minutes']: + self.log("CHANGED: idle_timeout") + changed = True + results['idle_timeout_in_minutes'] = self.idle_timeout + + if str(self.ip_tags or []) != str(results.get('ip_tags') or []): + self.log("CHANGED: ip_tags") + changed = True + results['ip_tags'] = self.ip_tags + update_tags, results['tags'] = self.update_tags(results['tags']) if update_tags: changed = True @@ -233,9 +291,13 @@ class AzureRMPublicIPAddress(AzureRMModuleBase): self.log("Create new Public IP {0}".format(self.name)) pip = self.network_models.PublicIPAddress( location=self.location, - public_ip_allocation_method=self.allocation_method, - sku=self.network_models.PublicIPAddressSku(name=self.sku) if self.sku else None + public_ip_address_version=self.version, + public_ip_allocation_method=self.allocation_method if self.version == 'IPv4' else None, + sku=self.network_models.PublicIPAddressSku(name=self.sku) if self.sku else None, + idle_timeout_in_minutes=self.idle_timeout if self.idle_timeout and self.idle_timeout > 0 else None ) + if self.ip_tags: + pip.ip_tags = [self.network_models.IpTag(ip_tag_type=x.type, tag=x.value) for x in self.ip_tags] if self.tags: pip.tags = self.tags if self.domain_name: diff --git a/lib/ansible/modules/cloud/azure/azure_rm_publicipaddress_facts.py b/lib/ansible/modules/cloud/azure/azure_rm_publicipaddress_facts.py index c28f7a9a798..b26e9144f9c 100644 --- a/lib/ansible/modules/cloud/azure/azure_rm_publicipaddress_facts.py +++ b/lib/ansible/modules/cloud/azure/azure_rm_publicipaddress_facts.py @@ -57,7 +57,9 @@ EXAMPLES = ''' RETURN = ''' azure_publicipaddresses: - description: List of public IP address dicts. + description: + - List of public IP address dicts. + - Please note that this option will be deprecated in 2.10 when curated format will become the only supported format. returned: always type: list example: [{ @@ -73,6 +75,87 @@ azure_publicipaddresses: }, "type": "Microsoft.Network/publicIPAddresses" }] +publicipaddresses: + description: + - List of publicipaddress + - Contains the detail which matches azure_rm_publicipaddress parameters. + - Returned when the format parameter set to curated. + returned: always + type: complex + contains: + id: + description: + - Resource ID. + returned: always + type: str + name: + description: + - Name of the public ip address. + returned: always + type: str + type: + description: + - Resource type. + returned: always + type: str + location: + description: + - Resource location. + returned: always + type: str + tags: + description: + - Resource tags. + returned: always + type: complex + allocation_method: + description: + - The public IP allocation method. + - Possible values are 'static' and 'dynamic'. + returned: always + type: str + version: + description: + - The public IP address version. + - Possible values are 'ipv4' and 'ipv6'. + returned: always + type: str + dns_settings: + description: + - The FQDN of the DNS record associated with the public IP address. + returned: always + type: complex + ip_tags: + description: + - The list of tags associated with the public IP address. + returned: always + type: complex + ip_address: + description: + - The Public IP Prefix this Public IP Address should be allocated from. + returned: always + type: str + idle_timeout: + description: + - The idle timeout of the public IP address. + returned: always + type: int + provisioning_state: + description: + - he provisioning state of the PublicIP resource. + - Possible values are 'Updating', 'Deleting', and 'Failed'. + returned: always + type: str + etag: + description: + - A unique read-only string that changes whenever the resource is updated. + returned: always + type: str + sku: + description: + - The public IP address SKU. + returned: always + type: str ''' try: from msrestazure.azure_exceptions import CloudError @@ -114,35 +197,73 @@ class AzureRMPublicIPFacts(AzureRMModuleBase): for key in self.module_arg_spec: setattr(self, key, kwargs[key]) + result = [] if self.name and not self.resource_group: self.fail("Parameter error: resource group required when filtering by name.") if self.name: - self.results['ansible_facts']['azure_publicipaddresses'] = self.get_item() + result = self.get_item() elif self.resource_group: - self.results['ansible_facts']['azure_publicipaddresses'] = self.list_resource_group() + result = self.list_resource_group() else: - self.results['ansible_facts']['azure_publicipaddresses'] = self.list_all() + result = self.list_all() + + raw = self.filter(result) + + self.results['ansible_facts']['azure_publicipaddresses'] = self.serialize(raw) + self.results['publicipaddresses'] = self.format(raw) return self.results + def format(self, raw): + return [self.pip_to_dict(item) for item in raw] + + def serialize(self, raw): + results = [] + for item in raw: + pip = self.serialize_obj(item, AZURE_OBJECT_CLASS) + pip['name'] = item.name + pip['type'] = item.type + results.append(pip) + return results + + def filter(self, response): + return [item for item in response if self.has_tags(item.tags, self.tags)] + + # duplicate with azure_rm_publicipaddress + def pip_to_dict(self, pip): + result = dict( + id=pip.id, + name=pip.name, + type=pip.type, + location=pip.location, + tags=pip.tags, + allocation_method=pip.public_ip_allocation_method.lower(), + version=pip.public_ip_address_version.lower(), + dns_settings=dict(), + ip_tags=dict(), + ip_address=pip.ip_address, + idle_timeout=pip.idle_timeout_in_minutes, + provisioning_state=pip.provisioning_state, + etag=pip.etag, + sku=pip.sku.name + ) + if pip.dns_settings: + result['dns_settings']['domain_name_label'] = pip.dns_settings.domain_name_label + result['dns_settings']['fqdn'] = pip.dns_settings.fqdn + result['dns_settings']['reverse_fqdn'] = pip.dns_settings.reverse_fqdn + if pip.ip_tags: + result['ip_tags'] = [dict(type=x.ip_tag_type, value=x.tag) for x in pip.ip_tags] + return result + def get_item(self): self.log('Get properties for {0}'.format(self.name)) item = None - result = [] - try: item = self.network_client.public_ip_addresses.get(self.resource_group, self.name) except CloudError: pass - - if item and self.has_tags(item.tags, self.tags): - pip = self.serialize_obj(item, AZURE_OBJECT_CLASS) - pip['name'] = item.name - pip['type'] = item.type - result = [pip] - - return result + return [item] if item else [] def list_resource_group(self): self.log('List items in resource groups') @@ -150,15 +271,7 @@ class AzureRMPublicIPFacts(AzureRMModuleBase): response = self.network_client.public_ip_addresses.list(self.resource_group) except AzureHttpError as exc: self.fail("Error listing items in resource groups {0} - {1}".format(self.resource_group, str(exc))) - - results = [] - for item in response: - if self.has_tags(item.tags, self.tags): - pip = self.serialize_obj(item, AZURE_OBJECT_CLASS) - pip['name'] = item.name - pip['type'] = item.type - results.append(pip) - return results + return response def list_all(self): self.log('List all items') @@ -166,15 +279,7 @@ class AzureRMPublicIPFacts(AzureRMModuleBase): response = self.network_client.public_ip_addresses.list_all() except AzureHttpError 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): - pip = self.serialize_obj(item, AZURE_OBJECT_CLASS) - pip['name'] = item.name - pip['type'] = item.type - results.append(pip) - return results + return response def main(): diff --git a/test/integration/targets/azure_rm_publicipaddress/tasks/main.yml b/test/integration/targets/azure_rm_publicipaddress/tasks/main.yml index 91f67750b10..a5f929b0a3b 100644 --- a/test/integration/targets/azure_rm_publicipaddress/tasks/main.yml +++ b/test/integration/targets/azure_rm_publicipaddress/tasks/main.yml @@ -22,7 +22,7 @@ - assert: that: - - output.state.public_ip_allocation_method == 'Static' + - output.state.public_ip_allocation_method == 'static' - output.state.dns_settings.domain_name_label == domain_name - output.state.tags | length == 2 - output.state.tags.testing == 'testing' @@ -31,7 +31,7 @@ azure_rm_publicipaddress: resource_group: "{{ resource_group }}" name: "pip{{ rpfx }}" - allocation_method: Static + allocation_method: static domain_name: "{{ domain_name }}" register: output @@ -42,6 +42,8 @@ azure_rm_publicipaddress: resource_group: "{{ resource_group }}" name: "pip{{ rpfx }}" + allocation_method: static + domain_name: "{{ domain_name }}" append_tags: yes tags: delete: never @@ -67,6 +69,8 @@ azure_rm_publicipaddress: resource_group: "{{ resource_group }}" name: "pip{{ rpfx }}" + allocation_method: static + domain_name: "{{ domain_name }}" append_tags: no register: output @@ -78,9 +82,14 @@ azure_rm_publicipaddress_facts: resource_group: "{{ resource_group }}" name: "pip{{ rpfx }}" + register: pip - assert: - that: azure_publicipaddresses | length == 1 + that: + - "pip.publicipaddresses | length == 1" + - pip.publicipaddresses[0].name == "pip{{ rpfx }}" + - pip.publicipaddresses[0].allocation_method == 'static' + - pip.publicipaddresses[0].dns_settings.domain_name_label == domain_name - name: Gather facts for all public ips azure_rm_publicipaddress_facts: