Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add azure_rm_afdendpoint module to support Azure Front Door Standard and Premium #1589

Merged
merged 12 commits into from
Jul 1, 2024
Merged
2 changes: 2 additions & 0 deletions meta/runtime.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ action_groups:
- azure.azcollection.azure_rm_adserviceprincipal_info
- azure.azcollection.azure_rm_aduser
- azure.azcollection.azure_rm_aduser_info
- azure.azcollection.azure_rm_afdendpoint
- azure.azcollection.azure_rm_afdendpoint_info
- azure.azcollection.azure_rm_aks
- azure.azcollection.azure_rm_aks_info
- azure.azcollection.azure_rm_aksagentpool
Expand Down
364 changes: 364 additions & 0 deletions plugins/modules/azure_rm_afdendpoint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,364 @@
#!/usr/bin/python
#
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#
# Python SDK Reference: https://learn.microsoft.com/en-us/python/api/azure-mgmt-cdn/azure.mgmt.cdn.operations.afdendpointsoperations?view=azure-python
#
# TODO: Name check the URL
#
from __future__ import absolute_import, division, print_function

__metaclass__ = type

DOCUMENTATION = '''
---
module: azure_rm_afdendpoint
version_added: "2.4.0"
short_description: Manage an Azure Front Door Endpoint to be used with Standard or Premium Frontdoor
description:
- Create, update and delete an Azure Front Door (AFD) Endpoint to be used by a Front Door Service Profile created using azure_rm_cdnprofile.
- This differs from the Front Door classic service and only is intended to be used by the Standard or Premium service offering.

options:
auto_generated_domain_name_label_scope:
description:
- Indicates the endpoint name reuse scope. Cannot be used to update an existing Endpoint at this time.
default: TenantReuse
type: str
choices:
- TenantReuse
- SubscriptionReuse
- ResourceGroupReuse
- NoReuse
enabled_state:
description:
- Whether to enable use of this rule.
default: Enabled
type: str
choices:
- Enabled
- Disabled
location:
description:
- Valid Azure location. Defaults to location of the resource group. Cannot be used to update an existing Endpoint at this time.
type: str
name:
description:
- Name of the AFD Endpoint.
required: True
type: str
profile_name:
description:
- Name of the AFD Profile where the Endpoint will be attached to.
required: True
type: str
resource_group:
description:
- Name of a resource group where the Azure Front Door Endpoint exists or will be created.
required: True
type: str
state:
description:
- Assert the state of the AFD Endpoint. Use C(present) to create or update an AFD Endpoint and C(absent) to delete it.
default: present
type: str
choices:
- absent
- present

extends_documentation_fragment:
- azure.azcollection.azure
- azure.azcollection.azure_tags

author:
- Jarret Tooley (@jartoo)
'''

EXAMPLES = '''
- name: Create an AFD Endpoint
azure_rm_afdendpoint:
name: myEndpoint
profile_name: myProfile
resource_group: myResourceGroup
state: present
tags:
testing: testing

- name: Delete the AFD Endpoint
azure_rm_afdendpoint:
name: myEndPoint
profile_name: myProfile
resource_group: myResourceGroup
state: absent
'''
RETURN = '''
id:
description:
- ID of the AFD Endpoint.
returned: always
type: str
sample: "id: /subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourcegroups/
myResourceGroup/providers/Microsoft.Cdn/profiles/myProfile/endpoints/myEndpoint"
host_name:
description:
- Host name of the AFD Endpoint.
returned: always
type: str
sample: "myendpoint.azurefd.net"

'''
from ansible_collections.azure.azcollection.plugins.module_utils.azure_rm_common import AzureRMModuleBase

try:
from azure.mgmt.cdn.models import AFDEndpoint, AFDEndpointUpdateParameters
from azure.mgmt.cdn import CdnManagementClient
except ImportError as ec:
# This is handled in azure_rm_common
pass


def endpoint_to_dict(endpoint):
return dict(
deployment_status=endpoint.deployment_status,
enabled_state=endpoint.enabled_state,
host_name=endpoint.host_name,
id=endpoint.id,
location=endpoint.location,
name=endpoint.name,
provisioning_state=endpoint.provisioning_state,
tags=endpoint.tags,
type=endpoint.type
)


class AzureRMEndpoint(AzureRMModuleBase):

def __init__(self):
self.module_arg_spec = dict(
auto_generated_domain_name_label_scope=dict(
type='str',
default='TenantReuse',
choices=["TenantReuse", "SubscriptionReuse", "ResourceGroupReuse", "NoReuse"]
),
enabled_state=dict(
type='str',
default='Enabled',
choices=['Enabled', 'Disabled']
),
location=dict(
type='str'
),
name=dict(
type='str',
required=True
),
profile_name=dict(
type='str',
required=True
),
resource_group=dict(
type='str',
required=True
),
state=dict(
type='str',
default='present',
choices=['present', 'absent']
)
)

self.auto_generated_domain_name_label_scope = None
self.enabled_state = None
self.location = None
self.tags = None

self.name = None
self.profile_name = None
self.resource_group = None
self.state = None

