Closed zhengchang907 closed 1 year ago
Thanks for raising this, it definitely looks like a regression in v0.4.1008.
One thing that's slightly unusual about your mainTemplate.bicep file is the use of the reference()
function. Is there a reason for it?
Instead of the following:
var ref_preDeployment = reference(resourceId('Microsoft.Resources/deployments', 'pre'))
module pre './module/pre.bicep' = {
name: 'pre'
}
module core './module/core.bicep' = {
name: 'core'
params: {
resourceGroupName: ref_preDeployment.outputs.rgName.value
}
dependsOn: [
pre
]
}
The more idiomatic way to do this in Bicep would be:
module pre './module/pre.bicep' = {
name: 'pre'
}
module core './module/core.bicep' = {
name: 'core'
params: {
resourceGroupName: pre.outputs.rgName
}
}
Thanks for raising this, it definitely looks like a regression in v0.4.1008.
One thing that's slightly unusual about your mainTemplate.bicep file is the use of the
reference()
function. Is there a reason for it?Instead of the following:
var ref_preDeployment = reference(resourceId('Microsoft.Resources/deployments', 'pre')) module pre './module/pre.bicep' = { name: 'pre' } module core './module/core.bicep' = { name: 'core' params: { resourceGroupName: ref_preDeployment.outputs.rgName.value } dependsOn: [ pre ] }
The more idiomatic way to do this in Bicep would be:
module pre './module/pre.bicep' = { name: 'pre' } module core './module/core.bicep' = { name: 'core' params: { resourceGroupName: pre.outputs.rgName } }
Hi Anthony, I agree with you on this example. However, in our product project we have the reference()
thing up there with some other logic integrated like 'if'. And we use reference()
so that the later parts can look prettier.
@zhengchang907 -- can you clarify what looks prettier when you use reference()
? Generally speaking, sticking with idiomatic bicep results in less characters required to express the same amount of information. Can you provide an example where you use reference()
in combination with a condition/ternary operator?
@zhengchang907 -- can you clarify what looks prettier when you use
reference()
? Generally speaking, sticking with idiomatic bicep results in less characters required to express the same amount of information. Can you provide an example where you usereference()
in combination with a condition/ternary operator?
Hi Alex,
In our usage, sometime we have different deployments for the same resource, decided by user inputs. And later if we want to reference the output of the deployment, we will determine the deployment name first, then reference the deployment using reference()
, and finally use output values of it. We use this practice to approach a clear code structure.
And we are surely open to better ways to do so.
Here is a sample code from our repo
// Determine the deployment name
var name_networkDeployment = enableAppGWIngress ? (appGatewayCertificateOption == const_appgwSSLCertOptionGenerateCert ? 'ds-networking-deployment-1': 'ds-networking-deployment') : 'ds-networking-deployment-2'
// Reference the deployment
var ref_networkDeployment = reference(name_networkDeployment)
module networkingDeployment '_deployment-scripts/_ds-create-networking.bicep' = if (enableAppGWIngress && appGatewayCertificateOption != const_appgwSSLCertOptionGenerateCert) {
name: 'ds-networking-deployment'
params: {
// ...
appgwFrontendSSLCertData: existingKeyvault.getSecret(keyVaultSSLCertDataSecretName)
appgwFrontendSSLCertPsw: existingKeyvault.getSecret(keyVaultSSLCertPasswordSecretName)
// ...
}
dependsOn: [
// ...
]
}
// Wrokaround for "Error BCP180: Function "getSecret" is not valid at this location. It can only be used when directly assigning to a module parameter with a secure decorator."
module networkingDeployment2 '_deployment-scripts/_ds-create-networking.bicep' = if (enableAppGWIngress && appGatewayCertificateOption == const_appgwSSLCertOptionGenerateCert) {
name: 'ds-networking-deployment-1'
params: {
// ...
appgwFrontendSSLCertData: existingKeyvault.getSecret(keyVaultSSLCertDataSecretName)
appgwFrontendSSLCertPsw: 'null'
// ...
}
dependsOn: [
// ...
]
}
module networkingDeployment3 '_deployment-scripts/_ds-create-networking.bicep' = if (!enableAppGWIngress) {
name: 'ds-networking-deployment-2'
params: {
// ...
appgwFrontendSSLCertData: 'null'
appgwFrontendSSLCertPsw: 'null'
// ...
}
dependsOn: [
// ...
]
}
// Use the deployment output to format values we need here
output adminConsoleExternalUrl string = enableAppGWIngress ? (enableDNSConfiguration ? format('http://{0}console', const_appgwAdminCustomDNSAlias) : format('http://{0}/console', appgwDeployment.outputs.appGatewayAlias)) : ref_networkDeployment.outputs.adminConsoleLBUrl.value
Origin code: https://github.com/oracle/weblogic-azure/blob/main/weblogic-azure-aks/src/main/bicep/modules/networking.bicep
Hi @zhengchang907
Until this is fixed, here is a workaround that respect what you are doing and is a more "bicep native" instead of calling the ARM reference()
function yourself.
If I start from your code in mainTemplate.bicep
in your zip file. I replaced the reference()
call and changed it for an existing resource reference to your prior deployment. You'll need to add a .properties
member before the .outputs
member for the output references you are doing.
Before
var ref_preDeployment = reference(resourceId('Microsoft.Resources/deployments', 'pre'))
...
resourceGroupName: ref_preDeployment.outputs.rgName.value
After
resource ref_preDeployment 'Microsoft.Resources/deployments@2021-04-01' existing = {
name: 'pre'
}
...
resourceGroupName: ref_preDeployment.properties.outputs.rgName.value
Full example:
//var ref_preDeployment = reference(resourceId('Microsoft.Resources/deployments', 'pre'))
resource ref_preDeployment 'Microsoft.Resources/deployments@2021-04-01' existing = {
name: 'pre'
}
module pre './module/pre.bicep' = {
name: 'pre'
}
module core './module/core.bicep' = {
name: 'core'
params: {
resourceGroupName: ref_preDeployment.properties.outputs.rgName.value
}
dependsOn: [
pre
]
}
I've tested this on Bicep CLI version 0.4.1124 (66c84c8ee5)
Hope it helps.
Hello @stephaniezyen , any update on this? We're still tracking it as a dependency for our Deployment Script resources for Java EE on Azure.
@edburns -- does the workaround that @slapointe provided work for your team? Personally, I think this is safer than using the reference()
function directly.
I'm closing this due to no activity since it is in Top10. Feel free to correct me it it's still an urgent issue.
Bicep version v0.4.1008
Describe the bug v0.4.1008 built templates throw deployment exceptions:
{"code":"DeploymentFailed","message":"At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/DeployOperations for usage details.","details":[{"code":"InvalidTemplate","message":"Unable to process template language expressions for resource '/subscriptions/05887623-95c5-4e50-a71c-6e1c738794e2/resourceGroups/zhengtest102101rg/providers/Microsoft.Resources/deployments/core' at line '43' and column '5'. 'The language expression property 'rgName' doesn't exist, available properties are 'templateHash, mode, provisioningState, timestamp, duration, correlationId, providers, dependencies, outputs, outputResources'.'"}]}
To Reproduce Steps to reproduce the behavior:
bicep build mainTemplate.bicep
withBicep CLI version 0.4.1008 (223b8d227a)
az deployment group create -f mainTemplate.json -g <some_test_rg>
Additional context Cannot reproduce it using
v0.4.613
orv0.4.451