0

我已经编写了一个模板和随附的运行手册。模板触发 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 传递到模板。

运行手册 (Update-ResourceGroupTags.ps1)

对于测试,运行手册如下所示:

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

没有身份验证,因为它还不是必需的,我故意不输入$MyTags,尽管我已经尝试[object]并使用 `[parameter(Mandatory = $true)] 以防万一有不成文/遗漏的规则。

目标

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

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

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

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

该模板运行"type" : "jobs".

运行的 Runbookjobs有一个MyTags需要接受的参数roleTagObject,我将其传递给jobs.properties.parameters.MyTags

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

这是行不通的。如果我将其分解为每个键(测试 8),它就可以工作。

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

模板(testRunbook.json)

我已将模板放在 GIST 中,以免再提出这个问题。 https://gist.github.com/arcotek-ltd/7c606540​​980a45a3a7915ccae2e0b140

模板已编写好,因此我可以将该"resources":[]部分复制到不同的模板中。因此,为什么某些变量和参数的名称可能看起来很奇怪。正如我所说,除了这个问题之外,模板有效。

电源外壳

我使用 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 有效,但我需要能够将参数传递给运行时在模板内生成的运行手册。换句话说,我不能使用 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() 模板功能。并不是说我希望它能够工作,因为它需要一个字符串。

"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() 模板功能示例:

"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 中的参数从 1 更改为 3。

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


我没主意了。请问有什么建议吗?

4

1 回答 1

0

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

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

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

然后在你的运行手册中你可以做 $MyTags = ConvertFrom-Json $MyTags

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

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

如评论中所示的示例:

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

然后您可以通过将其转换为字符串来传入此模板对象:

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

如果字符串函数不起作用,请告诉我。

希望这有帮助,埃蒙

于 2018-03-15T15:29:11.807 回答