mkcoding
mkcoding

Reputation: 135

ARM Template Deployment: DeploymentNotFound Error When Using reference() function for Conditional Deployment

I have an main ARM template, let's call it azuredeploy.json, and a linked template, let's call it privateEndpoint.json. I have a parameter that determines whether or not the resource will be deployed, let's call it enablePrivateEndpoints. It is currently set to 'false' so the deployment for this resource does not occur.

In the opposite case the output from 'privateEndpoint.json' should be read to get the networkInterface id of the private endpoint.

azuredeploy.json

{
            "condition": "[not(equals(parameters('enablePrivateEndpoints'), 'false'))]",
            "name": "keyvault-privateendpoint",
            "type": "Microsoft.Resources/deployments",
            "apiVersion": "2019-10-01",
            "dependsOn": [
                "keyvault"
            ],
            "properties": {
                "mode": "Incremental",
                "templateLink": {
                "uri": "[concat(variables('templateFolderUrl'), '/', variables('privateEndpointTemplateFileName'), parameters('_artifactsLocationSasToken'))]"
                },
                "parameters": {
                ...
...
                "enablePrivateEndpoints": "[parameters('enablePrivateEndpoints')]"
                }
            }
        },
},
{
            "condition": "[not(equals(parameters('enablePrivateEndpoints'), 'false'))]",
            "name": "networkInterface-kv",
            "type": "Microsoft.Resources/deployments",
            "apiVersion": "2019-10-01",
            "properties": {
                "mode": "Incremental",
                "templateLink": {
                "uri": "[concat(variables('templateFolderUrl'), '/', variables('networkInterfaceTemplateFileName'), parameters('_artifactsLocationSasToken'))]"
                },
                "parameters": {
                    "networkInterfaceId": {
                        "value": "[reference('keyvault-privateendpoint', '2021-04-01').outputs.networkInterfaceId.value]"
                    }
                }
            }
        }

privateEndpoint.json

...
"enablePrivateEndpoints": {
      "type": "string"
    }
    },
    "variables": {},    
    "resources": [
        {
            "name": "[parameters('privateEndpointName')]",
            "type": "Microsoft.Network/privateEndpoints",
            "apiVersion": "2021-04-01",
            "location": "[resourceGroup().location]",
            "dependsOn": [],
            "properties": "[parameters('privateEndpointProperties')]"
        }
    ],
    "outputs": {
      "networkInterfaceId": {
        "condition": "[not(equals(parameters('enablePrivateEndpoints'), 'false'))]",
        "type": "string",
        "value": "[reference(resourceId('Microsoft.Network/privateEndpoints', parameters('privateEndpointName'))).networkInterfaces[0].id]"
      }
    }

The issue lies in this piece of code:

"networkInterfaceId": {
                        "value": "[reference('keyvault-privateendpoint', '2021-04-01').outputs.networkInterfaceId.value]"
                    }

The reference function is still being evaluated despite the condition stopping the deployment of the referenced resource. The deployment fails with "DeploymentNotFound: The deployment 'keyvault-privateendpoint' could not be found"

Here are some things I've tried to fix this issue:

Attempt #1

You can see already I have tried to add a condition to the output itself

"outputs": {
      "networkInterfaceId": {
        "condition": "[not(equals(parameters('enablePrivateEndpoints'), 'false'))]",
        "type": "string",
        "value": "[reference(resourceId('Microsoft.Network/privateEndpoints', parameters('privateEndpointName'))).networkInterfaces[0].id]"
      }
    }

This did not fix the issue

Attempt #2

I tried adding an if to the value that's looking at the output itself, only to evaluate the reference function if the enablePrivateEndpoints parameter is true.

"networkInterfaceId": {
                        "value": "[if(parameters(enablePrivateEndpoints), reference('keyvault-privateendpoint', '2021-04-01').outputs.networkInterfaceId.value, '')]"
                    }

This also did not fix the issue.

I don't understand why the non-existent deployment is still being attempted to be referenced.

I mean even the deployment resource itself that is doing the referencing is conditional under the same parameter.

Note: These resources haven't been successfully deployed yet, so they are new.

Upvotes: 1

Views: 2344

Answers (2)

mkcoding
mkcoding

Reputation: 135

I found out what the issue is. When using conditional deployments, this doesn't mean the reference function will not be evaluated, as it is a runtime function.

You have to put an additional if on anywhere the reference function is being used in a conditional deployment if you don't want it's evaluation to occur at deployment.

This includes at the output.

See below, the linked template's output now has an if: privateEndpoint.json

"networkInterfaceId": {
        "condition": "[equals(parameters('enablePrivateEndpoints'), 'true')]",
        "type": "string",
        "value": "[if(equals(parameters('enablePrivateEndpoints'), 'true'), reference(resourceId('Microsoft.Network/privateEndpoints', parameters('privateEndpointName'))).networkInterfaces[0].id, '1')]"

Then in the main deployment arm template, the reference function again is put behind an if: azuredeploy.json

"networkInterfaceId": {
                        "value": "[if(equals(parameters('enablePrivateEndpoints'), 'true'), reference('keyvault-privateendpoint', '2021-04-01').outputs.networkInterfaceId.value, '1')]"
                    }

Upvotes: 2

Nancy Xiong
Nancy Xiong

Reputation: 28294

Try to use

"networkInterfaceId": 
{
                    
"value": "[if(not(equals(parameters('enablePrivateEndpoints'), 'false')), reference('keyvault-privateendpoint', '2021-04-01').outputs.networkInterfaceId.value , '')]"
}

in the parameters of resource "type": "Microsoft.Resources/deployments".

Upvotes: 1

Related Questions