Azure / bicep

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

"The resource X is defined multiple times in a template" error after enabling user defined types #9457

Closed jeskew closed 1 year ago

jeskew commented 1 year ago

After enabling custom types and getting everything to compile, when actually deploying to azure, I get these new errors:

{'code': 'MultipleErrorsOccurred', 'message': 'Multiple error occurred: BadRequest,BadRequest,BadRequest. Please see details.'}

Inner Errors:
{'code': 'InvalidTemplate', 'target': '/subscriptions/******/resourceGroups/my-test/providers/Microsoft.Resources/deployments/vnet', 'message': "Deployment template validation failed: 'The resource 'Microsoft.Network/networkSecurityGroups/nsg-uniun-dev-we-01' at line '1' and column '5055' is defined multiple times in a template. Please see https://aka.ms/arm-template/#resources for usage details.'.", 'additionalInfo': [{'type': 'TemplateViolation', 'info': {'lineNumber': 1, 'linePosition': 5055, 'path': 'properties.template.resources.newNsg'}}]}

Inner Errors:
{'code': 'InvalidTemplate', 'target': '/subscriptions/******/resourceGroups/my-test/providers/Microsoft.Resources/deployments/appGatewayPublicIp', 'message': "Deployment template validation failed: 'The resource 'Microsoft.Network/publicIPAddresses/pip-uniun-agw-dev-we-01' at line '1' and column '1542' is defined multiple times in a template. Please see https://aka.ms/arm-template/#resources for usage details.'.", 'additionalInfo': [{'type': 'TemplateViolation', 'info': {'lineNumber': 1, 'linePosition': 1542, 'path': 'properties.template.resources.existingPublicIp'}}]}

Inner Errors:
{'code': 'InvalidTemplate', 'target': '/subscriptions/******/resourceGroups/my-test/providers/Microsoft.Resources/deployments/loadBalancerPublicIp', 'message': "Deployment template validation failed: 'The resource 'Microsoft.Network/publicIPAddresses/pip-uniun-lbe-dev-we-01' at line '1' and column '1546' is defined multiple times in a template. Please see https://aka.ms/arm-template/#resources for usage details.'.", 'additionalInfo': [{'type': 'TemplateViolation', 'info': {'lineNumber': 1, 'linePosition': 1546, 'path': 'properties.template.resources.existingPublicIp'}}]}

Undoing my refactoring of custom types resolves this issue again. I can't see any duplicate definition of the resources mentioned..

Originally posted by @dazinator in https://github.com/Azure/bicep/issues/4158#issuecomment-1372506910

jeskew commented 1 year ago

@dazinator This is likely an issue with symbolic name templates (which custom types require). Could you try deploying the template with symbolic name codegen enabled but types disabled? For example, using a config like:

{
  "experimentalFeaturesEnabled": {
    "symbolicNameCodegen": true
  }
}
anthony-c-martin commented 1 year ago

Would you mind also sharing the Bicep file you're using to deploy (if you're able to)?

dazinator commented 1 year ago

@jeskew Yes enabling symbolic name code gen - without any use of custom types, is enough to reproduce my problem..

@anthony-c-martin It's rather large with a lot of module, could possibly share it over a private channel if you could suggest one, but I can't post it here at present. UPDATE: Have commented below with example bicep code that causes the bug.

dazinator commented 1 year ago

@jeskew @anthony-c-martin ok I have figured out what is causing the error with symbolicNameCodeGen turned on. I use the following pattern in a few templates - to control whether an existing resource is looked up, or a new one create:

@description('name of the NSG that will be created for the swarm subnet. If this name is specified and createNsg = true, an NSG will be created, otherwise if this name is specified and createNsg is false, the existing named NSG will be used.')
param swarmSubnetNsgName string  = ''

@description('Whether the NSG with a name specified with the swarmSubnetNsgName param, will be created, or wether it exists already. If swarmSubnetNsgName is not specified then this param has no effect.')
param createNsg bool  = true

resource newNsg 'Microsoft.Network/networkSecurityGroups@2022-05-01' = if(createNsg && !empty(swarmSubnetNsgName)) {
  name: swarmSubnetNsgName
  location: location  
}

resource existingNsg 'Microsoft.Network/networkSecurityGroups@2022-05-01' existing = if(!createNsg && !empty(swarmSubnetNsgName)) {
  name: swarmSubnetNsgName
}

If i comment out the resource existingNsg in this example, stuff works. It seemingly doesn't like this pattern. The reason I use this pattern for example for public ip addresses - when deploying new environments its fine to create new public ip's, but I also intend to deploy this in place of existing environments in future, and we'll want to re-use the same ip's that we already have in play, so where this is the case, I have a parameter indicating whether to create a new ip or lookup an existing one. In general though I have found its helpful for modules to auto create related resources, but also offer flexibility so if you want to contol creation of that resource yourself (outside the module) you can do, and then the module can look it up as an existing resource (after you've created it) if necessary, rather than take ownership of its creation.

levimatheri commented 1 year ago

I'm encountering similar issue, with the following error: InvalidTemplate - Deployment template validation failed: 'The template resource '<rg>/<product>/<APIM instance>/<api name>' for type 'Microsoft.ApiManagement/service/products/apis' at line '1' and column '12767' has incorrect segment lengths. A nested resource type must have identical number of segments as its resource name. A root resource type must have segment length one greater than its resource name. Please see https://aka.ms/arm-template/#resources for usage details.'.

I tried with:

"experimentalFeaturesEnabled": {
    "userDefinedTypes": true
  }

..and

"experimentalFeaturesEnabled": {
    "symbolicNameCodegen": true
  }

... with no success. However, if I remove experimentalFeaturesEnabled altogether, the deployment works!

I have an existing resource in my main api module defined like this:

resource productResourceNames 'Microsoft.ApiManagement/service/products@2021-08-01' existing = [for i in range(0, length(products)): {
  parent: service
  name: products[i]
}]

// API products
resource api_product 'Microsoft.ApiManagement/service/products/apis@2021-08-01' = [for i in range(0, length(products)): {
  name: api.name
  parent: productResourceNames[i]
}]
tstooke commented 1 year ago

@dazinator This is likely an issue with symbolic name templates (which custom types require). Could you try deploying the template with symbolic name codegen enabled but types disabled? For example, using a config like:

@jeskew

Ah, I've been in a battle with Bicep and PSRule over the last week, and I didn't realize that Custom Types requires the Symbolic Name feature. I finally figured it out when I turned off the Custom Types feature and compared the resulting ARM template files, and this issue confirmed it.

I did notice that the Symbolic Names warning came up when I enabled the Custom Type feature, but I just ignored it because I thought I wasn't using that feature (by not explicitly enabling it).

Do you think we could we get a mention that the Custom Types feature requires the Symbolic Names feature here or here, please? This could save others a lot of headaches, I think.

Thanks for all the great work you're doing on this fantastic project!

jeskew commented 1 year ago

The fix for this is in the w16 ARM release.

jeskew commented 1 year ago

w16 has finished rolling out everywhere