Skip to content

Commit f379292

Browse files
authored
Merge pull request #50540 from edburns/edburns/linked-templates
#50539 On branch edburns/linked-templates try to improve readability
2 parents bb6cb89 + 3953343 commit f379292

File tree

1 file changed

+80
-56
lines changed

1 file changed

+80
-56
lines changed

articles/azure-resource-manager/templates/linked-templates.md

Lines changed: 80 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ ms.date: 12/11/2019
66
---
77
# Using linked and nested templates when deploying Azure resources
88

9-
To deploy complex solutions, you can break your template into many related templates, and then deploy them together through a main template. The related templates can be separate files or template syntax that is embedded within the main template. This article uses the term **linked template** to refer to a separate template file that is linked to from the main template. It uses the term **nested template** to refer to embedded template syntax within the main template.
9+
To deploy complex solutions, you can break your template into many related templates, and then deploy them together through a main template. The related templates can be separate files or template syntax that is embedded within the main template. This article uses the term **linked template** to refer to a separate template file that is referenced via a link from the main template. It uses the term **nested template** to refer to embedded template syntax within the main template.
1010

1111
For small to medium solutions, a single template is easier to understand and maintain. You can see all the resources and values in a single file. For advanced scenarios, linked templates enable you to break down the solution into targeted components. You can easily reuse these templates for other scenarios.
1212

@@ -86,11 +86,11 @@ The following example deploys a storage account through a nested template.
8686
}
8787
```
8888

89-
### Scope for expressions in nested templates
89+
### Expression evaluation scope in nested templates
9090

9191
When using a nested template, you can specify whether template expressions are evaluated within the scope of the parent template or the nested template. The scope determines how parameters, variables, and functions like [resourceGroup](template-functions-resource.md#resourcegroup) and [subscription](template-functions-resource.md#subscription) are resolved.
9292

93-
You set the scope through the `expressionEvaluationOptions` property. By default, the `expressionEvaluationOptions` property is set to `outer`, which means it uses the parent template scope. Set the value to `inner` to scope expressions to the nested template.
93+
You set the scope through the `expressionEvaluationOptions` property. By default, the `expressionEvaluationOptions` property is set to `outer`, which means it uses the parent template scope. Set the value to `inner` to cause expressions to be evaluated within the scope of the nested template.
9494

9595
```json
9696
{
@@ -152,14 +152,14 @@ The following template demonstrates how template expressions are resolved accord
152152
}
153153
```
154154

155-
The value of the variable changes based on the scope. The following table shows the results for both scopes.
155+
The value of `exampleVar` changes depending on the value of the `scope` property in `expressionEvaluationOptions`. The following table shows the results for both scopes.
156156

157-
| Scope | Output |
157+
| `expressionEvaluationOptions` `scope` | Output |
158158
| ----- | ------ |
159159
| inner | from nested template |
160160
| outer (or default) | from parent template |
161161

162-
The following example deploys a SQL server and retrieves a key vault secret to use for the password. The scope is set to `inner` because it dynamically creates the key vault ID and passes it as a parameter to the nested template.
162+
The following example deploys a SQL server and retrieves a key vault secret to use for the password. The scope is set to `inner` because it dynamically creates the key vault ID (see `adminPassword.reference.keyVault` in the outer templates `parameters`) and passes it as a parameter to the nested template.
163163

164164
```json
165165
{
@@ -209,6 +209,22 @@ The following example deploys a SQL server and retrieves a key vault secret to u
209209
"expressionEvaluationOptions": {
210210
"scope": "inner"
211211
},
212+
"parameters": {
213+
"location": {
214+
"value": "[parameters('location')]"
215+
},
216+
"adminLogin": {
217+
"value": "ghuser"
218+
},
219+
"adminPassword": {
220+
"reference": {
221+
"keyVault": {
222+
"id": "[resourceId(parameters('vaultSubscription'), parameters('vaultResourceGroupName'), 'Microsoft.KeyVault/vaults', parameters('vaultName'))]"
223+
},
224+
"secretName": "[parameters('secretName')]"
225+
}
226+
}
227+
},
212228
"template": {
213229
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
214230
"contentVersion": "1.0.0.0",
@@ -244,22 +260,6 @@ The following example deploys a SQL server and retrieves a key vault secret to u
244260
"value": "[reference(variables('sqlServerName')).fullyQualifiedDomainName]"
245261
}
246262
}
247-
},
248-
"parameters": {
249-
"location": {
250-
"value": "[parameters('location')]"
251-
},
252-
"adminLogin": {
253-
"value": "ghuser"
254-
},
255-
"adminPassword": {
256-
"reference": {
257-
"keyVault": {
258-
"id": "[resourceId(parameters('vaultSubscription'), parameters('vaultResourceGroupName'), 'Microsoft.KeyVault/vaults', parameters('vaultName'))]"
259-
},
260-
"secretName": "[parameters('secretName')]"
261-
}
262-
}
263263
}
264264
}
265265
}
@@ -271,7 +271,7 @@ The following example deploys a SQL server and retrieves a key vault secret to u
271271

