[英]How to concatenate strings in Terraform output with for loop?
I have multiple aws_glue_catalog_table
resources and I want to create a single output
that loops over all resources to show the S3 bucket location of each one.我有多个
aws_glue_catalog_table
资源,我想创建一个循环所有资源的output
,以显示每个资源的 S3 存储桶位置。 The purpose of this is to test if I am using the correct location
(because it is a concatenation of variables) for each resource in Terratest.这样做的目的是测试我是否为 Terratest 中的每个资源使用了正确的
location
(因为它是变量的串联)。 I cannot use aws_glue_catalog_table.*
or aws_glue_catalog_table.[]
because Terraform does not allow to reference a resource without specifying its name.我不能使用
aws_glue_catalog_table.*
或aws_glue_catalog_table.[]
因为 Terraform 不允许在不指定名称的情况下引用资源。
So I created a variable "table_names"
with r1
, r2
, rx
.所以我用
r1
, r2
, rx
创建了一个variable "table_names"
。 Then, I can loop over the names.然后,我可以遍历名称。 I want to create the string
aws_glue_catalog_table.r1.storage_descriptor[0].location
dynamically, so I can check if the location
is correct.我想动态创建字符串
aws_glue_catalog_table.r1.storage_descriptor[0].location
,以便我可以检查location
是否正确。
resource "aws_glue_catalog_table" "r1" {
name = "r1"
database_name = var.db_name
storage_descriptor {
location = "s3://${var.bucket_name}/${var.environment}-config/r1"
}
...
}
resource "aws_glue_catalog_table" "rX" {
name = "rX"
database_name = var.db_name
storage_descriptor {
location = "s3://${var.bucket_name}/${var.environment}-config/rX"
}
}
variable "table_names" {
description = "The list of Athena table names"
type = list(string)
default = ["r1", "r2", "r3", "rx"]
}
output "athena_tables" {
description = "Athena tables"
value = [for n in var.table_names : n]
}
First attempt: I tried to create an output "athena_tables_location"
with the syntax aws_glue_catalog_table.${table}
but does does.第一次尝试:我尝试使用语法
aws_glue_catalog_table.${table}
创建一个output "athena_tables_location"
,但确实如此。
output "athena_tables_location" {
// HOW DO I ITERATE OVER ALL TABLES?
value = [for t in var.table_names : aws_glue_catalog_table.${t}.storage_descriptor[0].location"]
}
Second attempt: I tried to create a variable "table_name_locations"
but IntelliJ already shows an error ${t}
in the for loop [for t in var.table_names : "aws_glue_catalog_table.${t}.storage_descriptor[0].location"]
.第二次尝试:我尝试创建一个
variable "table_name_locations"
但 IntelliJ 已经在 for 循环中显示错误${t}
[for t in var.table_names : "aws_glue_catalog_table.${t}.storage_descriptor[0].location"]
.
variable "table_name_locations" {
description = "The list of Athena table locations"
type = list(string)
// THIS ALSO DOES NOT WORK
default = [for t in var.table_names : "aws_glue_catalog_table.${t}.storage_descriptor[0].location"]
}
How can I list all table locations in the output
and then test it with Terratest?如何列出
output
中的所有表位置,然后使用 Terratest 对其进行测试? Once I can iterate over the tables and collect the S3 location I can do the following test using Terratest:一旦我可以遍历表并收集 S3 位置,我就可以使用 Terratest 进行以下测试:
athenaTablesLocation := terraform.Output(t, terraformOpts, "athena_tables_location")
assert.Contains(t, athenaTablesLocation, "s3://rX/test-config/rX",)
It seems like you have an unusual mix of static and dynamic here: you've statically defined a fixed number of aws_glue_catalog_table
resources but you want to use them dynamically based on the value of an input variable.似乎您在这里有一个不寻常的静态和动态混合:您已经静态定义了固定数量的
aws_glue_catalog_table
资源,但您想根据输入变量的值动态使用它们。
Terraform doesn't allow dynamic references to resources because its execution model requires building a dependency graph between all of the objects, and so it needs to know which exact resources are involved in a particular expression. Terraform 不允许动态引用资源,因为它的执行模型需要在所有对象之间构建依赖关系图,因此它需要知道特定表达式中涉及哪些确切资源。 However, you can in principle build your own single value that includes all of these objects and then dynamically choose from it:
但是,原则上您可以构建自己的包含所有这些对象的单个值,然后从中动态选择:
locals {
tables = {
r1 = aws_glue_catalog_table.r1
r2 = aws_glue_catalog_table.r2
r3 = aws_glue_catalog_table.r3
# etc
}
}
output "table_locations" {
value = {
for t in var.table_names : t => local.tables[t].storage_descriptor[0].location
}
}
With this structure Terraform can see that output "table_locations"
depends on local.tables
and local.tables
depends on all of the relevant resources, and so the evaluation order will be correct.通过这个结构,Terraform 可以看到
output "table_locations"
取决于local.tables
而local.tables
取决于所有相关资源,因此评估顺序将是正确的。
However, it also seems like your table definitions are systematic based on var.table_names
and so could potentially benefit from being dynamic themselves.但是,您的表定义似乎也是基于
var.table_names
系统化的,因此可能会从动态本身中受益。 You could achieve that using the resource for_each
feature to declare multiple instances of a single resource:您可以使用资源
for_each
功能来声明单个资源的多个实例:
variable "table_names" {
description = "Athena table names to create"
type = set(string)
default = ["r1", "r2", "r3", "rx"]
}
resource "aws_glue_catalog_table" "all" {
for_each = var.table_names
name = each.key
database_name = var.db_name
storage_descriptor {
location = "s3://${var.bucket_name}/${var.environment}-config/${each.key}"
}
...
}
output "table_locations" {
value = {
for k, t in aws_glue_catalog_table.all : k => t.storage_descriptor[0].location
}
}
In this case aws_glue_catalog_table.all
represents all of the tables together as a single resource with multiple instances, each one identified by the table name.在这种情况下,
aws_glue_catalog_table.all
将所有表一起表示为具有多个实例的单个资源,每个实例由表名称标识。 for_each
resources appear in expressions as maps, so this will declare resource instances with addresses like this: for_each
资源作为映射出现在表达式中,因此这将使用如下地址声明资源实例:
aws_glue_catalog_table.all["r1"]
aws_glue_catalog_table.all["r2"]
aws_glue_catalog_table.all["r3"]
Because this is already a map, this time we don't need the extra step of constructing the map in a local value, and can instead just access this map directly to build the output value, which will be a map from table name to storage location:因为这已经是一个map了,这次我们不需要在本地值中构建map的额外步骤,而是可以直接访问这个map来构建输出值,这将是一个从表名到存储的映射地点:
{
r1 = "s3://BUCKETNAME/ENVNAME-config/r1"
r2 = "s3://BUCKETNAME/ENVNAME-config/r2"
r3 = "s3://BUCKETNAME/ENVNAME-config/r3"
# ...
}
In this example I've assumed that all of the tables are identical aside from their names, which I expect isn't true in practice but I was going only by what you included in the question.在这个例子中,我假设所有的表除了它们的名字外都是相同的,我希望这在实践中不是真的,但我只是按照你在问题中包含的内容进行。 If the tables do need to have different settings then you can change
var.table_names
to instead be a variable "tables"
whose type is a map of object type where the values describe the differences between the tables, but that's a different topic kinda beyond the scope of this question, so I won't get into the details of that here.如果表确实需要具有不同的设置,那么您可以将
var.table_names
更改为variable "tables"
其类型是对象类型的映射,其中值描述表之间的差异,但这是一个不同的主题,有点超出这个问题的范围,所以我不会在这里详细介绍。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.