在 Terraform 中使用 for-each 遍历本地 json
Looping over local json using for-each in Terraform
我正在尝试使用来自 json 文件或本地声明的 json 的输入来创建多个 cloudwatch 警报。两者都可以。我已经删除了
的列表
问题是这是在一个模块中,所以我不能使用 file.auto.tfvars.json
我以前就是这样做的。
文件结构:
.
├── cloudwatch.tf
├── cloudwatchalarms.json
└── locals.tf
到目前为止我尝试过的:
- 使用
jsondecode
引入cloudwatchalarms.json
并按以下方式循环:
cloudwatch.tf
# creates alarms based on what exists within cloudwatchalarms.auto.tfvars.json
resource "aws_cloudwatch_metric_alarm" "alarms" {
for_each = { for alarm in local.all_alarms : alarm => alarm }
alarm_name = "${var.awsResourceName}-${each.value.Identifier}"
namespace = each.value.Namespace
comparison_operator = each.value.ComparisonOperator
evaluation_periods = each.value.EvaluationPeriods
statistic = each.value.Statistic
treat_missing_data = each.value.TreatMissingData
threshold = each.value.Threshold
period = each.value.Period
metric_name = each.value.MetricName
dimensions = {
EcsServiceName = var.awsResourceName
EcsClusterName = var.ecs_cluster_name
}
}
locals.tf
# create locals to pull in cloudwatchalarms.json
locals {
cloudwatchAlarms = jsondecode(file("${path.module}/cloudwatchalarms.json"))
# loop over the cloudwatchalarms json structure
all_alarms = [for alarms in local.cloudwatchAlarms.cloudwatchAlarms : alarms.Identifier]
}
cloudwatchalarms.json
{
"cloudwatchAlarms": [
{
"Identifier": "ServiceMemoryUtilisation",
"Namespace": "AWS/ECS",
"MetricName": "MemoryUtilization",
"Statistic": "Average",
"Threshold": 90,
"Period": 60,
"EvaluationPeriods": 5,
"ComparisonOperator": "GreaterThanThreshold",
"TreatMissingData": "missing"
},
{
"Identifier": "ServiceCPUUtilisation",
"Namespace": "AWS/ECS",
"MetricName": "CPUUtilization",
"Statistic": "Average",
"Threshold": 90,
"Period": 60,
"EvaluationPeriods": 5,
"ComparisonOperator": "GreaterThanThreshold",
"TreatMissingData": "missing"
}
]
}
}
使用此方法时,每个属性都出现以下错误:
Error: Unsupported attribute
on .terraform/modules/terraform-ecs-monitoring/cloudwatch.tf line 4, in resource "aws_cloudwatch_metric_alarm" "alarms":
4: alarm_name = "${var.awsResourceName}-${each.value.Identifier}"
|----------------
| each.value is "TaskStability"
This value does not have any attributes.
- 我尝试使用的第二种方法是在
locals
中声明 json 结构
cloudwatch.tf
# creates alarms based on what exists within cloudwatchalarms.auto.tfvars.json
resource "aws_cloudwatch_metric_alarm" "alarms" {
for_each = { for alarm in local.cloudwatchAlarms : alarm.Identifier => alarm }
alarm_name = "${var.awsResourceName}-${each.value.Identifier}"
namespace = each.value.Namespace
comparison_operator = each.value.ComparisonOperator
evaluation_periods = each.value.EvaluationPeriods
statistic = each.value.Statistic
treat_missing_data = each.value.TreatMissingData
threshold = each.value.Threshold
period = each.value.Period
metric_name = each.value.MetricName
dimensions = {
EcsServiceName = var.awsResourceName
EcsClusterName = var.ecs_cluster_name
}
}
locals.tf
locals {
cloudwatchAlarms = {
"cloudwatchAlarms": [
{
"Identifier": "ServiceMemoryUtilisation",
"Namespace": "AWS/ECS",
"MetricName": "MemoryUtilization",
"Statistic": "Average",
"Threshold": 90,
"Period": 60,
"EvaluationPeriods": 5,
"ComparisonOperator": "GreaterThanThreshold",
"TreatMissingData": "missing"
},
{
"Identifier": "ServiceCPUUtilisation",
"Namespace": "AWS/ECS",
"MetricName": "CPUUtilization",
"Statistic": "Average",
"Threshold": 90,
"Period": 60,
"EvaluationPeriods": 5,
"ComparisonOperator": "GreaterThanThreshold",
"TreatMissingData": "missing"
}
]
}
}
然后我在尝试此方法时遇到此错误:
Error: Unsupported attribute
on .terraform/modules/terraform-ecs-monitoring/cloudwatch.tf line 3, in resource "aws_cloudwatch_metric_alarm" "alarms":
3: for_each = { for alarm in local.cloudwatchAlarms : alarm.Identifier => alarm }
This value does not have any attributes.
Throw to stop pipeline
任何帮助或指向正确方向的帮助都会很棒。谢谢。
您在第一次尝试中更接近于正确构建 set(object)
,并在第二次尝试中重构数据。将两者结合起来,我们得出:
locals {
cloudwatchAlarms = jsondecode(file("${path.module}/cloudwatchalarms.json"))
}
resource "aws_cloudwatch_metric_alarm" "alarms" {
for_each = { for alarm in local.cloudwatchAlarms : alarm.Identifier => alarm }
...
}
和您的 for_each
元参数遍历 set(object)
(从 tuple
类型隐式转换)并检索每个 Identifier
键的值 object
和整个 object
。 for
表达式中的 Map 构造函数将前者分配给键,将后者分配给值,迭代时将为您提供资源块正文所需的行为,因为它当前存在于问题中。
另请注意:
alarm_name = "${var.awsResourceName}-${each.value.Identifier}"
可以简化为:
alarm_name = "${var.awsResourceName}-${each.key}"
我使用以下配置对其进行了排序:
locals.tf
# create locals to pull in cloudwatchalarms.json
locals {
cloudwatch_alarms = jsondecode(file("${path.module}/cloudwatchalarms.json"))
# loop over the cloudwatchalarms json structure
all_alarms = { for alarms in local.cloudwatch_alarms.cloudwatchAlarms : alarms.Identifier => alarms }
}
cloudwatchalarms.json
{
"cloudwatchAlarms": [
{
"Identifier": "ServiceMemoryUtilisation",
"Namespace": "AWS/ECS",
"MetricName": "MemoryUtilization",
"Statistic": "Average",
"Threshold": 90,
"Period": 60,
"EvaluationPeriods": 5,
"ComparisonOperator": "GreaterThanThreshold",
"TreatMissingData": "missing"
},
{
"Identifier": "ServiceCPUUtilisation",
"Namespace": "AWS/ECS",
"MetricName": "CPUUtilization",
"Statistic": "Average",
"Threshold": 90,
"Period": 60,
"EvaluationPeriods": 5,
"ComparisonOperator": "GreaterThanThreshold",
"TreatMissingData": "missing"
}
]
}
}
cloudwatch.tf
# creates alarms based on what exists within cloudwatchalarms.auto.tfvars.json
resource "aws_cloudwatch_metric_alarm" "alarms" {
for_each = { for alarm in local.all_alarms : alarm.Identifier => alarm }
alarm_name = "${var.awsResourceName}-${each.value.Identifier}"
namespace = each.value.Namespace
comparison_operator = each.value.ComparisonOperator
evaluation_periods = each.value.EvaluationPeriods
statistic = each.value.Statistic
treat_missing_data = each.value.TreatMissingData
threshold = each.value.Threshold
period = each.value.Period
metric_name = each.value.MetricName
dimensions = {
EcsServiceName = var.awsResourceName
EcsClusterName = var.ecs_cluster_name
}
}
修复是将 locals.tf
中的这一行更改为以下内容:
all_alarms = { for alarms in local.cloudwatch_alarms.cloudwatchAlarms : alarms.Identifier => alarms }
现在这是一张地图。
然后在 cloudwatch.tf
中将 for_each
更改为以下内容:
for_each = { for alarm in local.all_alarms : alarm.Identifier => alarm }
我正在尝试使用来自 json 文件或本地声明的 json 的输入来创建多个 cloudwatch 警报。两者都可以。我已经删除了
的列表问题是这是在一个模块中,所以我不能使用 file.auto.tfvars.json
我以前就是这样做的。
文件结构:
.
├── cloudwatch.tf
├── cloudwatchalarms.json
└── locals.tf
到目前为止我尝试过的:
- 使用
jsondecode
引入cloudwatchalarms.json
并按以下方式循环:
cloudwatch.tf
# creates alarms based on what exists within cloudwatchalarms.auto.tfvars.json
resource "aws_cloudwatch_metric_alarm" "alarms" {
for_each = { for alarm in local.all_alarms : alarm => alarm }
alarm_name = "${var.awsResourceName}-${each.value.Identifier}"
namespace = each.value.Namespace
comparison_operator = each.value.ComparisonOperator
evaluation_periods = each.value.EvaluationPeriods
statistic = each.value.Statistic
treat_missing_data = each.value.TreatMissingData
threshold = each.value.Threshold
period = each.value.Period
metric_name = each.value.MetricName
dimensions = {
EcsServiceName = var.awsResourceName
EcsClusterName = var.ecs_cluster_name
}
}
locals.tf
# create locals to pull in cloudwatchalarms.json
locals {
cloudwatchAlarms = jsondecode(file("${path.module}/cloudwatchalarms.json"))
# loop over the cloudwatchalarms json structure
all_alarms = [for alarms in local.cloudwatchAlarms.cloudwatchAlarms : alarms.Identifier]
}
cloudwatchalarms.json
{
"cloudwatchAlarms": [
{
"Identifier": "ServiceMemoryUtilisation",
"Namespace": "AWS/ECS",
"MetricName": "MemoryUtilization",
"Statistic": "Average",
"Threshold": 90,
"Period": 60,
"EvaluationPeriods": 5,
"ComparisonOperator": "GreaterThanThreshold",
"TreatMissingData": "missing"
},
{
"Identifier": "ServiceCPUUtilisation",
"Namespace": "AWS/ECS",
"MetricName": "CPUUtilization",
"Statistic": "Average",
"Threshold": 90,
"Period": 60,
"EvaluationPeriods": 5,
"ComparisonOperator": "GreaterThanThreshold",
"TreatMissingData": "missing"
}
]
}
}
使用此方法时,每个属性都出现以下错误:
Error: Unsupported attribute
on .terraform/modules/terraform-ecs-monitoring/cloudwatch.tf line 4, in resource "aws_cloudwatch_metric_alarm" "alarms":
4: alarm_name = "${var.awsResourceName}-${each.value.Identifier}"
|----------------
| each.value is "TaskStability"
This value does not have any attributes.
- 我尝试使用的第二种方法是在
locals
中声明 json 结构
cloudwatch.tf
# creates alarms based on what exists within cloudwatchalarms.auto.tfvars.json
resource "aws_cloudwatch_metric_alarm" "alarms" {
for_each = { for alarm in local.cloudwatchAlarms : alarm.Identifier => alarm }
alarm_name = "${var.awsResourceName}-${each.value.Identifier}"
namespace = each.value.Namespace
comparison_operator = each.value.ComparisonOperator
evaluation_periods = each.value.EvaluationPeriods
statistic = each.value.Statistic
treat_missing_data = each.value.TreatMissingData
threshold = each.value.Threshold
period = each.value.Period
metric_name = each.value.MetricName
dimensions = {
EcsServiceName = var.awsResourceName
EcsClusterName = var.ecs_cluster_name
}
}
locals.tf
locals {
cloudwatchAlarms = {
"cloudwatchAlarms": [
{
"Identifier": "ServiceMemoryUtilisation",
"Namespace": "AWS/ECS",
"MetricName": "MemoryUtilization",
"Statistic": "Average",
"Threshold": 90,
"Period": 60,
"EvaluationPeriods": 5,
"ComparisonOperator": "GreaterThanThreshold",
"TreatMissingData": "missing"
},
{
"Identifier": "ServiceCPUUtilisation",
"Namespace": "AWS/ECS",
"MetricName": "CPUUtilization",
"Statistic": "Average",
"Threshold": 90,
"Period": 60,
"EvaluationPeriods": 5,
"ComparisonOperator": "GreaterThanThreshold",
"TreatMissingData": "missing"
}
]
}
}
然后我在尝试此方法时遇到此错误:
Error: Unsupported attribute
on .terraform/modules/terraform-ecs-monitoring/cloudwatch.tf line 3, in resource "aws_cloudwatch_metric_alarm" "alarms":
3: for_each = { for alarm in local.cloudwatchAlarms : alarm.Identifier => alarm }
This value does not have any attributes.
Throw to stop pipeline
任何帮助或指向正确方向的帮助都会很棒。谢谢。
您在第一次尝试中更接近于正确构建 set(object)
,并在第二次尝试中重构数据。将两者结合起来,我们得出:
locals {
cloudwatchAlarms = jsondecode(file("${path.module}/cloudwatchalarms.json"))
}
resource "aws_cloudwatch_metric_alarm" "alarms" {
for_each = { for alarm in local.cloudwatchAlarms : alarm.Identifier => alarm }
...
}
和您的 for_each
元参数遍历 set(object)
(从 tuple
类型隐式转换)并检索每个 Identifier
键的值 object
和整个 object
。 for
表达式中的 Map 构造函数将前者分配给键,将后者分配给值,迭代时将为您提供资源块正文所需的行为,因为它当前存在于问题中。
另请注意:
alarm_name = "${var.awsResourceName}-${each.value.Identifier}"
可以简化为:
alarm_name = "${var.awsResourceName}-${each.key}"
我使用以下配置对其进行了排序:
locals.tf
# create locals to pull in cloudwatchalarms.json
locals {
cloudwatch_alarms = jsondecode(file("${path.module}/cloudwatchalarms.json"))
# loop over the cloudwatchalarms json structure
all_alarms = { for alarms in local.cloudwatch_alarms.cloudwatchAlarms : alarms.Identifier => alarms }
}
cloudwatchalarms.json
{
"cloudwatchAlarms": [
{
"Identifier": "ServiceMemoryUtilisation",
"Namespace": "AWS/ECS",
"MetricName": "MemoryUtilization",
"Statistic": "Average",
"Threshold": 90,
"Period": 60,
"EvaluationPeriods": 5,
"ComparisonOperator": "GreaterThanThreshold",
"TreatMissingData": "missing"
},
{
"Identifier": "ServiceCPUUtilisation",
"Namespace": "AWS/ECS",
"MetricName": "CPUUtilization",
"Statistic": "Average",
"Threshold": 90,
"Period": 60,
"EvaluationPeriods": 5,
"ComparisonOperator": "GreaterThanThreshold",
"TreatMissingData": "missing"
}
]
}
}
cloudwatch.tf
# creates alarms based on what exists within cloudwatchalarms.auto.tfvars.json
resource "aws_cloudwatch_metric_alarm" "alarms" {
for_each = { for alarm in local.all_alarms : alarm.Identifier => alarm }
alarm_name = "${var.awsResourceName}-${each.value.Identifier}"
namespace = each.value.Namespace
comparison_operator = each.value.ComparisonOperator
evaluation_periods = each.value.EvaluationPeriods
statistic = each.value.Statistic
treat_missing_data = each.value.TreatMissingData
threshold = each.value.Threshold
period = each.value.Period
metric_name = each.value.MetricName
dimensions = {
EcsServiceName = var.awsResourceName
EcsClusterName = var.ecs_cluster_name
}
}
修复是将 locals.tf
中的这一行更改为以下内容:
all_alarms = { for alarms in local.cloudwatch_alarms.cloudwatchAlarms : alarms.Identifier => alarms }
现在这是一张地图。
然后在 cloudwatch.tf
中将 for_each
更改为以下内容:
for_each = { for alarm in local.all_alarms : alarm.Identifier => alarm }