272272
> [!NOTE]
273273
>
274-
> When scope is set to `outer`, you can't use the `reference` function in the outputs section of a nested template for a resource you have deployed in the nested template. To return the values for a deployed resource in a nested template, either use inner scope or convert your nested template to a linked template.
274+
> When scope is set to `outer`, you can't use the `reference` function in the outputs section of a nested template for a resource you have deployed in the nested template. To return the values for a deployed resource in a nested template, either use `inner` scope or convert your nested template to a linked template.
275275

276276
## Linked template
277277

@@ -302,9 +302,18 @@ To link a template, add a [deployments resource](/azure/templates/microsoft.reso
302302
}
303303
```
304304

305-
You can't specify a local file or a file that is only available on your local network. You can only provide a URI value that includes either **http** or **https**. Resource Manager must be able to access the template. One option is to place your linked template in a storage account, and use the URI for that item.
305+
When referencing a linked template, the value of `uri` must not be a local file or a file that is only available on your local network. You must provide a URI value that downloadable as **http** or **https**.
306+
307+
> [!NOTE]
308+
>
309+
> You may reference templates using parameters that ultimately resolve
310+
> to something that uses **http** or **https**, for example, using the
311+
> `_artifactsLocation` parameter like so:
312+
> `"uri": "[concat(parameters('_artifactsLocation'), '/shared/os-disk-parts-md.json', parameters('_artifactsLocationSasToken'))]",`
313+
306314

307-
You don't have to provide the `contentVersion` property for the template or parameters. If you don't provide a content version value, the current version of the template is deployed. If you provide a value for content version, it must match the version in the linked template; otherwise, the deployment fails with an error.
315+
316+
Resource Manager must be able to access the template. One option is to place your linked template in a storage account, and use the URI for that item.
308317

309318
### Parameters for linked template
310319

@@ -319,12 +328,12 @@ You can provide the parameters for your linked template either in an external fi
319328
"properties": {
320329
"mode": "Incremental",
321330
"templateLink": {
322-
"uri":"https://mystorageaccount.blob.core.windows.net/AzureTemplates/newStorageAccount.json",
323-
"contentVersion":"1.0.0.0"
331+
"uri":"https://mystorageaccount.blob.core.windows.net/AzureTemplates/newStorageAccount.json",
332+
"contentVersion":"1.0.0.0"
324333
},
325334
"parametersLink": {
326-
"uri":"https://mystorageaccount.blob.core.windows.net/AzureTemplates/newStorageAccount.parameters.json",
327-
"contentVersion":"1.0.0.0"
335+
"uri":"https://mystorageaccount.blob.core.windows.net/AzureTemplates/newStorageAccount.parameters.json",
336+
"contentVersion":"1.0.0.0"
328337
}
329338
}
330339
}
@@ -355,6 +364,41 @@ To pass parameter values inline, use the **parameters** property.
355364

356365
You can't use both inline parameters and a link to a parameter file. The deployment fails with an error when both `parametersLink` and `parameters` are specified.
357366

367+
## `contentVersion`
368+
369+
You don't have to provide the `contentVersion` property for the `templateLink` or `parametersLink` property. If you don't provide a `contentVersion`, the current version of the template is deployed. If you provide a value for content version, it must match the version in the linked template; otherwise, the deployment fails with an error.
370+
371+
## Using variables to link templates
372+
373+
The previous examples showed hard-coded URL values for the template links. This approach might work for a simple template, but it doesn't work well for a large set of modular templates. Instead, you can create a static variable that stores a base URL for the main template and then dynamically create URLs for the linked templates from that base URL. The benefit of this approach is that you can easily move or fork the template because you need to change only the static variable in the main template. The main template passes the correct URIs throughout the decomposed template.
374+
375+
The following example shows how to use a base URL to create two URLs for linked templates (**sharedTemplateUrl** and **vmTemplate**).
376+
377+
```json
378+
"variables": {
379+
"templateBaseUrl": "https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/postgresql-on-ubuntu/",
380+
"sharedTemplateUrl": "[uri(variables('templateBaseUrl'), 'shared-resources.json')]",
381+
"vmTemplateUrl": "[uri(variables('templateBaseUrl'), 'database-2disk-resources.json')]"
382+
}
383+
```
384+
385+
You can also use [deployment()](template-functions-deployment.md#deployment) to get the base URL for the current template, and use that to get the URL for other templates in the same location. This approach is useful if your template location changes or you want to avoid hard coding URLs in the template file. The templateLink property is only returned when linking to a remote template with a URL. If you're using a local template, that property isn't available.
386+
387+
```json
388+
"variables": {
389+
"sharedTemplateUrl": "[uri(deployment().properties.templateLink.uri, 'shared-resources.json')]"
390+
}
391+
```
392+
393+
Ultimately, you would use the variable in the `uri` property of a `templateLink` property.
394+
395+
```json
396+
"templateLink": {
397+
"uri": "[variables('sharedTemplateUrl')]",
398+
"contentVersion":"1.0.0.0"
399+
}
400+
```
401+
358402
## Using copy
359403

360404
To create multiple instances of a resource with a nested template, add the copy element at the level of the **Microsoft.Resources/deployments** resource. Or, if the scope is inner, you can add the copy within the nested template.
@@ -404,35 +448,13 @@ The following example template shows how to use copy with a nested template.
404448
]
405449
```
406450

