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

Resource reference in a resource #565

Closed
omiossec opened this issue Sep 25, 2020 · 13 comments
Closed

Resource reference in a resource #565

omiossec opened this issue Sep 25, 2020 · 13 comments
Labels
enhancement New feature or request provider bug

Comments

@omiossec
Copy link

Is your feature request related to a problem? Please describe.
Some resource such as Load Balancer or Application Gateway have circular reference in a resource

"frontendIPConfiguration": {
                                "id": "[concat(resourceId('Microsoft.Network/applicationGateways', parameters('applicationGatewatName')), '/frontendIPConfigurations/appGwPublicFrontendIp')]"
    },

but it's not possible to use this form in bicep

resource appGateway 'Microsoft.Network/applicationGateways@2020-05-01' = {
  name: appGatewayName
  location: defaultLocation
//
 frontendIPConfiguration: {
                    id: appGateway.ID //
                }
//

It give a  Error BCP061: The expression is involved in a cycle.

**Describe the solution you'd like**
Allow a resource to reference them self
@omiossec omiossec added the enhancement New feature or request label Sep 25, 2020
@ghost ghost added the Needs: Triage 🔍 label Sep 25, 2020
@alex-frankel
Copy link
Collaborator

Is that frontendIPConfiguration.id property required? What happens if you don't include it? It seems very strange for the resource to need its own resource ID..

@slavizh
Copy link
Contributor

slavizh commented Sep 28, 2020

Yes it is needed as far as I know. We use it the same way. There are even strange cases like virtual wan where you have Microsoft.Network/vpnGateways where you have connections which should be empty upon first deployment but filled on next deployments when you have vpn connections. This leads you to do workarounds like checking if the VPN gateway is already deployed or not and if it has vpn connections created or not. If the VPN Gateway exists and have vpn connection you have to take the value of connections from it via reference and deploy it with that value. You cannot fill that value on your own as you basically upon every deployment you need to know which VPN connections are already deployed and which are yet to deployed. You can get the current ones only via reference to the resources itself.

Just ordinary problems with RPs :)

@alex-frankel
Copy link
Collaborator

To unblock you in the meantime, you can use the resourceId() function directly to dodge our cycle detection logic. So something like this:

