如何使用terraform csvdecode读取双引号字符串值?

vatpfxk5  于 2023-09-28  发布在  其他
关注(0)|答案(2)|浏览(86)

我有一个包含以下内容的CSV文件:

id,value
123,{"M":{"name_1":{"S":"value_1"}, "name_2":{"S":"value_2"}}}

我正在尝试读取此CSV文件,并通过以下方式在DynamoDB中创建记录:

locals {
  custom_data = csvdecode(file("${path.module}/../custom_data.csv"))
}

resource "aws_dynamodb_table_item" "custom_table_item" {
  for_each = {for row in local.custom_data : row.id => row}

  table_name = aws_dynamodb_table.custom_table.name
  hash_key   = aws_dynamodb_table.custom_table.hash_key

  item = jsonencode({
    "id" : { "S" : each.value.id },
    "value" : jsondecode(each.value.value)
  })

  lifecycle {
    ignore_changes = [item]
  }
}

然而,这段代码不起作用,我找不到任何关于如何从CSV文件中读取双引号值的示例,而jsondecode可以创建适当的JSON结构。有人知道怎么做吗?

8fsztsew

8fsztsew1#

清理你的csv文件:

id,value
123,"{""M"":{""name_1"":{""S"":""value_1""}, ""name_2"":{""S"":""value_2""}}}"

然后:

$ terraform-repl
> csvdecode(file("${path.module}/custom_data.csv"))
tolist([
  {
    "id" = "123"
    "value" = "{\"M\":{\"name_1\":{\"S\":\"value_1\"}, \"name_2\":{\"S\":\"value_2\"}}}"
  },
])

> jsondecode(csvdecode(file("${path.module}/custom_data.csv"))[0].value)
{
  "M" = {
    "name_1" = {
      "S" = "value_1"
    }
    "name_2" = {
      "S" = "value_2"
    }
  }
}
fzsnzjdm

fzsnzjdm2#

您在这里展示的文档并不是Terraform函数想要解析的通常意义上的CSV文档,它是在RFC 4180中定义的格式。您的第二个“field”似乎是一个JSON文档,其中包含自己的字段,包括逗号,这意味着csvdecode将误解此文档的意图。
相反,我认为这是一种自定义格式,因此使用更简单的原语解析它:

locals {
  custom_data_raw = file("${path.module}/../custom_data.csv")
  custom_data_lines = slice([
    for chunk in split("\n", local.custom_data_raw) : chomp(chunk)
  ], 1, length(local.custom_data_raw))
  custom_data_fields = [
    for line in local.custom_data_lines : regex("^(?P<id>[^,]),(?P<values>.*)$", line)
  ]
  custom_data = {
    for fields in local.custom_data_fields :
    fields.id => jsondecode(fields.value)
  }
}

上面使用了不同Terraform函数的混合来将文件内容拆分为较小的令牌:

  • split将整个内容拆分为单独的行(chomp用于处理Windows风格的行结尾的可能性,这将是\r\n而不仅仅是\n,因此之后需要额外的剥离。
  • slice丢弃第一行,即“header”行。
  • regex将“id”和“values”字段分开,忽略“values”字段中多余的逗号和引号。
  • 最后jsondecode将“values”字符串替换为它使用JSON语法描述的对象。

我将其拆分为多个步骤,以便更容易地查看中间步骤的结果,但如果您愿意,您应该能够将其中至少一些步骤组合在一起形成更大的表达式。
在所有这些之后,local.custom_data应该是一个可以与for_each一起使用的数据结构,形状如下:

{
  "123" = {
    "M" = {
      "name_1" = {
        "S" = "value_1"
      }
      "name_2" = {
        "S" = "value_2"
      }
    }
  }
}
resource "aws_dynamodb_table_item" "custom_table_item" {
  for_each = local.custom_data

  table_name = aws_dynamodb_table.custom_table.name
  hash_key   = aws_dynamodb_table.custom_table.hash_key

  item = jsonencode({
    "id" : { "S" : each.key },
    "value" : each.values
  })

  lifecycle {
    ignore_changes = [item]
  }
}

如果你想把它当作一个普通的CSV文档,并使用csvdecode,那么你需要首先改变“value”字段的编码,以转义引号和逗号,这意味着:

  • 将第二个参数中的整个JSON字符串写入引号"中,如RFC 4180第2节第6项所述。
  • 在JSON文档中写入双引号(""而不是"),如RFC 4180第2节第7项所述。

原则上可以使用Terraform本身执行这种转换,但它与我上面展示的较低级别的解析基本相同,首先分别标记id和value字段,所以我不会选择这个选项,除非我可以改变生成原始文档的系统来生成有效的CSV数据本身,这样Terraform就可以只依赖于csvdecode

相关问题