Azure / bicep

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

A dependency on an `existing` resource doesn't actually require the resource to exist #13325

Closed jurjenoskam closed 8 months ago

jurjenoskam commented 8 months ago

Bicep version Bicep CLI version 0.24.24 (5646341b0c)

Describe the bug (This is somewhat related to #2716, but is about a different use case and scenario.)

Some, but not all, references to existing resources will work just fine even if the referred-to resource doesn't exist at all:

var sqlServerName = 'anythinggoes'

resource sqlServer 'Microsoft.Sql/servers@2021-11-01' existing = {
  name: sqlServerName
}

output demo string = sqlServer.name

This template will work for any value of sqlServerName (or more precisely: any value that meets the naming restrictions for SQL Server resources).

This is a problem because I'm trying to do something like this (pseudocode), which silently doesn't work:

resource sqlServer 'Microsoft.Sql/servers@2021-11-01' existing = {
  name: 'foo'
}

resource scriptToRunOnSqlServer 'Microsoft.Resources/deploymentScripts@2023-08-01' = {
  name: 'bar'
  dependsOn: [ sqlServer ]
  kind: 'AzureCLI'
  properties: {
    scriptContent: 'echo Do something with the SQL Server resource'
  }
}

My expectation is that scriptToRunOnSqlServer does not deploy if sqlServer does not exist. In reality the deploymentScript does deploy.

Worse, it will also fail an case of an implicit dependency, e.g. when the deployment script resource does not have the explicit dependsOn but includes sqlServer.name somewhere in its definition. That will just run the deployment script as if there's a server with that name, even though it doesn't exist at all.

Further background Looking at the resulting ARM, it turns out that there are two types of references to existing resources, and they behave differently:

This difference is completely invisible in the Bicep template (other than that you can only use references of the first type in certain locations, but that's beside the point here) . Only at deployment time the difference has an effect. This is undocumented and unintuitive. Things would be much more consistent if a dependency (either explicit or implicit) on an existing resource always results a reference() to the target resource.

jeskew commented 8 months ago

There are a couple quirks of the ARM platform that you're running in to.

The first is that dependsOn is more of an ordering directive than it is a precondition: a resource that depends on another will not start deploying until the depended upon resource has successfully finished deploying, but resources can only depend on resources deployed in the same template. Bicep allows you to declare this dependency because some but not all versions of ARM templates allow you to declare existing resources (on which you can declare a dependency). If Bicep is targeting an earlier version of the ARM template language, then the dependency is dropped.

The second is that existing resources are only fetched if their properties are accessed. (This is true regardless of the ARM template version targeted.) There is some more discussion/detail on why that is the case in #10097.

stephaniezyen commented 8 months ago

This is by design and explained further in the above comment