Azure Bicep - Subresource reference with resourceId() - azure

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)

Related

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.

Bicep: How to concat tags

I am using a Bicep script to create resources in Mcirosoft Azure.
I have defined a variable with the common tags that are the same for all resources.But now, when assigning this variable to a resource, I want to add more tags that are only for this resource.
However, I have not yet found a way to do this.
You can use the union function to merge object.
In this sample, I've defined a parameter with the common tags and merge the object with resource specific tags:
param commonTags object = {
commonTag1: 'commonTag1'
commonTag2: 'commonTag2'
}
resource storageAccount 'Microsoft.Storage/storageAccounts#2019-06-01' = {
name: 'my storage account name'
...
tags: union(commonTags, {
storageTag1: 'storageTag1'
storageTag2: 'storageTag2'
})
}

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 repeat blocks

I have a rather - I think - trivial question but I can not see the answer.
The pagerduty terraform provider allows to define a list of targets.
We live a "Full Ownership, Full Empowerment" culture, so each team has assigned their own .tf file where they can reign their garden.
This is a classical team file:
# create the teams terraform landscape
locals {
#some team locals
}
resource "pagerduty_service" "teletubbies" {
#...
}
resource "pagerduty_escalation_policy" "teletubbies" {
#...
rule {
escalation_delay_in_minutes = 10
target {
type = "schedule_reference"
id = pagerduty_schedule.draco.id
}
}
# PLACE OF QUESTION
}
resource "pagerduty_schedule" "teletubbies" {
#...
}
resource "pagerduty_service_integration" "teletubbies" {
#...
}
resource "pagerduty_extension" "teletubbies"{
#...
}
Now, I marked a PLACE OF QUESTION in my code.
Our teams are actually motivated to operate their service "alone". But you know how it works, some things just do not work out. I want to add to each teams policy 1 or two more rules that will trigger when the owning team does not react to the alert (a safety net).
As I also want clean code I do not want to copy pasta around 15 (15 teams) times the same code.
I fancy something like this:
resource "pagerduty_escalation_policy" "teletubbies" {
#...
#owning teams rules
template(escalation_rules)
}
I have found nothing that kind of "just loads text". I have seen that with TF>0.11 or so, you had a template_data provider, but this has been deprecated. I have also seen the new templatefile() but this seems to only work with an assignment.
The challenge I faced here is that e.g. templatefile() wants an assignment, you can not just do
resource "pagerduty_escalation_policy" "teletubbies" {
#...
#owning teams rules
templatefile(file, vars)
}
because it will complain until you do
resource "pagerduty_escalation_policy" "teletubbies" {
#...
#owning teams rules
xxxx = templatefile(file, vars)
}
which again is not what the provider wants of course.
Anyone has an idea how I can plainly render some definitions (without assignment)?
I checked modules but somehow this is also not what I need. I just need a "take a longer string and paste it neatly to the place I want" function.
Thank you for any pointers
PS:
terraform {
required_version = "~> 0.14.4"
required_providers {
pagerduty = {
source = "pagerduty/pagerduty"
version = "~> 1.8.0"
}
}
}

Access parameter from a resource defined using create_resources

I would like to know if it is possible to access a parameter from a class being instantiated using the create_resources function. I want to use that parameter in other class to conditionally install some things or not.
This is my scenario:
define myResource($myParam) { ... }
create_resources(myResource, $hashResources)
$hashResources = { "MyResource1" : { "myParam" : 1 },
"MyResource2" : { "myParam" : 2 }
}
myFancyPuppetClass($nameOfResource) {
if(******myParam from the resource defined with name $nameOfResource in the same catalog******) { ... }
}
Is this possible? If it is, how can I do the reference? Thank you!
Since the resources you are attempting to create are defined types, and the parameters in a defined resource are not accessible, this is not possible in the latest version of Puppet.
See a previous answer of mine regarding accessing parameters in defined resources for an alternative.

Resources