407-
## Using variables to link templates
408-
409-
The previous examples showed hard-coded URL values for the template links. This approach might work for a simple template but it doesn't work well when working with a large set of modular templates. Instead, you can create a static variable that stores a base URL for the main template and then dynamically create URLs for the linked templates from that base URL. The benefit of this approach is you can easily move or fork the template because you only need to change the static variable in the main template. The main template passes the correct URIs throughout the decomposed template.
410-
411-
The following example shows how to use a base URL to create two URLs for linked templates (**sharedTemplateUrl** and **vmTemplate**).
412-
413-
```json
414-
"variables": {
415-
"templateBaseUrl": "https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/postgresql-on-ubuntu/",
416-
"sharedTemplateUrl": "[concat(variables('templateBaseUrl'), 'shared-resources.json')]",
417-
"vmTemplateUrl": "[concat(variables('templateBaseUrl'), 'database-2disk-resources.json')]"
418-
}
419-
```
420-
421-
You can also use [deployment()](template-functions-deployment.md#deployment) to get the base URL for the current template, and use that to get the URL for other templates in the same location. This approach is useful if your template location changes or you want to avoid hard coding URLs in the template file. The templateLink property is only returned when linking to a remote template with a URL. If you're using a local template, that property isn't available.
422-
423-
```json
424-
"variables": {
425-
"sharedTemplateUrl": "[uri(deployment().properties.templateLink.uri, 'shared-resources.json')]"
426-
}
427-
```
428-
429451
## Get values from linked template
430452

431453
To get an output value from a linked template, retrieve the property value with syntax like: `"[reference('deploymentName').outputs.propertyName.value]"`.
432454

433-
When getting an output property from a linked template, the property name can't include a dash.
455+
When getting an output property from a linked template, the property name must not include a dash.
434456

435-
The following examples demonstrate how to reference a linked template and retrieve an output value. The linked template returns a simple message.
457+
The following examples demonstrate how to reference a linked template and retrieve an output value. The linked template returns a simple message. First, the linked template:
436458

437459
```json
438460
{
@@ -481,9 +503,9 @@ The main template deploys the linked template and gets the returned value. Notic
481503
}
482504
```
483505

484-
Like other resource types, you can set dependencies between the linked template and other resources. When other resources require an output value from the linked template, make sure the linked template is deployed before them. Or, when the linked template relies on other resources, make sure other resources are deployed before the linked template.
506+
As with other resource types, you can set dependencies between the linked template and other resources. When other resources require an output value from the linked template, make sure the linked template is deployed before them. Or, when the linked template relies on other resources, make sure other resources are deployed before the linked template.
485507

486-
The following example shows a template that deploys a public IP address and returns the resource ID:
508+
The following example shows a template that deploys a public IP address and returns the resource ID of the Azure resource for that public IP:
487509

488510
```json
489511
{
@@ -518,7 +540,7 @@ The following example shows a template that deploys a public IP address and retu
518540
}
519541
```
520542

521-
To use the public IP address from the preceding template when deploying a load balancer, link to the template and add a dependency on the deployment resource. The public IP address on the load balancer is set to the output value from the linked template.
543+
To use the public IP address from the preceding template when deploying a load balancer, link to the template and declare a dependency on the `Microsoft.Resources/deployments` resource. The public IP address on the load balancer is set to the output value from the linked template.
522544

523545
```json
524546
{
@@ -548,6 +570,7 @@ To use the public IP address from the preceding template when deploying a load b
548570
"properties": {
549571
"privateIPAllocationMethod": "Dynamic",
550572
"publicIPAddress": {
573+
// this is where the output value from linkedTemplate is used
551574
"id": "[reference('linkedTemplate').outputs.resourceID.value]"
552575
}
553576
}
@@ -560,6 +583,7 @@ To use the public IP address from the preceding template when deploying a load b
560583
"outboundNatRules": [],
561584
"inboundNatPools": []
562585
},
586+
// This is where the dependency is declared
563587
"dependsOn": [
564588
"linkedTemplate"
565589
]

0 commit comments

Comments
 (0)