resource appGateway 'Microsoft.Network/applicationGateways@2020-05-01' = {
  name: appGatewayName
  location: defaultLocation
  ...
  frontendIPConfiguration: {
    id: resourceId('Microsoft.Network/applicationGateway', appGatewayName) 
  }

Not ideal, but it should work. Let us know if you have any questions.

@sebader
Copy link
Member

sebader commented Jan 25, 2021

I came across the same issue with FrontDoor (another Microsoft.Network RP...)

resource frontdoor 'Microsoft.Network/frontDoors@2020-05-01' = {
  name: frontDoorName
  location: 'Global'
  properties: {
    healthProbeSettings: [
      {
        name: 'HealthProbeSetting'
        properties: {
          healthProbeMethod: 'HEAD'
          path: '/healthcheck'
          protocol: 'Https'
          intervalInSeconds: 30
        }
      }
    ]
    backendPools: [
      {
        name: 'BackendApis'
        properties: {
          backends: frontDoorBackends
          healthProbeSettings: {
            id: '${resourceId('Microsoft.Network/frontDoors', frontDoorName)}/healthProbeSettings/HealthProbeSetting' 
                // <-- here I would like to able to instead use '${frontdoor.id}/healthProbeSettings/HealthProbeSetting'
          }

@anthony-c-martin
Copy link
Member

It's quite a niche case, but I do think it would be safe to skip the cycle detection logic for a deploy-time constant self-reference (e.g. res.id, res.type, res.name & res.apiVersion)

@sebader
Copy link
Member

sebader commented Jan 25, 2021

of course, what I would really like to be able to do - and I'm not sure if this would be even remotely possible with Bicep:

healthProbeSettings: {
            id: frontdoor.properties.healthProbeSettings.Where(s => s.name == 'HealthProbeSetting') // And have compile-time validation that a setting with the name HealthProbeSetting exists
          }

:)

@alex-frankel
Copy link
Collaborator

it would be safe to skip the cycle detection logic for a deploy-time constant self-reference (e.g. res.id, res.type, res.name & res.apiVersion)

+1!

@majastrz
Copy link
Member

+1 as well.

@askew
Copy link

askew commented Apr 23, 2021

Application Gateway in particular has a lot of cross references to child items. These child items are all arrays. Solving this issue along with #1853 would be great.

Could you directly reference other properties (that are in included in bicep document and therefore deploy-time constant)?

What would be really nice is if instead of ...

...
    httpListeners: [
      {
        name: 'httpListener'
        properties: {
          protocol: 'Http'
          frontendIPConfiguration: {
            id: resourceId('Microsoft.Network/applicationGateways/frontendIPConfigurations', appgwname, 'public')
          }
          frontendPort: {
            id: resourceId('Microsoft.Network/applicationGateways/frontendPorts', appgwname, 'httpPort')
          }
        }
      }
...

you could have:

...
    httpListeners: [
      {
        name: 'httpListener'
        properties: {
          protocol: 'Http'
          frontendIPConfiguration: {
            id: frontendIPConfigurations['public'].id
          }
          frontendPort: {
            id: frontendPorts['httpPort'].id
          }
        }
      }
...

@anthony-c-martin
Copy link
Member

Also worth mentioning that we could potentially simplify this in conjunction with #2245 - to use the above example, I'd imagine something like (assuming we have a this or similar keyword):

...
    httpListeners: [
      {
        name: 'httpListener'
        properties: {
          protocol: 'Http'
          frontendIPConfiguration: {
            id: this.child('frontendIPConfigurations', 'public').id
          }
          frontendPort: {
            id: this.child('frontendPorts', 'httpPort').id
          }
        }
      }
...

@scottstout
Copy link

scottstout commented Jul 6, 2021

This bicep for an App Gateway(specifically the gatewayIPConfigurations) has only the name property (and not the id). This is how it should be done. The 'id' is automatically generated for you. However, if you accidentally supply the id (instead of the name), but leave an invalid id, it fails with InvalidRequestFormat, "Cannot parse the request." This is troublesome since VS Code doesn't complain in name is missing and doesn't tell you that the id is not properly formatted. I think the 'id' just needs to be removed from the bicep interpretation of the schema since it is generated when you deploy. The schema format is just ambiguous since it makes no distinction between generated properties and properties that need to be supplied. It seems like either name or id should be required.

https://github.com/Azure/bicep/blob/main/docs/examples/101/application-gateway-v2-autoscale-create/main.bicep

The schema is here, and contains both 'id' and 'name':
https://docs.microsoft.com/en-us/azure/templates/microsoft.network/applicationgateways?tabs=json

Here is the specific documentation on the gatewayIPConfigurations. Note that neither 'name' nor 'id' is required (according to the docs).
https://docs.microsoft.com/en-us/azure/templates/microsoft.network/applicationgateways?tabs=bicep#applicationgatewayipconfiguration-object

@ghost
Copy link

ghost commented Jan 18, 2022

Hi guys, I think I have a similar problem

]
virtualNetworkPeerings: [
{
name: '${virtualNetworks_az104_05_vnet2_name}_to_az104-05-vnet0'
properties: {
peeringState: 'Connected'
remoteVirtualNetwork: {
id: virtualNetworks_az104_05_vnet0_name_resource.id
}
allowVirtualNetworkAccess: true
allowForwardedTraffic: false
allowGatewayTransit: false
useRemoteGateways: false
remoteAddressSpace: {
addressPrefixes: [
'10.50.0.0/22'
]
}
}
}

  I received 
  resource virtualNetworks_az104_05_vnet0_name_resource

Microsoft.Network/virtualNetworks@2020-11-01
The expression is involved in a cycle ("virtualNetworks_az104_05_vnet0_name_resource" -> "virtualNetworks_az104_05_vnet1_name_resource" -> "virtualNetworks_az104_05_vnet2_name_resource").bicep(BCP080)

image

@alex-frankel
Copy link
Collaborator

Closing this as a dup of #1852

@ghost ghost locked as resolved and limited conversation to collaborators May 29, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or request provider bug
Projects
None yet
Development

No branches or pull requests

9 participants