Azure Resource Manager テンプレートでプロパティのトランスフォーマーとコレクターを実装する

記事「Azure Resource Manager テンプレートのコピー ループのパラメーターとしてオブジェクトを使用する」で、オブジェクトにリソース プロパティ値を格納する方法と、デプロイ中にリソースにそれらを適用する方法を確認できます。 これはパラメーターの管理には非常に便利な方法ですが、テンプレートでオブジェクトを使用するたびに、オブジェクトのプロパティをリソースのプロパティにマップする必要があります。

これを回避するために、オブジェクト配列を反復処理してリソースの JSON スキーマに変換するプロパティ変換とコレクターのテンプレートを実装できます。

重要

この方法では、Resource Manager のテンプレートと関数について深い理解があることが必要です。

ネットワーク セキュリティ グループをデプロイするためのプロパティ コレクターとトランスフォーマーを実装する例を見てみましょう。 以下の図は、テンプレートがそのテンプレート内のリソースにどのように関連しているかを示しています。

プロパティのコレクターとトランスフォーマーのアーキテクチャ

この呼び出し元テンプレートには 2 つのリソースが含まれています。

  • コレクター テンプレートを呼び出す、テンプレート リンク
  • デプロイするネットワーク セキュリティ グループ リソース

このコレクター テンプレートには 2 つのリソースが含まれています。

  • アンカー リソース
  • コピー ループ内で変換テンプレートを呼び出すテンプレート リンク

変換テンプレートには、source JSON をメイン テンプレート内のネットワーク セキュリティ グループ リソースで想定されている JSON スキーマに変換する変数を持つ空のテンプレートという 1 つのリソースが含まれています。

パラメーター オブジェクト

Azure Resource Manager テンプレートのコピー ループのパラメーターとしてオブジェクトを使用する」の securityRules パラメーター オブジェクトを使用します。 変換テンプレートは、securityRules 配列内の各々のオブジェクトを、呼び出し元テンプレート内のネットワーク セキュリティ グループ リソースで想定されている JSON スキーマに変換します。

{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "networkSecurityGroupsSettings": {
            "value": {
                "securityRules": [
                    {
                        "name": "RDPAllow",
                        "description": "allow RDP connections",
                        "direction": "Inbound",
                        "priority": 100,
                        "sourceAddressPrefix": "*",
                        "destinationAddressPrefix": "10.0.0.0/24",
                        "sourcePortRange": "*",
                        "destinationPortRange": "3389",
                        "access": "Allow",
                        "protocol": "Tcp"
                    },
                    {
                        "name": "HTTPAllow",
                        "description": "allow HTTP connections",
                        "direction": "Inbound",
                        "priority": 200,
                        "sourceAddressPrefix": "*",
                        "destinationAddressPrefix": "10.0.1.0/24",
                        "sourcePortRange": "*",
                        "destinationPortRange": "80",
                        "access": "Allow",
                        "protocol": "Tcp"
                    }
                ]
            }
        }
    }
}

最初に変換テンプレートを見てみましょう。

変換テンプレート

この変換テンプレートには、コレクター テンプレートから渡される 2 つのパラメーターが含まれています。

  • source は、プロパティ配列からプロパティ値オブジェクトの 1 つを受け取るオブジェクトです。 例では、securityRules 配列の各オブジェクトが一度に 1 つ渡されます。
  • state は、以前の変換のすべてを連結した結果を受け取る配列です。 これは、変換された JSON のコレクションです。

パラメーターは次のようになります。

{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "source": {
            "type": "object"
        },
        "state": {
            "type": "array",
            "defaultValue": []
        }
    },

テンプレートでは、source オブジェクトを必要な JSON スキーマに変換する instance という名前の変数の定義も行います。

"variables": {
    "instance": [
        {
            "name": "[parameters('source').name]",
            "properties": {
                "description": "[parameters('source').description]",
                "protocol": "[parameters('source').protocol]",
                "sourcePortRange": "[parameters('source').sourcePortRange]",
                "destinationPortRange": "[parameters('source').destinationPortRange]",
                "sourceAddressPrefix": "[parameters('source').sourceAddressPrefix]",
                "destinationAddressPrefix": "[parameters('source').destinationAddressPrefix]",
                "access": "[parameters('source').access]",
                "priority": "[parameters('source').priority]",
                "direction": "[parameters('source').direction]"
            }
        }
    ]
}

最後に、テンプレートの output によって、state パラメーターの収集された変換が instance 変数によって実行される現在の変換と連結されます。

"resources": [],
"outputs": {
    "collection": {
        "type": "array",
        "value": "[concat(parameters('state'), variables('instance'))]"
    }
}

次に、コレクター テンプレートによってパラメーター値がどのように渡されているかを見てみましょう。

コレクター テンプレート

このコレクター テンプレートには 3 つのパラメーターが含まれています。

  • source は完全なパラメーター オブジェクトの配列です。 これは、呼び出し元テンプレートによって渡されます。 変換テンプレートsource パラメーターと同じ名前ですが、重要な違いが 1 つあります。これは完全な配列ですが、一度に 1 つの配列要素のみを変換テンプレートに渡します。
  • transformTemplateUri は、この変換テンプレートの URI です。 テンプレートが再利用できるように、パラメーターとして定義します。
  • state は、変換テンプレートに渡す、最初は空である配列です。 これにより、コピー ループの完了後に、変換されたパラメーター オブジェクトのコレクションが格納されます。

パラメーターは次のようになります。