self.endpoint_client = None

self.results = dict(changed=False)

super(AzureRMEndpoint, self).__init__(
derived_arg_spec=self.module_arg_spec,
supports_check_mode=True,
supports_tags=True)

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.endpoint_client = self.get_endpoint_client()

to_be_updated = False

if not self.location:
resource_group = self.get_resource_group(self.resource_group)
self.location = resource_group.location

response = self.get_endpoint()

if self.state == 'present':

if not response:
self.log("Need to create the AFD Endpoint")

if not self.check_mode:
new_response = self.create_endpoint()
self.results['id'] = new_response['id']
self.results['host_name'] = new_response['host_name']
self.log("AFD Endpoint creation done")

self.results['changed'] = True
return self.results

else:
self.log('Results : {0}'.format(response))
self.results['id'] = response['id']
self.results['host_name'] = response['host_name']

update_tags, self.tags = self.update_tags(response['tags'])

if update_tags:
to_be_updated = True

if response['provisioning_state'] == "Succeeded":
if response['enabled_state'] != self.enabled_state:
to_be_updated = True

if self.location.lower() != response['location'].lower() and self.location:
# Location is not currently implemented in begin_update()
self.log("AFD Endpoint locations changes are not idempotent, please delete and recreate the Endpoint.")

if to_be_updated:
self.log("Need to update the AFD Endpoint")
self.results['changed'] = True

if not self.check_mode:
result = self.update_endpoint()
self.results['host_name'] = result['host_name']
self.log("AFD Endpoint update done")

elif self.state == 'absent':
if not response:
self.log("AFD Endpoint {0} does not exist.".format(self.name))
self.results['id'] = ""
else:
self.log("Need to delete the AFD Endpoint")
self.results['changed'] = True
self.results['id'] = response['id']

if not self.check_mode:
self.delete_endpoint()
self.log("Azure AFD Endpoint deleted")

return self.results

def create_endpoint(self):
'''
Creates an AFD Endpoint.

:return: deserialized AFD Endpoint instance state dictionary
'''
self.log("Creating the AFD Endpoint instance {0}".format(self.name))

parameters = AFDEndpoint(
auto_generated_domain_name_label_scope=self.auto_generated_domain_name_label_scope,
enabled_state=self.enabled_state,
location=self.location,
tags=self.tags
)

try:
poller = self.endpoint_client.afd_endpoints.begin_create(
endpoint_name=self.name,
profile_name=self.profile_name,
resource_group_name=self.resource_group,
endpoint=parameters)
response = self.get_poller_result(poller)
return endpoint_to_dict(response)
except Exception as exc:
self.log('Error attempting to create AFD Endpoint instance.')
self.fail("Error Creating AFD Endpoint instance: {0}".format(str(exc)))

def update_endpoint(self):
'''
Updates an AFD Endpoint.

:return: deserialized AFD Endpoint instance state dictionary
'''
self.log("Updating the AFD Endpoint instance {0}".format(self.name))

parameters = AFDEndpointUpdateParameters(
tags=self.tags,
enabled_state=self.enabled_state
)
try:
poller = self.endpoint_client.afd_endpoints.begin_update(
endpoint_name=self.name,
profile_name=self.profile_name,
resource_group_name=self.resource_group,
endpoint_update_properties=parameters)
response = self.get_poller_result(poller)
return endpoint_to_dict(response)
except Exception as exc:
self.log('Error attempting to update AFD Endpoint instance.')
self.fail("Error updating AFD Endpoint instance: {0}".format(str(exc)))

def delete_endpoint(self):
'''
Deletes the specified AFD Endpoint in the specified subscription and resource group.

:return: True
'''
self.log("Deleting the AFD Endpoint {0}".format(self.name))
try:
poller = self.endpoint_client.afd_endpoints.begin_delete(
resource_group_name=self.resource_group, profile_name=self.profile_name, endpoint_name=self.name)
self.get_poller_result(poller)
return True
except Exception as exc:
self.log('Error attempting to delete the AFD Endpoint.')
self.fail("Error deleting the AFD Endpoint: {0}".format(str(exc)))
return False

def get_endpoint(self):
'''
Gets the properties of the specified AFD Endpoint.

:return: deserialized AFD Endpoint state dictionary
'''
self.log(
"Checking if the AFD Endpoint {0} is present".format(self.name))
try:
response = self.endpoint_client.afd_endpoints.get(
resource_group_name=self.resource_group,
profile_name=self.profile_name,
endpoint_name=self.name)
self.log("Response : {0}".format(response))
self.log("AFD Endpoint : {0} found".format(response.name))
return endpoint_to_dict(response)
except Exception as err:
self.log('Did not find the AFD Endpoint.')
return False

def get_endpoint_client(self):
if not self.endpoint_client:
self.endpoint_client = self.get_mgmt_svc_client(
CdnManagementClient,
base_url=self._cloud_environment.endpoints.resource_manager,
api_version='2023-05-01')
return self.endpoint_client


def main():
"""Main execution"""
AzureRMEndpoint()


if __name__ == '__main__':
main()
Loading