Azure / template-specs

MIT License
31 stars 4 forks source link

templateSpecId cannot be derived from resourceId() function if deploying at the subscriptionLevel scope #41

Open stweb1963 opened 3 years ago

stweb1963 commented 3 years ago

It would be convenient to derive the resourceId as

resourceId([resourceGroupName], 'Microsoft.Resources/templateSpecs/versions/', '[templateSpecName]', '[templateSpecVersion]'

This unfortunately is unsupported at the subscriptionScope so we are forced to use concat, etc to build the templateSpec resourceId. This then goes against the ARM Test Toolkit best practice test case 'IDs Should Be Derived From ResourceIDs' and 'ResourceIds should not contain' so we are force to exclude these tests.

Brief Example

{
  "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "templateSpecsResourceGroupName": { "type": "string" },
    "resourceGroupName": { "type": "string" }

  },
  "variables": {
    "location": "[deployment().location]",
    "templates": {
      "rg": {
        "name": "resourcegroups",
        "version": "0.1.0"
      }
    }
  },
  "resources": [
    {
      "name": "rg",
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2020-06-01",
      "location": "[variables('location')]",
      "properties": {
        "mode": "Incremental",
        "templateLink": {
          "id": "[resourceId(parameters('templateSpecsResourceGroupName'), 'Microsoft.Resources/templateSpecs', variables('templates').rg.name, variables('templates').rg.version)]"
        },
        "parameters": {
          "name": {
            "value": "[parameters('resourceGroupName')]"
          }
        }
      }
    }
  ],
  "outputs": {}
}
stweb1963 commented 3 years ago

THis would also imply and probably have more value when deploying to multiple subscriptions

resourceId('[subscriptionId]', [resourceGroupName], 'Microsoft.Resources/templateSpecs/versions/', '[templateSpecName]', '[templateSpecVersion]')

alex-frankel commented 3 years ago

You are right - this is a known issue with the resourceId() function. It is basically impossible to construct an RG-scoped resourceId in non-RG scoped deployments. The fix for this is in progress, so hoping it is resolved sometime in Feb of next year.

alex-frankel commented 3 years ago

BTW - you should be able to get around this by creating a nested deployment targeting a resource group with expressionEvaluationOptions.scope set to inner:

    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2019-10-01",
      "name": "test",
      "resourceGroup": "test",
      "properties": {
        "expressionEvaluationOptions": {
          "scope": "inner"
        },
        "mode": "Incremental",
        "template": {
          "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
          "contentVersion": "1.0.0.0",
          "functions": [],
          "resources": [
            // create deployment resource that references ts here and resourceId() should work like normal
          ]
        }
      }
    }

It's definitely a hack, so hopefully we can get this resolved quickly

stweb1963 commented 3 years ago

Definitely going to wait as this requires having the RG first

This would require an inline deployment of the RG, then the hack, then follow up with the deployments but we include a standard linked RG template which does all the proper tagging, etc

For now the pipeline passes in the root templateSpec resourcegroup id to create the base pointer for the versions which are derived from semantic versioning


 "templates": {
      "rg": "resourcegroups/versions/0.13.0",
      "bh": "bastionhosts/versions/0.4.0",
      "pip": "publicipaddresses/versions/0.6.0"
    },
    "baseTemplateSpecId": "[concat(parameters('pipelineVariables').templateSpecResourceGroupId,'/providers/Microsoft.Resources/templateSpecs/')]",
    "rgTemplateSpecId": "[concat(variables('baseTemplateSpecId'), variables('templates').rg)]",
    "pipTemplateSpecId": "[concat(variables('baseTemplateSpecId'), variables('templates').pip)]",
    "bhTemplateSpecId": "[concat(variables('baseTemplateSpecId'), variables('templates').bh)]",