Using bicep, I am creating a storage account, and creating an app service. For the app service, it is attempting to to set the AzureWebJobsStorage app setting to point to the storage account. I get the following error:
...
"details": [
{
"code": "StorageAccountIsNotProvisioned",
"message": "The storage account provisioning state must be 'Succeeded' before executing the operation."
}
]
...
It seems that even though I have dependencies set up, the creation of the function app does not wait for successful completion of the storage account, and there must be validation on the function app appsettings values. I think the error is referring to the AzureWebJobsStorage appsettings key of the appService resource in the bicep below.
If I run the bicep a second time, everything works, because the storage account has already been created. is there some way in the bicep file to ensure that the storage account has been successfully created before creating the function app?
What's interesting is it never errors out on the reference to the application insights, only on the reference to the storage account, and both references are within appsettings.
In one module I create my storage account:
param tags object
param storeAccountName string
param location string = resourceGroup().location
param skuName string = 'Standard_LRS'
resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = {
name: toLower(storeAccountName)
kind: 'StorageV2'
location : location
sku: {
name: skuName
}
tags: tags
}
In another module I create a function app, and refer to the storage account:
param tags object
param name string
param location string = resourceGroup().location
param appServicePlanId string
param applicationInsightsName string
param storageAccountName string
resource appInsights 'Microsoft.Insights/components@2020-02-02' existing = {
name: applicationInsightsName
}
resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' existing = {
name: toLower(storageAccountName)
}
resource appService 'Microsoft.Web/sites@2022-03-01' = {
name: name
location: location
kind: 'functionapp'
properties: {
serverFarmId: appServicePlanId
siteConfig: {
appSettings: [
//Storage settings
{
name: 'AzureWebJobsStorage'
value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storageAccount.listKeys().keys[0].value}'
}
//Application insight settings
{
//https://learn.microsoft.com/en-us/azure/azure-monitor/app/migrate-from-instrumentation-keys-to-connection-strings
name: 'APPLICATIONINSIGHTS_CONNECTION_STRING'
value: appInsights.properties.ConnectionString
}
{
name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
value: appInsights.properties.InstrumentationKey
}
{
name: 'APPINSIGHTS_PROFILERFEATURE_VERSION'
value: '1.0.0'
}
{
name: 'APPINSIGHTS_SNAPSHOTFEATURE_VERSION'
value: '1.0.0'
}
{
name: 'ApplicationInsightsAgent_EXTENSION_VERSION'
value: '~2'
}
{
name: 'XDT_MicrosoftApplicationInsights_Java'
value: '1'
}
{
name: 'XDT_MicrosoftApplicationInsights_Mode'
value: 'recommended'
}
{
name: 'XDT_MicrosoftApplicationInsights_NodeJS'
value: '1'
}
{
name: 'InstrumentationEngine_EXTENSION_VERSION'
value: 'disabled'
}
{
name: 'SnapshotDebugger_EXTENSION_VERSION'
value: 'disabled'
}
{
name: 'XDT_MicrosoftApplicationInsights_BaseExtensions'
value: 'disabled'
}
{
name: 'XDT_MicrosoftApplicationInsights_PreemptSdk'
value: 'disabled'
}
]
}
}
dependsOn: [
//Some Appsettings depend on resources that must be deployed first
appInsights
storageAccount
]
tags: tags
identity: {
type: 'SystemAssigned'
}
}
output principalId string = appService.identity.principalId
My Main bicep file uses the modules as follows:
param location string = resourceGroup().location
param storageAccountSKUName string = 'Standard_LRS'
param functionAppServiceSKUName string = 'Y1'
param logAnalyticsSKUName string = 'Standard'
var storageAccountName = 'mystorage'
var logAnalyticsWorkspaceName = 'mylogs'
var appInsightsName = 'myinsights'
var appServicePlanName = 'myappservice'
var tags = {...}
module storageAccount './modules/storage/StorageAccount.bicep' = {
name:'storageAccount'
params: {
tags: tags
location:location
storeAccountName:storageAccountName
skuName:storageAccountSKUName
}
}
module logWorkspace './modules/loganalytics/LogWorkspace.bicep' = {
name: 'logAnalyticsWorkspace'
params: {
name: logAnalyticsWorkspaceName
tags: tags
skuName: logAnalyticsSKUName
location: location
}
}
module appInsights './modules/loganalytics/AppInsignts.bicep' = {
name: 'appInsights'
params: {
name:appInsightsName
tags: tags
location:location
workspaceId:logWorkspace.outputs.resourceId
}
}
module appServicePlan './modules/services/AppServicePlan.bicep' =
{
name: 'appServicePlan'
params: {
tags: tags
name: appServicePlanName
skuName: appServiceSKUName
location:location
}
}
module appService './modules/services/AppServiceReceiver.bicep' = {
name: 'appServiceReceiveHL7v2POI'
params: {
tags: tags
name: appServiceReceiveHL7v2POIName
location:location
appServicePlanId:functionServicePlan.outputs.resourceId
applicationInsightsName:appInsightsName
storageAccountName:storageAccountName
}
}
Your AppService module is not waiting for the Storage creation.
module appService './modules/services/AppServiceReceiver.bicep' = {
name: 'appServiceReceiveHL7v2POI'
params: {
tags: tags
name: appServiceReceiveHL7v2POIName
location:location
appServicePlanId:functionServicePlan.outputs.resourceId
applicationInsightsName:appInsightsName
storageAccountName:storageAccountName //This line is wrong
}
}
You need a DependsOn added to the App Service module call. This can be explicit or implicit.
Explicit (not great practice);
module appService './modules/services/AppServiceReceiver.bicep' = {
name: 'appServiceReceiveHL7v2POI'
params: {
tags: tags
name: appServiceReceiveHL7v2POIName
location:location
appServicePlanId:functionServicePlan.outputs.resourceId
applicationInsightsName:appInsightsName
storageAccountName:storageAccountName
}
dependsOn: [
storageAccount
]
}
or Implicit
module appService './modules/services/AppServiceReceiver.bicep' = {
name: 'appServiceReceiveHL7v2POI'
params: {
tags: tags
name: appServiceReceiveHL7v2POIName
location:location
appServicePlanId:functionServicePlan.outputs.resourceId
applicationInsightsName:appInsightsName
storageAccountName: storageAccount.outputs.name
}
}
You currently have the dependsOn inside the appService module, which is too late. You need it before the module is referenced for the dependency chain to be built properly.