Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
jurjenoskam opened this issue Feb 12, 2024 · 3 comments

Comments

@jurjenoskam
Copy link

jurjenoskam commented Feb 12, 2024

Bicep version
Bicep CLI version 0.24.24 (5646341)

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:

  • references that can be computed at template compilation time do not end up as references in the ARM template at all, they are simply replaced by a value like [variables('sqlServerName')] (in the first example template above). This type of reference will work even when the referred-to resource does not even exist.
  • references that can't be computed do end up as references in the ARM template using the reference() function. This type of reference will fail if the referred-to resource does not exist.

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
Copy link
Contributor

jeskew commented Feb 13, 2024

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
Copy link
Contributor

This is by design and explained further in the above comment

@github-project-automation github-project-automation bot moved this from Todo to Done in Bicep Feb 21, 2024
@jurjenoskam
Copy link
Author

Even though this was marked as wontfix because the behavior is by design, #15447 has now made it possible (for languageVersion 2.0 templates only!) to specify that an existing resource must actually exist by making it the target of an explicit dependsOn.

The following template will still successfully deploy and will output resource IDs of resources that do not exist, as there's no explicit dependsOn:

#disable-next-line no-unused-params
param foo string?  // this is only here to force templateVersion 2.0

resource uami1 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' existing = {
  name: 'does-not-exist'
}

resource uami2 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' existing = {
  name: 'does-not-exist-as-well'
}

output uami1Id string = uami1.id
output uami2Id string = uami2.id

The following template has an explicit dependsOn and will now (after #15447) fail to deploy because the depended-on resource does not exist:

#disable-next-line no-unused-params
param foo string?  // this is only here to force templateVersion 2.0

resource uami1 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' existing = {
  name: 'does-not-exist'
}

resource uami2 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' existing = {
  name: 'does-not-exist-as-well'
  dependsOn: [  // with https://github.com/Azure/bicep/pull/15447 this now results in a failure to deploy when uami1
    uami1       // does not exist (but only in templateVersion 2.0 templates)
  ]
}

output uami1Id string = uami1.id
output uami2Id string = uami2.id

Again, note that this only applies to languageVersion 2.0 templates! Leaving out the param foo string? from the examples above will always result in a successful deployment and the output containing resource IDs of resources that do not exist, despite the second example having an explicit dependsOn.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Archived in project
Development

No branches or pull requests

3 participants