"parameters": {
    "source": {
        "type": "array"
    },
    "transformTemplateUri": {
        "type": "string"
    },
    "state": {
        "type": "array",
        "defaultValue": []
    }
}

次に、count という名前の変数を定義します。 その値は、source パラメーター オブジェクトの配列の長さです。

"variables": {
    "count": "[length(parameters('source'))]"
}

コピー ループでのイテレーションの回数に使用しています。

ここで、リソースを見てみましょう。 2 つのリソースを定義します。

  • loop-0 はコピー ループの 0 から始まるリソースです。
  • loop-copyIndex(1) 関数の結果と連結され、リソースに、1 で始まるイテレーションに基づく一意の名前を生成します。

リソースは次のようになります。

"resources": [
    {
        "type": "Microsoft.Resources/deployments",
        "apiVersion": "2015-01-01",
        "name": "loop-0",
        "properties": {
            "mode": "Incremental",
            "parameters": { },
            "template": {
                "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
                "contentVersion": "1.0.0.0",
                "parameters": { },
                "variables": { },
                "resources": [ ],
                "outputs": {
                    "collection": {
                        "type": "array",
                        "value": "[parameters('state')]"
                    }
                }
            }
        }
    },
    {
        "type": "Microsoft.Resources/deployments",
        "apiVersion": "2015-01-01",
        "name": "[concat('loop-', copyindex(1))]",
        "copy": {
            "name": "iterator",
            "count": "[variables('count')]",
            "mode": "serial"
        },
        "dependsOn": [
            "loop-0"
        ],
        "properties": {
            "mode": "Incremental",
            "templateLink": { "uri": "[parameters('transformTemplateUri')]" },
            "parameters": {
                "source": { "value": "[parameters('source')[copyindex()]]" },
                "state": { "value": "[reference(concat('loop-', copyindex())).outputs.collection.value]" }
            }
        }
    }
]

入れ子になったテンプレート内の変換テンプレートに渡すパラメーターを詳しく見てみましょう。 source パラメーターは source パラメーター オブジェクトの配列にある現在のオブジェクトを渡していることを思い出してください。 state パラメーターは収集の発生点です。これがコピー ループの前のイテレーションの出力を受け取って、現在のイテレーションに渡します。 reference() 関数は、パラメーターのない copyIndex() 関数を使用して、前にリンクされたテンプレート オブジェクトの name を参照しています。

最後に、テンプレートの output は、変換テンプレートの最後のイテレーションの output を返します。

"outputs": {
    "result": {
        "type": "array",
        "value": "[reference(concat('loop-', variables('count'))).outputs.collection.value]"
    }
}

変換テンプレートの最後のイテレーションの output呼び出し元テンプレートに返すのは、それを source パラメーターに格納していたように感じられるため、直感に反するかもしれません。 しかし、これは変換されたプロパティ オブジェクトの完全な配列を持つ変換テンプレートの最後のイテレーションであり、まさに返そうとしているものです。

最後に、呼び出し元テンプレートからコレクター テンプレートを呼び出す方法を見てみましょう。

呼び出し元テンプレート

この呼び出し元テンプレートは、networkSecurityGroupsSettings という名前の単一パラメーターを定義します。

...
"parameters": {
    "networkSecurityGroupsSettings": {
        "type": "object"
    }
}

次に、テンプレートは collectorTemplateUri という名前の単一の変数を定義します。

"variables": {
    "collectorTemplateUri": "[uri(deployment().properties.templateLink.uri, 'collector.template.json')]"
}

これはリンクされたテンプレート リソースによって使用されるコレクター テンプレートの URI です。

{
    "apiVersion": "2020-06-01",
    "name": "collector",
    "type": "Microsoft.Resources/deployments",
    "properties": {
        "mode": "Incremental",
        "templateLink": {
            "uri": "[variables('collectorTemplateUri')]",
            "contentVersion": "1.0.0.0"
        },
        "parameters": {
            "source": {
                "value": "[parameters('networkSecurityGroupsSettings').securityRules]"
            },
            "transformTemplateUri": {
                "value": "[uri(deployment().properties.templateLink.uri, 'transform.json')]"
            }
        }
    }
}

コレクター テンプレートに 2 つのパラメーターを渡します。

  • source はプロパティ オブジェクトの配列です。 この例では、networkSecurityGroupsSettings パラメーターです。
  • transformTemplateUriコレクター テンプレートの URI で定義した変数です。

最後に、Microsoft.Network/networkSecurityGroups リソースで、collector がリンクされたテンプレート リソースの output をその securityRules プロパティに直接割り当てます。

"resources": [
    {
        "apiVersion": "2020-05-01",
        "type": "Microsoft.Network/networkSecurityGroups",
        "name": "networkSecurityGroup1",
        "location": "[resourceGroup().location]",
        "properties": {
            "securityRules": "[reference('collector').outputs.result.value]"
        }
    }
],
"outputs": {
    "instance": {
        "type": "array",
        "value": "[reference('collector').outputs.result.value]"
    }
}

テンプレートを試行する

テンプレートの例は GitHub で入手できます。 テンプレートをデプロイするには、リポジトリを複製し、次の Azure CLI コマンドを実行します。

git clone https://github.com/mspnp/template-examples.git
cd template-examples/example4-collector
az group create --location <location> --name <resource-group-name>
az deployment group create -g <resource-group-name> \
    --template-uri https://raw.githubusercontent.com/mspnp/template-examples/master/example4-collector/deploy.json \
    --parameters deploy.parameters.json

次のステップ