I'm trying to create a new host key for a newly created function app and it fails with the following error:
{
"status": "Failed",
"error": {
"code": "BadRequest",
"message": "Encountered an error (InternalServerError) from host runtime.",
"details": [
{
"message": "Encountered an error (InternalServerError) from host runtime."
},
{
"code": "BadRequest"
},
{}
]
}
}
Also, it seems to mess up the portal as well:
When doing the same when the function app already exists, it works though.
Here's what I'm doing
module myFunctionModule '../function-bundle.bicep' = {
name: parentDeploymentName
params: {
storageAccountName: storageAccountName
functionAppName: functionName
functionAppPlanName: appPlanName
keyVaultName: keyVaultName
tags: functionAppTags
location: location
parentDeploymentName: parentDeploymentName
}
}
resource waitDeployment 'Microsoft.Resources/deployments@2021-04-01' = {
name: 'waitForFunctionApp'
properties: {
mode: 'Incremental'
template: {
'$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#'
contentVersion: '1.0.0.0'
resources: []
}
}
dependsOn: [
myFunctionModule
]
}
resource myKey 'Microsoft.Web/sites/host/functionKeys@2022-03-01' = {
name: '${functionName}/default/myKey'
properties: {
name: 'myKey'
}
dependsOn: [
waitDeployment
]
}
I've tried with and without the waitDeployment
, it fails regardless.
Here's the content of the function-bundle
module
param tags object
param functionAppName string
param functionAppPlanName string
param storageAccountName string
param keyVaultName string
param location string
param parentDeploymentName string
module functionModule './function.bicep' = {
name: take('${parentDeploymentName}-functionDeployment', 64)
params: {
location: location
storageAccountName: storageAccountName
appServicePlanName: functionAppPlanName
functionAppTags: tags
functionAppName: functionAppName
}
}
module addKeyVaultAccessDeploymentModule './add-kv-access.bicep' = {
name: take('${parentDeploymentName}-functionAddKeyVaultAccessDeployment', 64)
params: {
keyVaultName: keyVaultName
principalId: functionModule.outputs.functionIdentity.principalId
roleName: 'KeyVaultSecretsUserRole'
principalType: 'ServicePrincipal'
}
}
@secure()
output storageAccountKey string = functionModule.outputs.storageAccountKey
@secure()
output storageAccountConnectionString string = functionModule.outputs.storageAccountConnectionString
output functionUrl string = functionModule.outputs.functionUrl
And function.bicep
param location string
param storageAccountName string
param appServicePlanName string
param functionAppTags object
param functionAppName string
param sku object = {
name: 'B1'
tier: 'Basic'
size: 'B1'
family: 'B'
capacity: 1
}
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-05-01' = {
name: storageAccountName
location: location
tags: functionAppTags
sku: {
name: 'Standard_LRS'
}
kind: 'Storage'
}
resource appServicePlan 'Microsoft.Web/serverfarms@2024-04-01' = {
name: appServicePlanName
location: location
properties: {
reserved: true
}
kind: 'functionapp,linux'
sku: sku
tags: functionAppTags
}
resource function 'Microsoft.Web/sites@2024-04-01' = {
name: functionAppName
location: location
tags: functionAppTags
kind: 'functionapp,linux'
identity: {
type: 'SystemAssigned'
}
properties: {
enabled: true
serverFarmId: appServicePlan.id
siteConfig: {
numberOfWorkers: 1
linuxFxVersion: 'DOTNET-ISOLATED|9.0'
appSettings: [
{
name: 'AzureWebJobsStorage'
value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};AccountKey=${storageAccount.listKeys().keys[0].value};EndpointSuffix=core.windows.net'
}
{
name: 'FUNCTIONS_WORKER_RUNTIME'
value: 'dotnet-isolated'
}
{
name: 'FUNCTIONS_EXTENSION_VERSION'
value: '~4'
}
]
}
}
}
var listKeyResult = storageAccount.listKeys()
output functionIdentity object = function.identity
@secure()
output storageAccountKey string = listKeyResult.keys[0].value
@secure()
output storageAccountConnectionString string = 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};AccountKey=${listKeyResult.keys[0].value};EndpointSuffix=core.windows.net'
output functionUrl string = 'https://${function.properties.defaultHostName}/api'
output defaultHostKey string = '' //listKeys(resourceId('Microsoft.Web/sites/host', functionAppName, 'default'), function.apiVersion).functionKeys.default
I've also tried
resource myKey 'Microsoft.Web/sites/host/functionKeys@2022-03-01' = {
name: '${functionName}/default/myKey'
properties: {
name: 'myKey'
}
dependsOn: [
myFunctionModule
]
}
Still fails.
Could it be that depending on a module isn't as reliable as depending on a resource ?
I've have been able to do it this way.
Underneath the definition for myFunctionModule
Since the actual resource is contained in the module and not exposable through its outputs
resource existingFunction 'Microsoft.Web/sites@2024-04-01' existing = {
name: functionName
dependsOn: [myFunctionModule]
}
Then fetch the site host for the function
resource siteHost 'Microsoft.Web/sites/host@2022-03-01' existing = {
name: 'default'
parent: existingFunction
}
Then create the key
resource myKey 'Microsoft.Web/sites/host/functionKeys@2022-03-01' = {
name: 'myKey'
properties: {
name: 'myKey'
}
parent: siteHost
}
Then I can use the result as output, if needed
@secure()
output myKey string = myKey.properties.value
Both myKey
and siteHost
are flagged with a warning that:
Resource type "Microsoft.Web/sites/host/functionKeys@2022-03-01" does not have types available. Bicep is unable to validate resource properties prior to deployment, but this will not block the resource from being deployed
But it still works. You have to make sure that when creating the function app, those appSettings are present if you want to manage its host keys. (I used to update the app settings after creation, which was a problem)
var initialAppSettings = [
{
name: 'AzureWebJobsStorage'
value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};AccountKey=${storageAccount.listKeys().keys[0].value};EndpointSuffix=core.windows.net'
}
{
name: 'FUNCTIONS_WORKER_RUNTIME'
value: 'dotnet-isolated'
}
{
name: 'FUNCTIONS_EXTENSION_VERSION'
value: '~4'
}
]
I have not validated which one(s) are needed exactly, but if you ignore them altogether this will fail.