Terraform:如何循环元素列表并基于每个元素创建资源



我需要为inference变量中传递的每个data_uri设置aws s3访问点;这是为了提供一个跨帐户uri。我只需要从每个data_uri中解析出bucket名称,然后为每个创建资源。我该怎么做呢?

以下是我目前所拥有的:

resource "aws_s3_access_point" "s3_access_point" {
count    = var.create ? 1 : 0
for_each = var.inference
bucket = split("/", replace(each.value.image_uri, "s3://", ""))[0]
name   = format("%s-%s", split("/", replace(each.value.image_uri, "s3://", ""))[0], "-access-point")
}

变量如下所示:

{
"inference": [
{
"data_uri": "s3://my_bucket/model.tar.gz"
},
{
"data_uri": "s3://my_bucket_2/model.tar.gz"
},
{
"data_uri": "s3://my_bucket_3/model.tar.gz"
}
]
}

如果命名一致,我建议使用split。此外,您不能混合count和for_each;根据情况需要使用其中一个或另一个。

注意:这个答案已经根据下面的评论进行了修改

locals {
inference = [
{ "data_uri" : "s3://my_bucket/model.tar.gz" },
{ "data_uri" : "s3://my_bucket_2/model.tar.gz" },
{ "data_uri" : "s3://my_bucket_3/model.tar.gz" }
]
uri_bucket_map = {
for x in local.inference : x.data_uri =>
split("/", split("//", x.data_uri)[1])[0]
}
}
resource "aws_s3_access_point" "s3_access_point" {
for_each = local.uri_bucket_map
bucket = each.value
name   = var.s3_access_point_name
}
output "s3_access_point" {
value = { for uri, ap in aws_s3_access_point.s3_access_point : uri => ap.arn }
}

在这个迭代中,我们生成了一个从data_uribucket_name的映射,以便您可以在需要时访问这两个映射。当然,您仍然可以只使用uri的toset版本并计算资源中的bucket,但由于您更喜欢这种方法,因此可以在其他地方访问bucket名称,因此我选择了映射。

创建资源后,我们生成一个输出,该输出是从data_uri到接入点arn的映射。

Terraform的regex函数的文档包括一个包含匹配URL的方案和权限部分的模式的示例,该模式是RFC 3986附录B:中给出的模式的简化

> regex("^(?:(?P<scheme>[^:/?#]+):)?(?://(?P<authority>[^/?#]*))?", "https://terraform.io/docs/")
{
"authority" = "terraform.io"
"scheme" = "https"
}

这些S3 URL似乎遵循通常的URL生成,因此解析这些URL的一种方法是通过相同的正则表达式模式运行它们:

> regex("^(?:(?P<scheme>[^:/?#]+):)?(?://(?P<authority>[^/?#]*))?", "s3://my_bucket/model.tar.gz")
{
"authority" = "my_bucket"
"scheme" = "s3"
}

要做到这一点,我首先从local.inference中导出一个新值,它扩展了这些URL:

locals {
data_uris = [
for o in local.inference : merge(
{uri = o.data_uri},
regex("^(?:(?P<scheme>[^:/?#]+):)?(?://(?P<authority>[^/?#]*))?", o.data_uri),
)
]
}

上面的merge是将regex结果与原始输入URI相结合,为每个输入获得一个简单的对象:

[
{
uri       = "s3://my_bucket/model.tar.gz",
scheme    = "s3"
authority = "my_bucket"
},
{
uri       = "s3://my_bucket_2/model.tar.gz",
scheme    = "s3"
authority = "my_bucket_2"
},
{
uri       = "s3://my_bucket_3/model.tar.gz",
scheme    = "s3"
authority = "my_bucket_3"
},
]

然后,我们可以在for_each内部进行更多的过滤/投影,将其转换为一组bucket名称,如果没有设置var.create,则将其全部过滤掉,并跳过任何不是S3 URL的URL:

resource "aws_s3_access_point" "s3_access_point" {
for_each = toset([
for ap in local.data_uris : ap.authority
if var.enabled && ap.scheme == "s3"
])
bucket = each.key
name   = "${each.key}-access-point"
}

无可否认,这里使用regex并不理想,因为不清楚regex模式在做什么。如果你继续这样做,那么我建议包括源代码注释,注意这个正则表达式正在解析URI,并可能链接到RFC 3986附录B来解释模式。

相关内容

  • 没有找到相关文章

最新更新