Azure嵌套模板部署:将模板元素(而不是templateLink)与PowerShell一起使用

时间:2017-08-04 00:30:11

标签: powershell azure azure-template

为了让生活更轻松(从长远来看),我试图使用properties.template,而不是记录良好的properties.templateLink。前者通过将child.json模板文件的内容作为模板参数传递给parent.json模板,文档很少。

来自Microsoft.Resources/deployments的MS文档:

  

模板内容。如果要直接在请求中传递模板语法而不是链接到现有模板,则可以使用此元素。它可以是JObject或格式良好的JSON字符串。使用templateLink属性或模板属性,但不能同时使用两者。

在我的父模板中,我声明参数childTemplates并在properties.template中引用它:

"parameters": {
    "childTemplates": {
      "type": "object",
      "metadata": {
        "description": "Child template"
      }
    }
}

other stuff...


"resources": [
  {
    "name": "[concat('linkedTemplate-VM-Net-',copyIndex(1))]",
    "type": "Microsoft.Resources/deployments",
    "apiVersion": "2017-06-01",
    "dependsOn": [],
    "copy": {
      "name": "interate",
      "count": "[parameters('vmQty')]"
    },
    "properties": {
      "mode": "Incremental",
      "template": "[parameters('childTemplates')]",
      "parameters": {
        "sharedVariables": { "value": "[variables('sharedVariables')]" },
        "sharedTemplate": { "value": "[variables('sharedTemplate')]" },
        "artifactsLocationSasToken": { "value": "[parameters('artifactsLocationSasToken')]" },
        "adminPassword": { "value": "[parameters('adminPassword')]" },
        "copyIndexValue": { "value": "[copyIndex(1)]" }
      },
      "debugSetting": {
        "detailLevel": "both"
      }
    }
  }
],

然后我将子模板传递给New-AzureRmResourceGroupDeployment -TemplateParameterObject以部署父模板:

$TemplateFileLocation = "C:\Temp\templates\parent.json"
$JsonChildTemplate = Get-Content -Raw (Join-Path ($TemplateFileLocation | Split-Path -Parent) "nestedtemplates\child.json") | ConvertFrom-Json

$TemplateParameters = @{
    childTemplates = $JsonChildTemplate
    ...Other parameters...
}

New-AzureRmResourceGroupDeployment -TemplateParameterObject $TemplateParameters

这会产生以下错误:

Code    : InvalidTemplate
Message : The nested deployment 'linkedTemplate-VM-Net-1' failed validation: 'Required property '$schema' not found in JSON. Path 'properties.template'.'.
Target  : 
Details : 

如果我看$JsonChildTemplate,它就会给我:

$schema        : https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#
contentVersion : 1.0.0.0
parameters     : @{sharedVariables=; sharedTemplate=; vhdStorageAccountName=; artifactsLocationSasToken=; adminPassword=; copyIndexValue=}
variables      : @{seqNo=[padleft(add(parameters('copyIndexValue'),3),3,'0')]; nicName=[concat('NIC-',parameters('sharedVariables').role,'-', variables('seqNo'),'-01')]; 
                 subnetRef=[parameters('sharedVariables').network.subnetRef]; ipConfigName=[concat('ipconfig-', variables('seqNo'))]}
resources      : {@{apiVersion=2016-03-30; type=Microsoft.Network/networkInterfaces; name=[variables('nicName')]; location=[resourceGroup().location]; tags=; dependsOn=System.Object[]; 
                 properties=}}
outputs        : @{nicObject=; vmPrivateIp=; vmNameSuffix=; vmPrivateIpArray=}

对我而言,$schema似乎就在那里。

我也尝试使用相同的错误删除| ConvertFrom-Json

上面,我正在展示最新的API版本,但我已尝试过其他版本,例如2016-09-01,以防万一有错误。

在我搜索解决方案时,我在GitHub上发现了this问题。推荐是删除$schemacontentVersion,尽管这会在错误面前飞逝。我尝试了以下内容:

