Azure / arm-template-whatif

A repository to track issues related to what-if noise suppression
MIT License
88 stars 14 forks source link

What-If doesn't show difference whith user-defined data type & optional property #375

Open TiTi opened 1 month ago

TiTi commented 1 month ago

dedicated issue because not quite the same as #157

i found another weird case of wrong what-if with user-defined data type & optional property

Caller:

type vmInfosType = {
  name: string
  size: string
  hasSql: bool?
}

@description('Virtual machines to create')
param vmInfos vmInfosType

module vmModule '../azure-virtual-machine/vm.bicep' = {
  name: 'vm1'
  params: {
    location: location
    tags: tags
    name: vmInfos.name
    size: vmInfos.size
    // ...
    hasSql: vmInfos.hasSql
  }
}

Like so, the whatif result is empty!! No changes!

if you then replace the parameter hasSql like so when calling the module: hasSql: vmInfos.?hasSql

Then the what-if works as expected. 🤯 Crazy!

So make sure to use "?" anywhere you have an optionnal property!!

The difference in the generated arm json: what-if fails:

          "hasSql": {
            "value": "[variables('vmInfos').hasSql]"
          },

what-if works:

          "hasSql": {
            "value": "[tryGet(variables('vmInfos'), 'hasSql')]"
          },

i tested with current bicep version : Bicep CLI version 0.29.47 (132ade51bc)

Originally posted by @TiTi in https://github.com/Azure/arm-template-whatif/issues/157#issuecomment-2245648814

jeskew commented 3 weeks ago

That is a confusing user experience! This will be addressed by the work we're doing to address #157, though you're right that this isn't quite the same issue.

What's going on behind the scenes is that the mechanism used by What-If to enumerate resources in modules can't easily distinguish between an expression that will fail at runtime vs an expression that will fail until runtime. The latter is what #157 is tracking and covers cases like dereferencing properties of resources created earlier in the deployment.

For the case you describe, the [variables('vmInfos').hasSql] expression is failing because there is no .hasSql property. This will fail when the template is deployed, but what-if isn't sure if the expression failed because it is invalid or because it won't be evaluable until the deployment is under way. As a result, what-if 'short-circuits' the entire module (as described in #157). The [tryGet(variables('vmInfos'), 'hasSql')] expression will evaluate to null rather than raising an error, allowing what-if to proceed evaluating the nested module.

When the work currently under way for #157 is completed, the call to What-If will fail with the same error message that would have caused the deployment to fail later on. Rather than short-circuiting, you would get an accurate assessment that the deployment is not valid.