From ea609c34927f7f38fe7bf5c82bd3bbe6bd6c61f1 Mon Sep 17 00:00:00 2001 From: Zim Kalinowski Date: Mon, 8 Apr 2019 11:05:21 +0800 Subject: [PATCH] adding plan and container settings to function app (#54830) --- .../cloud/azure/azure_rm_appserviceplan.py | 14 ++-- .../cloud/azure/azure_rm_functionapp.py | 81 ++++++++++++++++++- .../azure_rm_functionapp/tasks/main.yml | 68 ++++++++++++---- 3 files changed, 140 insertions(+), 23 deletions(-) diff --git a/lib/ansible/modules/cloud/azure/azure_rm_appserviceplan.py b/lib/ansible/modules/cloud/azure/azure_rm_appserviceplan.py index a427ad45006..9bb40252113 100644 --- a/lib/ansible/modules/cloud/azure/azure_rm_appserviceplan.py +++ b/lib/ansible/modules/cloud/azure/azure_rm_appserviceplan.py @@ -110,6 +110,7 @@ from ansible.module_utils.azure_rm_common import AzureRMModuleBase try: from msrestazure.azure_exceptions import CloudError + from msrest.polling import LROPoller from msrestazure.azure_operation import AzureOperationPoller from msrest.serialization import Model from azure.mgmt.web.models import ( @@ -315,10 +316,11 @@ class AzureRMAppServicePlans(AzureRMModuleBase): try: response = self.web_client.app_service_plans.get(self.resource_group, self.name) - self.log("Response : {0}".format(response)) - self.log("App Service Plan : {0} found".format(response.name)) + if response: + self.log("Response : {0}".format(response)) + self.log("App Service Plan : {0} found".format(response.name)) - return appserviceplan_to_dict(response) + return appserviceplan_to_dict(response) except CloudError as ex: self.log("Didn't find app service plan {0} in resource group {1}".format(self.name, self.resource_group)) @@ -340,10 +342,10 @@ class AzureRMAppServicePlans(AzureRMModuleBase): plan_def = AppServicePlan( location=self.location, app_service_plan_name=self.name, sku=sku_def, reserved=self.is_linux, tags=self.tags if self.tags else None) - poller = self.web_client.app_service_plans.create_or_update(self.resource_group, self.name, plan_def) + response = self.web_client.app_service_plans.create_or_update(self.resource_group, self.name, plan_def) - if isinstance(poller, AzureOperationPoller): - response = self.get_poller_result(poller) + if isinstance(response, LROPoller) or isinstance(response, AzureOperationPoller): + response = self.get_poller_result(response) self.log("Response : {0}".format(response)) diff --git a/lib/ansible/modules/cloud/azure/azure_rm_functionapp.py b/lib/ansible/modules/cloud/azure/azure_rm_functionapp.py index 7053ae51a50..2a02af8f646 100644 --- a/lib/ansible/modules/cloud/azure/azure_rm_functionapp.py +++ b/lib/ansible/modules/cloud/azure/azure_rm_functionapp.py @@ -34,6 +34,29 @@ options: location: description: - Valid Azure location. Defaults to location of the resource group. + plan: + description: + - App service plan. + - It can be name of existing app service plan in same resource group as function app. + - "It can be resource id of existing app service plan. eg., + /subscriptions//resourceGroups//providers/Microsoft.Web/serverFarms/" + - It can be a dict which contains C(name), C(resource_group). + - C(name). Name of app service plan. + - C(resource_group). Resource group name of app service plan. + version_added: "2.8" + container_settings: + description: Web app container settings. + suboptions: + name: + description: Name of container. eg. "imagename:tag" + registry_server_url: + description: Container registry server url. eg. mydockerregistry.io + registry_server_user: + description: The container registry server user name. + registry_server_password: + description: + - The container registry server password. + version_added: "2.8" storage_account: description: - Name of the storage account to use. @@ -130,12 +153,23 @@ from ansible.module_utils.azure_rm_common import AzureRMModuleBase try: from msrestazure.azure_exceptions import CloudError - from azure.mgmt.web.models import Site, SiteConfig, NameValuePair, SiteSourceControl + from azure.mgmt.web.models import ( + site_config, app_service_plan, Site, SiteConfig, NameValuePair, SiteSourceControl, + AppServicePlan, SkuDescription + ) from azure.mgmt.resource.resources import ResourceManagementClient + from msrest.polling import LROPoller except ImportError: # This is handled in azure_rm_common pass +container_settings_spec = dict( + name=dict(type='str', required=True), + registry_server_url=dict(type='str'), + registry_server_user=dict(type='str'), + registry_server_password=dict(type='str', no_log=True) +) + class AzureRMFunctionApp(AzureRMModuleBase): @@ -150,7 +184,14 @@ class AzureRMFunctionApp(AzureRMModuleBase): type='str', aliases=['storage', 'storage_account_name'] ), - app_settings=dict(type='dict') + app_settings=dict(type='dict'), + plan=dict( + type='raw' + ), + container_settings=dict( + type='dict', + options=container_settings_spec + ) ) self.results = dict( @@ -164,6 +205,8 @@ class AzureRMFunctionApp(AzureRMModuleBase): self.location = None self.storage_account = None self.app_settings = None + self.plan = None + self.container_settings = None required_if = [('state', 'present', ['storage_account'])] @@ -213,10 +256,28 @@ class AzureRMFunctionApp(AzureRMModuleBase): else: self.results['changed'] = False else: + kind = 'functionapp' + linux_fx_version = None + if self.container_settings and self.container_settings.get('name'): + kind = 'functionapp,linux,container' + linux_fx_version = 'DOCKER|' + if self.container_settings.get('registry_server_url'): + self.app_settings['DOCKER_REGISTRY_SERVER_URL'] = 'https://' + self.container_settings['registry_server_url'] + linux_fx_version += self.container_settings['registry_server_url'] + '/' + linux_fx_version += self.container_settings['name'] + if self.container_settings.get('registry_server_user'): + self.app_settings['DOCKER_REGISTRY_SERVER_USERNAME'] = self.container_settings.get('registry_server_user') + + if self.container_settings.get('registry_server_password'): + self.app_settings['DOCKER_REGISTRY_SERVER_PASSWORD'] = self.container_settings.get('registry_server_password') + + if not self.plan and function_app: + self.plan = function_app.server_farm_id + if not exists: function_app = Site( location=self.location, - kind='functionapp', + kind=kind, site_config=SiteConfig( app_settings=self.aggregated_app_settings(), scm_type='LocalGit' @@ -226,6 +287,20 @@ class AzureRMFunctionApp(AzureRMModuleBase): else: self.results['changed'], function_app = self.update(function_app) + # get app service plan + if self.plan: + if isinstance(self.plan, dict): + self.plan = "/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Web/serverfarms/{2}".format( + self.subscription_id, + self.plan.get('resource_group', self.resource_group), + self.plan.get('name') + ) + function_app.server_farm_id = self.plan + + # set linux fx version + if linux_fx_version: + function_app.site_config.linux_fx_version = linux_fx_version + if self.check_mode: self.results['state'] = function_app.as_dict() elif self.results['changed']: diff --git a/test/integration/targets/azure_rm_functionapp/tasks/main.yml b/test/integration/targets/azure_rm_functionapp/tasks/main.yml index 19349495f5a..5a42f09a763 100644 --- a/test/integration/targets/azure_rm_functionapp/tasks/main.yml +++ b/test/integration/targets/azure_rm_functionapp/tasks/main.yml @@ -1,18 +1,26 @@ - name: Fix resource prefix set_fact: - fixed_resource_prefix: "{{ (resource_prefix | replace('-','x'))[-22:] }}" + fixed_resource_prefix: "{{ resource_group | hash('md5') | truncate(7, True, '') }}{{ 1000 | random }}" + +- name: Fix resource prefix + set_fact: + funcapp_name_basic: "fa{{ fixed_resource_prefix }}basic" + funcapp_name_container: "fa{{ fixed_resource_prefix }}container" + funcapp_name_params: "fa{{ fixed_resource_prefix }}params" + storage_account_name: "sa{{ fixed_resource_prefix }}" + plan_name: "ap{{ fixed_resource_prefix }}" - name: create storage account for function apps azure_rm_storageaccount: resource_group: '{{ resource_group }}' - name: sa{{ fixed_resource_prefix }} + name: "{{ storage_account_name }}" account_type: Standard_LRS - name: create basic function app azure_rm_functionapp: - resource_group: '{{ resource_group }}' - name: af{{ fixed_resource_prefix }} - storage_account: sa{{ fixed_resource_prefix }} + resource_group: "{{ resource_group }}" + name: "{{ funcapp_name_basic }}" + storage_account: "{{ storage_account_name }}" register: output - name: assert the function was created @@ -22,19 +30,19 @@ - name: list facts for function azure_rm_functionapp_facts: resource_group: '{{ resource_group }}' - name: af{{ fixed_resource_prefix }} + name: "{{ funcapp_name_basic }}" register: results - name: assert the facts were retrieved assert: that: - results.ansible_facts.azure_functionapps|length == 1 - - results.ansible_facts.azure_functionapps[0].name == 'af{{ fixed_resource_prefix }}' + - results.ansible_facts.azure_functionapps[0].name == "{{ funcapp_name_basic }}" - name: delete basic function app azure_rm_functionapp: resource_group: '{{ resource_group }}' - name: af{{ fixed_resource_prefix }} + name: "{{ funcapp_name_basic }}" state: absent register: output @@ -45,8 +53,8 @@ - name: create a function with app settings azure_rm_functionapp: resource_group: '{{ resource_group }}' - name: af{{ fixed_resource_prefix }}x - storage_account: sa{{ fixed_resource_prefix }} + name: "{{ funcapp_name_params }}" + storage_account: "{{ storage_account_name }}" app_settings: hello: world things: more stuff @@ -60,8 +68,8 @@ - name: change app settings azure_rm_functionapp: resource_group: '{{ resource_group }}' - name: af{{ fixed_resource_prefix }}x - storage_account: sa{{ fixed_resource_prefix }} + name: "{{ funcapp_name_params }}" + storage_account: "{{ storage_account_name }}" app_settings: hello: world things: more stuff @@ -76,7 +84,7 @@ - name: delete the function app azure_rm_functionapp: resource_group: '{{ resource_group }}' - name: af{{ fixed_resource_prefix }}x + name: "{{ funcapp_name_params }}" state: absent register: output @@ -84,8 +92,40 @@ assert: that: output.changed +- name: Create a linux app service plan + azure_rm_appserviceplan: + resource_group: "{{ resource_group }}" + name: "{{ plan_name }}" + sku: S1 + is_linux: true + number_of_workers: 1 + +- name: "Create azure function app {{ function_app }}" + azure_rm_functionapp: + resource_group: "{{ resource_group }}" + name: "{{ funcapp_name_container }}" + storage_account: "{{ storage_account_name }}" + plan: + resource_group: "{{ resource_group }}" + name: "{{ plan_name }}" + container_settings: + name: httpd + app_settings: + FUNCTIONS_EXTENSION_VERSION: "~2" + register: output + +- name: assert the function was changed + assert: + that: output.changed + +- name: delete the function app + azure_rm_functionapp: + resource_group: '{{ resource_group }}' + name: "{{ funcapp_name_container }}" + state: absent + - name: delete storage account azure_rm_storageaccount: resource_group: '{{ resource_group }}' - name: sa{{ fixed_resource_prefix }} + name: "{{ storage_account_name }}" state: absent