Azure / bicep

Bicep is a declarative language for describing and deploying Azure resources
MIT License
3.23k stars 748 forks source link

`existing` resources with `false` conditions must use valid expressions for name and scoping properties in language version 2 #13937

Open slavizh opened 6 months ago

slavizh commented 6 months ago

Bicep version Bicep CLI version 0.26.170 (e9abaf16a5)

Describe the bug On language version 2 (when I add user defined types) the template below stops to work.

To Reproduce If I have the following template

main.bicep

targetScope = 'subscription'

@export()
type settingsType = {
  logAnalytics: logsAnalyticsType?
  eventHub: eventHubType?
}

type logsAnalyticsType = {
  resourceGroup: string
  name: string
  logs: string[]?
}

type eventHubType = {
  resourceGroup: string
  namespace: string
  name: string?
  policyName: string?
  logs: string[]?
}

param settings settingsType = {
  logAnalytics: {
    name: '<TO BE REPLACED>'
    resourceGroup: '<TO BE REPLACED>'
    logs: [
      'Administrative'
    ]
  }
}

var settingsObject = {
  logAnalytics: {
    name: ''
    resourceGroup: ''
    logs: []
  }
  eventHub: {
    namespace: ''
    resourceGroup: ''
    policyName: 'RootManageSharedAccessKey'
    logs: []
  }
}

resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2022-10-01' existing = if (!empty(union(settingsObject, settings).logAnalytics.name)) {
  name: union(settingsObject, settings).logAnalytics.name
  scope: resourceGroup(settings.logAnalytics!.resourceGroup)
}

resource logsAndMetricsToLogAnalytics 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = if (!empty(union(settingsObject, settings).logAnalytics.name)) {
  name: 'subscriptionLogs1'
  properties: {
    workspaceId: logAnalyticsWorkspace.id
    logs: [for log in union(settingsObject, settings).logAnalytics.logs: {
      category: log
      enabled: true
    }]
  }
}

resource eventHub 'Microsoft.EventHub/namespaces@2022-10-01-preview' existing = if (!empty(union(settingsObject, settings).eventHub.namespace)) {
  name: union(settingsObject, settings).eventHub.namespace
  scope: resourceGroup(union(settingsObject, settings).eventHub.resourceGroup)
}

resource eventHubAuthorizationRule 'Microsoft.EventHub/namespaces/authorizationRules@2022-10-01-preview' existing = if (!empty(union(settingsObject, settings).eventHub.namespace)) {
  name: union(settingsObject, settings).eventHub.policyName
  parent: eventHub
}

resource logsAndMetricsToEventHub 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = if (!empty(union(settingsObject, settings).eventHub.namespace)) {
  name: 'subscriptionLogs2'
  properties: {
    eventHubAuthorizationRuleId: eventHubAuthorizationRule.id
    eventHubName: null
    logs: [for log in union(settingsObject, settings).eventHub.logs: {
      category: log
      enabled: true
    }]
  }
}

and I try to deploy it I get error like:

New-AzDeployment: 15:11:15 - Error: Code=InvalidTemplate; Message=Deployment template validation failed: 'The template resource '' of type 'Microsoft.EventHub/namespaces' at line '130' and column '21' is not valid. The name property cannot be null or empty. Please see https://aka.ms/arm-syntax-resources for usage details.'.
New-AzDeployment: The deployment validation failed

As soon as I remove the user defined types the template is deployed successfully.

another workaround is to put conditions on the names of the existing resources:

targetScope = 'subscription'

@export()
type settingsType = {
  logAnalytics: logsAnalyticsType?
  eventHub: eventHubType?
}

type logsAnalyticsType = {
  resourceGroup: string
  name: string
  logs: string[]?
}

type eventHubType = {
  resourceGroup: string
  namespace: string
  name: string?
  policyName: string?
  logs: string[]?
}

param settings settingsType = {
  logAnalytics: {
    name: '<TO BE REPLACED>'
    resourceGroup: '<TO BE REPLACED>'
    logs: [
      'Administrative'
    ]
  }
}

var settingsObject = {
  logAnalytics: {
    name: ''
    resourceGroup: ''
    logs: []
  }
  eventHub: {
    namespace: ''
    resourceGroup: ''
    policyName: 'RootManageSharedAccessKey'
    logs: []
  }
}

resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2022-10-01' existing = if (!empty(union(settingsObject, settings).logAnalytics.name)) {
  name: empty(union(settingsObject, settings).logAnalytics.name) ? 'something' : union(settingsObject, settings).logAnalytics.name
  scope: resourceGroup(settings.logAnalytics!.resourceGroup)
}

resource logsAndMetricsToLogAnalytics 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = if (!empty(union(settingsObject, settings).logAnalytics.name)) {
  name: 'subscriptionLogs1'
  properties: {
    workspaceId: logAnalyticsWorkspace.id
    logs: [for log in union(settingsObject, settings).logAnalytics.logs: {
      category: log
      enabled: true
    }]
  }
}

resource eventHub 'Microsoft.EventHub/namespaces@2022-10-01-preview' existing = if (!empty(union(settingsObject, settings).eventHub.namespace)) {
  name: empty(union(settingsObject, settings).eventHub.namespace) ? 'something' : union(settingsObject, settings).eventHub.namespace
  scope: resourceGroup(union(settingsObject, settings).eventHub.resourceGroup)
}

resource eventHubAuthorizationRule 'Microsoft.EventHub/namespaces/authorizationRules@2022-10-01-preview' existing = if (!empty(union(settingsObject, settings).eventHub.namespace)) {
  name: union(settingsObject, settings).eventHub.policyName
  parent: eventHub
}

resource logsAndMetricsToEventHub 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = if (!empty(union(settingsObject, settings).eventHub.namespace)) {
  name: 'subscriptionLogs2'
  properties: {
    eventHubAuthorizationRuleId: eventHubAuthorizationRule.id
    eventHubName: null
    logs: [for log in union(settingsObject, settings).eventHub.logs: {
      category: log
      enabled: true
    }]
  }
}

But overall that is workaround to what it seems is like some bug to behavior that should not change from adding user-defined types.

Additional context Add any other context about the problem here.

anthony-c-martin commented 6 months ago

Thanks for raising this. Here's a minimal repro:

type foo = {}

resource eventHub 'Microsoft.EventHub/namespaces@2022-10-01-preview' existing = if (false) {
  name: ''
}

The behavior is the same for non-existing resources in non-symbolicname templates:

resource eventHub 'Microsoft.EventHub/namespaces@2022-10-01-preview' = if (false) {
  name: ''
}

@alex-frankel I believe this is related to the condition-false problem we discussed recently, although I couldn't find an existing open issue to link it to.

jeskew commented 6 months ago

Possible duplicate of #12204

alex-frankel commented 5 months ago

Adding internal work item for tracking: https://msazure.visualstudio.com/One/_workitems/edit/27778828