Azure / bicep

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

Lambdas do not support resource references #14106

Open anthony-c-martin opened 4 months ago

anthony-c-martin commented 4 months ago

@anthony-c-martin I could not find the documentation for the new function features published yet but there are examples here in this PR. However for one of the main reasons to have index for lambda functions was to be able to access resource arrays and I have found out that this is not possible. Any idea why this was not done? It seems only half of the job was done.

properties: {
      actionGroups: map(eventSubscription.destination.actionGroups, (actionGroup, i) => actionGroups[i].id)
    }

shows error:


Using lambda variables inside resource or module array access is not currently supported. Found the following lambda variable(s) being accessed: "i".bicep(BCP247)

Originally posted by @slavizh in https://github.com/Azure/bicep/issues/13658#issuecomment-2117258414

anthony-c-martin commented 4 months ago

The challenge originally was that the deployment engine requires the reference() function parameters to be evaluable at the start of the deployment, in order to accurately build the deployment graph.

Now that we have symbolic names, it may be possible to revisit and relax this requirement, because there is no ambiguity about what a reference function call refers to, and Bicep will also emit the correct dependsOn statement.

For example:

param account {
  name: string
}

resource loop 'Microsoft.Storage/storageAccounts@2022-09-01' = [for i in range(0, 10): {
  name: 'loop${i}'
  location: resourceGroup().location
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'StorageV2'
  properties: {}
}]

resource sa 'Microsoft.Storage/storageAccounts@2022-09-01' = {
  name: account.name
  location: resourceGroup().location
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'StorageV2'
  properties: {
    // would result in the following dependsOn: "[format('loop[{0}]', 0)]"
    test: loop[0].properties.test
    // could result in the following dependsOn: "loop"
    test2: map(loop, x => x.properties.test)
  }
}

As long as Bicep builds the correct dependency graph, all good. If it doesn't, then things will fail in a very cryptic way. I do think this is something we could enforce during codegen however, so the cryptic failures would be limited to people authoring lambdas in ARM JSON templates.

There is a similar problem with list function calls - this is more tricky, because there is no symbolic reference to a "list". I don't think we'd be able to remove the restriction here.

slavizh commented 4 months ago

I think at least this should be allowed for properties like .id and .name as they do not require reference() they only need resourceId(). Symbolic naming seems good only when it relates to using reference() in the past but it somehow creates more pain when it is used only for the .id. At least that is my impression.

cedricbraekevelt commented 4 months ago

This would make us less dependent on foreach for referencing outputs. Would be a great improvement if possible!

slavizh commented 1 day ago

@anthony-c-martin any chance this gets fixed soon? It would open quite the cases with being able to loop over Key Vault secrets and convert the array to object as currently you have secure decorator only on objects and strings. Quite often we have resources that have array properties and within array you need to put a secret from key vault. In such cases you either need to ask the secret to be passed in plain text which is not good or ask for one secret for which the value is stored as json object so you can get the secret as string, convert it to json and use it within the array.