Function Get-ChildTemplate
{
    $TemplateFileLocation = "C:\Temp\templates\nestedtemplates\child.json"

    $json = Get-Content -Raw -Path $TemplateFileLocation | ConvertFrom-Json 

    $NewJson = @()
    $NewJson += $json.parameters
    $NewJson += $json.variables
    $NewJson += $json.resources
    $NewJson += $json.outputs

    Return $NewJson | ConvertTo-Json
}

$JsonChildTemplate = Get-ChildTemplate
$TemplateParameters = @{
    childTemplates = $JsonChildTemplate
    ...Other parameters...
}

$JsonChildTemplate返回:

[
    {
        "sharedVariables":  {
                                "type":  "object",
                                "metadata":  "@{description=Object of variables from master template}"
                            }...

我的猜测是我把child.json的内容传递给New-AzureRmResourceGroupDeployment时做错了。那或者实际上不可能做我想做的事。

P.S。

get-command New-AzureRmResourceGroupDeployment

CommandType     Name                                               Version    Source                                                                                                              
-----------     ----                                               -------    ------                                                                                                              
Cmdlet          New-AzureRmResourceGroupDeployment                 4.1.0      AzureRM.Resources

1 个答案:

答案 0 :(得分:0)

首先,你所做的事情让我感觉到什么,所以说,让我们试着帮助你。

  1. 尝试splatting。所以New-AzureRmResourceGroupDeployment ... @TemplateParameters而不是你正在做的事情。 (不知道,但不知何故,它在我的经历中效果更好)
  2. 如果这不起作用,请尝试将嵌套模板简化为最低限度,看看它是否有效,检查嵌套模板是否正常。
  3. 尝试使用-Debug开关创建部署,看看它的位置。
  4. 使用Azure Cli尝试相同的部署(可能以适当的方式将json转换为输入对象)
  5. 跳过1-4项并以正确的方式进行。我建议永远不要在ARM模板的飞行生成中进行预处理。如果你足够 smart hacky,他们已经有足够的功能来完成任何事情。我不知道你想要实现什么,但我可以打赌我的生活,你不需要你想要创造的怪物
  6. 小模板示例:

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

    编辑:我挖了一点,找到了解决方案。一种方法是使用arm模板的json()函数接受一个字符串并转换为有效的json。

    {
        "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
        "contentVersion": "1.0.0.0",
        "parameters": {
            "inp": {
                "type": "string"
            }
        },
        "resources": [
            {
                "name": "NestedDeployment1",
                "type": "Microsoft.Resources/deployments",
                "apiVersion": "2015-01-01",
                "properties": {
                    "mode": "Incremental",
                    "template": "[json(parameters('inp'))]",
                    "parameters": {}
                }
            }
        ]
    }
    

    要部署使用类似的东西:

    New-AzureRmResourceGroupDeployment ... -inp ((get-content path\to.json -raw) -replace '\s','')
    # we minify the string so it gets properly converted to json
    

    这有点像黑客,但问题在于powershell如何将您的输入转换为传递给模板的内容,而您无法真正控制它。

    另一种方法:(如果你需要输出,你可以添加另一个参数)

    {
        "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
        "contentVersion": "1.0.0.0",
        "parameters": {
            "input-param": {
                "type": "object"
            },
            "input-resource": {
                "type": "array"
            }
        },
        "resources": [
            {
                "name": "NestedDeployment1",
                "type": "Microsoft.Resources/deployments",
                "apiVersion": "2015-01-01",
                "properties": {
                    "mode": "Incremental",
                    "template": {
                        "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
                        "contentVersion": "1.0.0.0",
                        "parameters": "[parameters('input-param')]",
                        "resource": "[parameters('input-resource')]"
                    },
                    "parameters": {}
                }
            }
        ]
    }
    

    并像这样部署:

    New-AzureRmResourceGroupDeployment -ResourceGroupName zzz -TemplateFile path\to.json -input-param @{...} -input-resource @(...)
    

    PS。不介意沃尔特,每当他说某事不能做或不可能时,实际上是可能的。