def create_functionapp()

in src/appservice-kube/azext_appservice_kube/custom.py [0:0]


def create_functionapp(cmd, resource_group_name, name, storage_account=None, plan=None,
                       os_type=None, functions_version=None, runtime=None, runtime_version=None,
                       consumption_plan_location=None, app_insights=None, app_insights_key=None,
                       disable_app_insights=None, deployment_source_url=None,
                       deployment_source_branch='master', deployment_local_git=None,
                       docker_registry_server_password=None, docker_registry_server_user=None,
                       deployment_container_image_name=None, tags=None, assign_identities=None,
                       role='Contributor', scope=None,
                       custom_location=None, min_worker_count=None, max_worker_count=None):
    # pylint: disable=too-many-statements, too-many-branches
    if functions_version is None:
        logger.warning("No functions version specified so defaulting to 3. In the future, specifying a version will "
                       "be required. To create a 3.x function you would pass in the flag `--functions-version 3`")
        functions_version = '3'

    if deployment_source_url and deployment_local_git:
        raise MutuallyExclusiveArgumentError('usage error: --deployment-source-url <url> | --deployment-local-git')
    if not plan and not consumption_plan_location and not custom_location:
        raise RequiredArgumentMissingError("Either Plan, Consumption Plan or Custom Location must be specified")
    if consumption_plan_location and custom_location:
        raise MutuallyExclusiveArgumentError("Consumption Plan and Custom Location cannot be used together")
    if consumption_plan_location and plan:
        raise MutuallyExclusiveArgumentError("Consumption Plan and Plan cannot be used together")

    from azure.mgmt.web.models import Site
    SiteConfig, NameValuePair, SkuDescription = cmd.get_models('SiteConfig', 'NameValuePair', 'SkuDescription')
    docker_registry_server_url = parse_docker_image_name(deployment_container_image_name)
    disable_app_insights = disable_app_insights == "true"

    custom_location = _get_custom_location_id(cmd, custom_location, resource_group_name)

    site_config = SiteConfig(app_settings=[])
    client = web_client_factory(cmd.cli_ctx)

    functionapp_def = Site(location=None, site_config=site_config, tags=tags)

    plan_info = None
    if runtime is not None:
        runtime = runtime.lower()

    if consumption_plan_location:
        locations = list_consumption_locations(cmd)
        location = next((loc for loc in locations if loc['name'].lower() == consumption_plan_location.lower()), None)
        if location is None:
            raise ValidationError("Location is invalid. Use: az functionapp list-consumption-locations")
        functionapp_def.location = consumption_plan_location
        functionapp_def.kind = 'functionapp'
        # if os_type is None, the os type is windows
        is_linux = bool(os_type and os_type.lower() == LINUX_OS_NAME)

    else:  # apps with SKU based plan
        _should_create_new_plan = _should_create_new_appservice_plan_for_k8se(cmd,
                                                                              name, custom_location,
                                                                              plan, resource_group_name)
        if _should_create_new_plan:
            plan = generate_default_app_service_plan_name(name)
            logger.warning("Plan not specified. Creating Plan '%s' with sku '%s'", plan, KUBE_DEFAULT_SKU)
            create_app_service_plan(cmd=cmd, resource_group_name=resource_group_name,
                                    name=plan, is_linux=True, hyper_v=False, custom_location=custom_location,
                                    per_site_scaling=True, number_of_workers=1)
        if custom_location and plan:
            if not _validate_asp_and_custom_location_kube_envs_match(cmd, resource_group_name, custom_location, plan):
                raise ValidationError("Custom location's kube environment "
                                      "and App Service Plan's kube environment don't match")
        elif custom_location and not plan:
            app_details = get_app_details(cmd, name, resource_group_name)
            if app_details is not None:
                plan = app_details.server_farm_id

        if is_valid_resource_id(plan):
            parse_result = parse_resource_id(plan)
            plan_info = client.app_service_plans.get(parse_result['resource_group'], parse_result['name'])
        else:
            plan_info = client.app_service_plans.get(resource_group_name, plan)
        if not plan_info:
            raise ResourceNotFoundError("The plan '{}' doesn't exist".format(plan))

        location = plan_info.location
        is_linux = bool(plan_info.reserved)
        functionapp_def.server_farm_id = plan
        functionapp_def.location = location

    if functions_version == '2' and functionapp_def.location in FUNCTIONS_NO_V2_REGIONS:
        raise ValidationError("2.x functions are not supported in this region. To create a 3.x function, "
                              "pass in the flag '--functions-version 3'")

    if is_linux and not runtime and (consumption_plan_location or not deployment_container_image_name):
        raise ArgumentUsageError(
            "usage error: --runtime RUNTIME required for linux functions apps without custom image.")

    if runtime is None and runtime_version is not None:
        raise ArgumentUsageError('Must specify --runtime to use --runtime-version')

    is_kube = _is_function_kube(custom_location, plan_info, SkuDescription)
    if not storage_account and not is_kube:
        raise ValidationError("--storage-account required for non-kubernetes function apps")

    runtime_helper = _FunctionAppStackRuntimeHelper(cmd, linux=is_linux, windows=not is_linux)
    matched_runtime = runtime_helper.resolve("dotnet" if not runtime else runtime,
                                             runtime_version, functions_version, is_linux)

    if is_kube:
        if min_worker_count is not None:
            site_config.number_of_workers = min_worker_count

        if max_worker_count is not None:
            site_config.app_settings.append(NameValuePair(name='K8SE_APP_MAX_INSTANCE_COUNT', value=max_worker_count))

    site_config_dict = matched_runtime.site_config_dict
    app_settings_dict = matched_runtime.app_settings_dict

    con_string = None
    if storage_account:
        con_string = _validate_and_get_connection_string(cmd.cli_ctx, resource_group_name, storage_account)

    if is_kube:
        functionapp_def.enable_additional_properties_sending()
        # if Custom Location provided, use that for Extended Location Envelope. Otherwise, get Custom Location from ASP
        if custom_location:
            custom_location_id = _get_custom_location_id_from_custom_location(cmd, custom_location, resource_group_name)
            if custom_location_id:
                extended_loc = {'name': custom_location_id, 'type': 'CustomLocation'}
                functionapp_def.additional_properties["extendedLocation"] = extended_loc
        else:
            extended_loc = plan_info.additional_properties["extendedLocation"]
            functionapp_def.additional_properties["extendedLocation"] = extended_loc

        functionapp_def.kind = KUBE_FUNCTION_APP_KIND
        functionapp_def.reserved = True
        site_config.app_settings.append(NameValuePair(name='WEBSITES_PORT', value='80'))
        site_config.app_settings.append(NameValuePair(name='MACHINEKEY_DecryptionKey',
                                                      value=str(hexlify(urandom(32)).decode()).upper()))
        if deployment_container_image_name:
            functionapp_def.kind = KUBE_FUNCTION_CONTAINER_APP_KIND
            site_config.app_settings.append(NameValuePair(name='DOCKER_CUSTOM_IMAGE_NAME',
                                                          value=deployment_container_image_name))
            site_config.app_settings.append(NameValuePair(name='FUNCTION_APP_EDIT_MODE', value='readOnly'))
            site_config.linux_fx_version = _format_fx_version(deployment_container_image_name)
            site_config.app_settings.append(NameValuePair(name='DOCKER_REGISTRY_SERVER_URL',
                                                          value=docker_registry_server_url))
            if docker_registry_server_user is not None and docker_registry_server_password is not None:
                site_config.app_settings.append(NameValuePair(name='DOCKER_REGISTRY_SERVER_USERNAME',
                                                              value=docker_registry_server_user))
                site_config.app_settings.append(NameValuePair(name='DOCKER_REGISTRY_SERVER_PASSWORD',
                                                              value=docker_registry_server_password))
        else:
            site_config.app_settings.append(NameValuePair(name='WEBSITES_ENABLE_APP_SERVICE_STORAGE', value='true'))
            site_config.linux_fx_version = _get_linux_fx_kube_functionapp(runtime, runtime_version)
    elif is_linux:
        functionapp_def.kind = 'functionapp,linux'
        functionapp_def.reserved = True
        is_consumption = consumption_plan_location is not None
        if not is_consumption:
            site_config.app_settings.append(NameValuePair(name='MACHINEKEY_DecryptionKey',
                                                          value=str(hexlify(urandom(32)).decode()).upper()))
            if deployment_container_image_name:
                functionapp_def.kind = 'functionapp,linux,container'
                site_config.app_settings.append(NameValuePair(name='DOCKER_CUSTOM_IMAGE_NAME',
                                                              value=deployment_container_image_name))
                site_config.app_settings.append(NameValuePair(name='FUNCTION_APP_EDIT_MODE', value='readOnly'))
                site_config.app_settings.append(NameValuePair(name='WEBSITES_ENABLE_APP_SERVICE_STORAGE',
                                                              value='false'))
                site_config.linux_fx_version = _format_fx_version(deployment_container_image_name)

                # clear all runtime specific configs and settings
                site_config_dict.use32_bit_worker_process = False
                app_settings_dict = {}

                # ensure that app insights is created if not disabled
                matched_runtime.app_insights = True
            else:
                site_config.app_settings.append(NameValuePair(name='WEBSITES_ENABLE_APP_SERVICE_STORAGE',
                                                              value='true'))
    else:
        functionapp_def.kind = 'functionapp'

    # set site configs
    for prop, value in site_config_dict.as_dict().items():
        snake_case_prop = _convert_camel_to_snake_case(prop)
        setattr(site_config, snake_case_prop, value)

    # temporary workaround for dotnet-isolated linux consumption apps
    if is_linux and consumption_plan_location is not None and runtime == 'dotnet-isolated':
        site_config.linux_fx_version = ''

    # adding app settings
    for app_setting, value in app_settings_dict.items():
        site_config.app_settings.append(NameValuePair(name=app_setting, value=value))

    site_config.app_settings.append(NameValuePair(name='FUNCTIONS_EXTENSION_VERSION',
                                                  value=_get_extension_version_functionapp(functions_version)))
    if con_string:
        site_config.app_settings.append(NameValuePair(name='AzureWebJobsStorage', value=con_string))

    # If plan is not consumption or elastic premium, we need to set always on
    if consumption_plan_location is None and not is_plan_elastic_premium(cmd, plan_info):
        site_config.always_on = True

    # If plan is elastic premium or consumption, we need these app settings
    if is_plan_elastic_premium(cmd, plan_info) or consumption_plan_location is not None:
        if con_string:
            site_config.app_settings.append(NameValuePair(name='WEBSITE_CONTENTAZUREFILECONNECTIONSTRING',
                                                          value=con_string))
        site_config.app_settings.append(NameValuePair(name='WEBSITE_CONTENTSHARE', value=_get_content_share_name(name)))

    create_app_insights = False

    if app_insights_key is not None:
        site_config.app_settings.append(NameValuePair(name='APPINSIGHTS_INSTRUMENTATIONKEY',
                                                      value=app_insights_key))
    elif app_insights is not None:
        instrumentation_key = get_app_insights_key(cmd.cli_ctx, resource_group_name, app_insights)
        site_config.app_settings.append(NameValuePair(name='APPINSIGHTS_INSTRUMENTATIONKEY',
                                                      value=instrumentation_key))
    elif disable_app_insights or not matched_runtime.app_insights:
        # set up dashboard if no app insights
        if con_string:
            site_config.app_settings.append(NameValuePair(name='AzureWebJobsDashboard', value=con_string))
    elif not disable_app_insights and matched_runtime.app_insights:
        create_app_insights = True

    poller = client.web_apps.begin_create_or_update(resource_group_name, name, functionapp_def)
    functionapp = LongRunningOperation(cmd.cli_ctx)(poller)

    if consumption_plan_location and is_linux:
        logger.warning("Your Linux function app '%s', that uses a consumption plan has been successfully "
                       "created but is not active until content is published using "
                       "Azure Portal or the Functions Core Tools.", name)
    else:
        _set_remote_or_local_git(cmd, functionapp, resource_group_name, name, deployment_source_url,
                                 deployment_source_branch, deployment_local_git)

    if create_app_insights:
        try:
            try_create_application_insights(cmd, functionapp)
        except Exception:  # pylint: disable=broad-except
            logger.warning('Error while trying to create and configure an Application Insights for the Function App. '
                           'Please use the Azure Portal to create and configure the Application Insights, if needed.')
            if con_string:
                update_app_settings(cmd, functionapp.resource_group, functionapp.name,
                                    ['AzureWebJobsDashboard={}'.format(con_string)])

    if deployment_container_image_name:
        update_container_settings_functionapp(cmd, resource_group_name, name, docker_registry_server_url,
                                              deployment_container_image_name, docker_registry_server_user,
                                              docker_registry_server_password)

    if assign_identities is not None:
        identity = assign_identity(cmd, resource_group_name, name, assign_identities,
                                   role, None, scope)
        functionapp.identity = identity

    return functionapp