0
votes

I am trying to figure out how nested templates work and I have the below templates. I am trying to deploy from VS using the VS deploy mechanism:

  1. Right click on the project > Deploy > New
  2. "Artifact storage account" field is prepopulated with "Automatically create a storage account" and I leave it like that
  3. Click on Deploy button

If you take a look in HelloWorldParent.json template in variables you will see two variables "nestedTemplateUri" and "nestedTemplateUriWithBlobContainerName".

It is my understanding that "nestedTemplateUri" should contain the "blob container name" but that doesn't seem to be the case.

If I deploy with resources > properties > templateLink > "uri": "[variables('nestedTemplateUri')]"

  • The deployment fails with:

Error: Code=InvalidContentLink; Message=Unable to download deployment content from 'https://********.blob.core.windows.net/NestedTemplates/HelloWorld.json?sv=2017-07-29&sr=c&sig=ZCJAoOdp08qDWxbzKbXSZzX1VBCf7%2FNSt4aIznFCTPQ%3D&se=2019-03-12T03:39:09Z&sp=r'

  • The Storage Account is created, the templates, parameters and PS1 script are uploaded
  • A new deployment is not created in resource group / deployments

If I deploy with resources > properties > templateLink > "uri": "[variables('nestedTemplateUriWithBlobContainerName')]"

  • The deployments succeeds.

Any idea? Any help is highly appreciated!

HelloWorldParent.json

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "_artifactsLocation": {
      "type": "string",
      "metadata": {
        "description": "The base URI where artifacts required by this template are located including a trailing '/'"
      }
    },
    "_artifactsLocationSasToken": {
      "type": "securestring",
      "metadata": {
        "description": "The sasToken required to access _artifactsLocation.  When the template is deployed using the accompanying scripts, a sasToken will be automatically generated. Use the defaultValue if the staging location is not secured."
      },
      "defaultValue": ""
    }
  },
  "variables": {
    "blobContainerName": "[concat(resourceGroup().name, '-stageartifacts/')]",
    "nestedTemplateUriWithBlobContainerName": "[uri(parameters('_artifactsLocation'), concat(variables('blobContainerName'), 'NestedTemplates/HelloWorld.json', parameters('_artifactsLocationSasToken')))]",
    "nestedTemplateUri": "[uri(parameters('_artifactsLocation'), concat('NestedTemplates/HelloWorld.json', parameters('_artifactsLocationSasToken')))]"
  },
  "resources": [
    {
      "apiVersion": "2017-05-10",
      "name": "linkedTemplate",
      "type": "Microsoft.Resources/deployments",
      "properties": {
        "mode": "incremental",
        "templateLink": {
          "uri": "[variables('nestedTemplateUri')]",
          "contentVersion": "1.0.0.0"
        }
      }
    }
  ],
  "outputs": {
    "messageFromLinkedTemplate": {
      "type": "string",
      "value": "[reference('linkedTemplate').outputs.greetingMessage.value]"
    },
    "_artifactsLocation": {
      "type": "string",
      "value": "[parameters('_artifactsLocation')]"
    }
  }
}

HelloWorldParent.parameters.json

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
  }
}

NestedTemplates/HelloWorld.json

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {},
  "variables": {},
  "resources": [],
  "outputs": {
    "greetingMessage": {
      "value": "Hello World (1)",
      "type": "string"
    }
  }
}
1
your problem is not nested templates, its vs.4c74356b41

1 Answers

2
votes

Unfortunately VS is a bit "dated" in it's support for your scenario... the problem is that you're using the URI function and the _artifactsLocation does not have a trailing slash. So you have a few options to fix:

1) in the PS1 file in VS there is a line that looks like this:

$OptionalParameters[$ArtifactsLocationName] = $StorageAccount.Context.BlobEndPoint + $StorageContainerName

If you change it to this (add a trailing /):

$OptionalParameters[$ArtifactsLocationName] = $StorageAccount.Context.BlobEndPoint + $StorageContainerName + "/"

It should work - alternatively you can just replace the entire script with this one: https://github.com/Azure/azure-quickstart-templates/blob/master/Deploy-AzureResourceGroup.ps1

Note that if you have other templates that work without the trailing slash, this will be a breaking change.

2) use concat() to create the uri instead of the uri() function. You still have to know whether there is a trailing slash but this change can be done in the template and not the PS1 file.

   "nestedTemplateUri": "[concat(parameters('_artifactsLocation'), '/NestedTemplates/HelloWorld.json', parameters('_artifactsLocationSasToken'))]"

Either should work.