在 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

到目前为止我尝试过的:

  1. 使用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.
  1. 我尝试使用的第二种方法是在 locals
  2. 中声明 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 和整个 objectfor 表达式中的 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 }