如何将hashtables / objects从模板传递到Runbook

时间:2018-03-08 14:05:02

标签: json azure-resource-manager azure-template

我写了一个模板并附带了Runbook。模板触发Runbook。模板和Runbook工作正常,直到我尝试将对象传递给其中一个Runbook的参数。 Azure错误是:

错误

"content":  
{
    "status":  "Failed",
    "error":  
    {
        "code":  "DeploymentFailed",
        "message":  "At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/arm-debug for usage details.",
        "details":
        [
            {
                "code":  "BadRequest",
                "message":  "{\r\n  \"code\": \"BadRequest\",\r\n  \"message\": \"{\\\"Message\\\":\\\"The request is invalid.\\\",\\\"ModelState\\\":{\\\"job.properties.parameters.MyTags\\\":[\\\"An error has occurred.\\\"]}}\"\r\n}"
            }
        ]
    }
}

我不确定ModelState是什么意思,但是job.properties.parameters.MyTags指的是麻烦的参数。

我确信它与数据类型有关。这可能是因为参数作为JSON对象传递,并且Runbook无法理解它。我更习惯将对象从PowerShell传递到模板。

Runbook(Update-ResourceGroupTags.ps1)

对于测试,Runbook看起来像:

param
(
    [string]$ResourceGroupId,
    $MyTags
)
Write-Output "ResourceGroupId: $ResourceGroupId"
Write-Output "MyTags: $($MyTags | Out-String)"
Write-Output "MyTagsType: $($MyTags.GetType() | Out-String)"

