App Insights Connection String reference, give ERROR BCP178, with for loop - azure

I have a bicep that creates apps in for loop.
var App = {
(...)
}
module app 'app:latest' = [for i in range(0, length(App.appServices)): {
name: 'app${i}'
params: {
(...)
}
}]
I want to connect it with app insights.
I found I could use reference to resolve APPLICATIONINSIGHTS_CONNECTION_STRING:
siteConfig: {
linuxFxVersion: 'NODE|14-lts'
appSettings: [
{
name: 'APPLICATIONINSIGHTS_CONNECTION_STRING'
value: reference(resourceId(resourceGroup().name,'Microsoft.insights/components/', 'app1'), '2020-02-02').ConnectionString
}
And unfortunately this throw error:
Error BCP178: This expression is being used in the for-expression, which requires a value that can be calculated at the start of the deployment. You are referencing a variable which cannot be calculated at the start ("App" -> "applicationinsights_connection_string" -> "reference").
INFO: Command ran in 17.855 seconds (init: 0.252, invoke: 17.602)
How do I make it work? How do I force bicep to resolve it first?
Is there another way to link apps created with for loop with application insights?
P.S
code above works fine without for loop for a single app.

Error BCP178: This expression is being used in the for-expression, which requires a value that can be calculated at the start of the deployment.
This error means that referencing value must be given before the loop begins. So, build an array of connection strings outside of the loop and then reference that array within the loop.
create an array of connection strings by using a for loop outside of the module declaration. We then reference this array inside the loop that creates the app modules and assign the appropriate connection string to the params. appInsightsConnectionString property.
var appInsightsConnections = [ for i in range(0, length(app1.appServices)): ```
reference(resourceId(resourceGroup().name,'Microsoft.insights/components/', 'app1'), '2020-02-02').ConnectionString]
Add this in your bicep code:
params: {
(...)
appInsightsConnectionString: appInsightsConnections[i]
}
I made the above changes and ran a sample template taken from MSDoc and was able to deploy it successfully.
Refer this template to connect an app service with application insights.

Related

Azure Bicep - Subresource reference with resourceId()

I am deploying an App Gateway on Azure using a Bicep template (relevant pieces shown below).
var applicationGatewayId = resourceId('Microsoft.Network/applicationGateways', applicationGatewayName)
resource applicationGateway 'Microsoft.Network/applicationGateways#2021-08-01' = {
properties: {
urlPathMaps: [
{
properties: {
defaultBackendAddressPool: {
id: '${applicationGatewayId}/backendAddressPools/backendpool-test'
}
}
]
}
}
My question is about the id of the backendAddressPool in the example. I get a warning when compiling: Warning use-resource-id-functions: If property "id" represents a resource ID, it must use a symbolic resource reference, be a parameter or start with one of these functions: extensionResourceId, guid, if, reference, resourceId, subscription, subscriptionResourceId, tenantResourceId. [https://aka.ms/bicep/linter/use-resource-id-functions].
I tried using ${applicationGateway.id}/backendAddressPools/backendpool-test, but that results in a cyclic reference error. For other resource types I used resourceId(), but for this example I wouldn't know how to.
I tried, e.g., resourceId('Microsoft.Network/ApplicationGatewayBackendAddressPool', '${prefix}-backendpool-infocat'), but that seems to result in a different resource type altogether (doesn't compile into the same id, at least).
This question is applicable to other subresources too, such as:
applicationGateway.urlPathMaps.defaultBackendAddressPool
applicationGateway.urlPathMaps.pathRules.backendAddressPool
applicationGateway.urlPathMaps.pathRules.backendHttpSettings
...
So how does one refer to these subresources properly, when there's no readily defined resourceType to be used in resourceId()? Can the warnings be avoided?
Thanks in advance!
Try this:
id:resourceId('Microsoft.Network/applicationGateways/backendAddressPools', applicationGatewayName, applicationGatewayBackendAddressPoolName)

Bicep - data factory identity property

I'm running bicep 0.4.1318.
I have a "main" bicep module that calls a sub module to provision data factory:
var adfName = 'adf-ctaxrebate-${envPlusSuffix}-${formattedInstanceNum}'
module adfDeploy 'CTaxRebate.dataFactory.bicep' = {
name: 'adfDeploy'
params: {
adfName: adfName
}
}
The data factory module is as follows:
param adfName string
resource adf 'Microsoft.DataFactory/factories#2018-06-01' = {
name:adfName
location: resourceGroup().location
}
output dfId string = adf.identity.principalId
I used the PowerShell cdmlet New-AzResourceGroupDeployment to run the main bicep but I'm getting the following error:
The template output 'dfId' is not valid: The language expression
| property 'identity' doesn't exist, available properties are 'apiVersion, location, tags, etc...
I think this is trying to tell me that the following line from the adf module is wrong:
output dfId string = adf.identity.principalId
I'm puzzled by this since I've used the same code on a previous project and it works ok.
Also, the identity property does appear in the intellisense:
You need to add
identity: {
type: 'SystemAssigned'
}
to the definition of your DataFactory in the module to tell the system it should generate a system assigned ID for you.

Reading nested attribute in data source (of a Cloud Run service that might not exist) in Terraform

I'm using Terraform v0.14.4 with GCP. I have a Cloud Run service that won't be managed with Terraform (it might exist or not), and I want to read its url.
If the service exists this works ok:
data "google_cloud_run_service" "myservice" {
name = "myservice"
location = "us-central1"
}
output "myservice" {
value = data.google_cloud_run_service.myservice.status[0].url
}
But if it doesn't exist, I can't get it to work!. What I've tried:
data.google_cloud_run_service.myservice.*.status[*].url
status is null
length(data.google_cloud_run_service.myservice) > 0 ? data.google_cloud_run_service.myservice.*.status[0].url : ""
Tried with join("", data.google_cloud_run_service.myservice.*.status)
I get this error: data.google_cloud_run_service.myservice is object with 9 attributes
coalescelist(data.google_cloud_run_service.myservice.*.status, <...>)
It just returns [null], and using compact over the result gets me a Invalid value for "list" parameter: element 0: string required.
Any ideas?
It seems like you are working against the design of this data source a little here, but based on the error messages you've shown it seems like the behavior is that status is null when the requested object doesn't exist and is a list when it does, and so you'll need to write an expression that can deal with both situations.
Here's my attempt, based only on the documentation of the resource along with some assumptions I'm making based on the error message you included:
output "myservice" {
value = (
data.google_cloud_run_service.myservice.status != null ?
data.google_cloud_run_service.myservice.status[0].url :
null
)
}
There is another potentially-shorter way to write that, relying on the try function's ability to catch dynamic errors and return a fallback value, although this does go against the recommendations in the documentation in that it forces an unfamiliar future reader to do a bit more guesswork to understand in which situations the expression might succeed and which it might return the fallback:
output "myservice" {
value = try(data.google_cloud_run_service.myservice.status[0].url, null)
}

Terraform empty and non-empty block map variables

I want to make backend-service by using Terraform. I use resource_type google_compute_backend_service
Now, i have 2 backend-services created by gcloud command. The one is using cdn_policy block and another one doesn't use cdn_policy.
The first backend-services tfstate is like
...
"cdn_policy": [
{
"cache_key_policy": [],
"signed_url_cache_max_age_sec": 3600
}
]
...
And the second backend-services is like
"cdn_policy": []
How to create the terraform script works for both of them ? So, terraform script can run for backend-services who has cdn_policy include with its block map and can also run for backend-services without cdn_policy.
In my idea, i can create 2 terraform scripts. First for cdn_policy and second without cdn_policy. But, i think this is not best practice.
If i put cdn_policy = [], it would result error An argument named "cdn_policy" is not expected here
You can use dynamic blocks to create a set of blocks based on a list of objects in an input variable: Dynamic Blocks
resource "google_compute_backend_service" "service" {
...
dynamic "cdn_policy" {
for_each = var.cdn_policy
content {
cache_key_policy = cdn_policy.value.cache_key_policy
signed_url_cache_max_age_sec = cdn_policy.value.signed_url_cache_max_age_sec
}
}
}

Azure Functions table binding not being created when developing locally

I'm attempting to use an output table binding with an Azure Function V2 (node).
I have added the table binding to function.json, as described in the documentation.
{
"tableName": "Person",
"connection": "MyStorageConnectionAppSetting",
"name": "tableBinding",
"type": "table",
"direction": "out"
}
And then I am attempting to insert some content in to that table, again using the example as described in the documentation.
for (var i = 1; i < 10; i++) {
context.bindings.tableBinding.push({
PartitionKey: "Test",
RowKey: i.toString(),
Name: "Name " + i
});
}
To confirm - I have also added a setting called MyStorageConnectionAppSetting in to local.settings.json, with a valid Storage Account connection string as it's value.
Sadly though, this is failing and I'm seeing the following error -
System.Private.CoreLib: Exception while executing function: Functions.config. System.Private.CoreLib: Result: Failure
Exception: TypeError: Cannot read property 'push' of undefined
It seems that the binding object has not be created as expected, but I have no idea why.
The package Microsoft.Azure.WebJobs.Extensions.Storage is included in extensions.csproj, and the Function App starts just fine when I call func start.
Although I believe that no connection to the Storage Account is taking place, I did try to run my function both when the Table existed, and when it didn't.
Make sure the parameter has been initialized before usage. The output binding is undefined unless it's initialized or assigned value.
context.bindings.tableBinding = [];

Resources