我需要为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_uri
到bucket_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来解释模式。