没有身份验证,因为它不是必需的,我故意没有输入$MyTags,虽然我已经尝试[object]并使用`[参数(强制= $ true)]以防万一有未写/错过了规则。

目标

简而言之,我在模板中创建了一个复杂对象作为变量,我希望将它作为单个对象传递给Runbook的参数。这些值是动态的,直到部署时才知道。必须在Runbook中指定每个参数(测试8)才会破坏此要求。

我使用New-AzureRmResourceGroupDeployment cmdlet启动模板。

我创建了一个“复杂对象”变量:

"rolesTagObject": {
   "db": "TestVm1",
   "Server": "TestVm1",
   "Client": "TestVm1"
}

模板运行资源"type" : "jobs"

jobs运行的Runbook有一个参数MyTags,需要roleTagObject,我会传递给jobs.properties.parameters.MyTags

,
"parameters": {
     "MyTags": "[variable('roleTagObject')]"
}

这是不起作用的。如果我把它分解成每个键(测试8)就可以了。

我最初的想法是将其转换为单个字符串并使用json()函数将其传递给Runbook,但我不知道如何在模板中执行此操作。

模板(testRunRunbook.json)

我已将模板放入GIST中,以免再出现此问题。 https://gist.github.com/arcotek-ltd/7c606540980a45a3a7915ccae2e0b140

模板已经编写好,因此我可以将"resources":[]部分复制到另一个模板中。因此,为什么一些变量和参数可能看起来奇怪。正如我所说,除了这个问题外,该模板还可以使用。

的PowerShell

我用PowerShell调用模板,因此:

$Ticks = (Get-Date).Ticks.ToString()
$RGID = (Get-AzureRmResourceGroup -Name "MyResourceGroup").ResourceId

$MyTags = @{"TestTag2"="TestValue2"}

$JsonTagsHash = ($MyTags | ConvertTo-Json -Depth 20 | Out-String) -replace '\s',''

$TemplateParametersObject = @{
    currentDateTimeInTicks = $Ticks
    runbookParameters = @{
        ResourceGroupId = $RGID
        #"MyTags" = $MyTags #$JsonTagsHash
    } 
}

New-AzureRmResourceGroupDeployment `
        -Name "Test_Runbook" `
        -ResourceGroupName "MyResourceGroup" `
        -Mode Incremental `
        -DeploymentDebugLogLevel All `
        -Force `
        -TemplateFile "D:temp\testRunRunbook.json" `
        -Verbose `
        -TemplateParameterObject $TemplateParametersObject

我尝试过以下测试:

测试1

取消注释$TemplateParametersObject.runbookParameters.MyTags

$MyTags = @{"TestTag1"="TestValue1"}

$TemplateParametersObject = @{
    currentDateTimeInTicks = $Ticks
    runbookParameters = @{
        ResourceGroupId = $RGID
        MyTags = $MyTags
    } 
}

结果失败 - 请参阅上面的错误。

测试2

$MyTags替换为$JsonTagsHash

$MyTags = @{"TestTag2"="TestValue2"}

$JsonTagsHash = ($MyTags | ConvertTo-Json -Depth 20 | Out-String) -replace '\s',''

$TemplateParametersObject = @{
    currentDateTimeInTicks = $Ticks
    runbookParameters = @{
        ResourceGroupId = $RGID
        MyTags = $JsonTagsHash
    } 
}

结果: PASS 按预期工作。参数传递给Runbook。

测试2有效,但我需要能够将参数传递给在运行时在模板内生成的Runbook。换句话说,我不能使用PowerShell。在job.properties.parameters的模板内(要点中的第103行)

测试3

要证明问题MyTags导致问题,请完全取出:

"parameters": {
    "ResourceGroupId": "[parameters('runbookParameters').ResourceGroupId]"
}

结果:没有错误,但myTags未通过(显然)。

测试4

创建一个变量对象并将其传递给参数:

"variables" : {
    "rolesTagObject": {
        "db": "TestVm1",
        "Server": "TestVm1",
        "Client": "TestVm1"
    }
}

回到job.properties.parameters

"parameters": {
    "ResourceGroupId": "[parameters('runbookParameters').ResourceGroupId]",
    "MyTags": "[variables('rolesTagObject')]"
}

结果失败 - 请参阅上面的错误。

测试5

直接尝试:

"parameters": {
    "ResourceGroupId": "[parameters('runbookParameters').ResourceGroupId]",
    "MyTags": {
         "testTag5" : "testValue5"
    }
}

结果失败 - 请参阅上面的错误。

测试6

使用json() template function。并不是说我希望它能够工作,因为它需要一个字符串。

"parameters": {
    "ResourceGroupId": "[parameters('runbookParameters').ResourceGroupId]",
    "MyTags": "[json(variables('rolesTagObject'))]"
}

结果失败。正如预测的那样:

'The template language function 'json' expects an argument of type 'string'. The provided value is of type 'Object'.

测试7

尝试使用我的MS为json() template function提供的示例:

"parameters": {
    "ResourceGroupId": "[parameters('runbookParameters').ResourceGroupId]",
    "MyTags": "[json('{\"a\": \"b\"}')]"
}

结果失败 - 请参阅上面的错误。有趣!但为什么?工作的PowerShell测试表明它需要是一个JSON对象。这不是json()的作用吗?

测试8

将对象分解为单个键/值:

"parameters": {
    "db": "[variables('rolesTagObject').db]",
    "server": "[variables('rolesTagObject').server]",
    "client": "[variables('rolesTagObject').client]"
                }

我还必须将Runbook中的参数从一个更改为三个。

结果传递 - 但是能够传递对象的想法是它可以具有任意数量的键/值对。这样,不仅必须对变量和参数进行硬编码,Runbook也是如此。不是很灵活。

我没有想法。有什么建议吗?

1 个答案:

答案 0 :(得分:0)

自动化作业参数不了解复杂对象,因此您希望将参数作为字符串传递,然后转换回Runbook中的Json。 在您的示例中,您可以在json对象$ MyTags周围加上引号,以便它以字符串形式出现。

$TemplateParametersObject = @{
    currentDateTimeInTicks = $Ticks
    runbookParameters = @{
        ResourceGroupId = $RGID
        "MyTags" = $MyTags
    } 
}

$TemplateParametersObject = @{
    currentDateTimeInTicks = $Ticks
    runbookParameters = @{
        ResourceGroupId = $RGID
        "MyTags" = "$MyTags"
    } 
}

然后在你的Runbook中你可以做到 $ MyTags = ConvertFrom-Json $ MyTags

将其恢复为可以根据需要使用的json对象。

如果要将模板中的对象转换为字符串,则只需使用字符串函数https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-template-functions-string#string

评论中显示的示例:

"myParams": {
  "Hello": "World",
  "Location": {
    "Country": "USA",
    "State": "WA"
  }
},

然后您只需将其转换为字符串即可传递此模板对象:

 "properties": {
"runbook": {
    "name": "[variables('runbookName')]"
},
"parameters": {
    "ResourceGroupId": "[variables('myParams').Hello]",
    "MyTags": "[String(variables('myParams'))]"
}

如果字符串功能不起作用,请告诉我。

希望这个帮助, 埃蒙