有没有绕过这个 Terraform 循环错误的方法?

huangapple go评论52阅读模式
英文:

Is there a way around this terraform cycle error?

问题

我尝试动态创建一组基于路径列表的 AWS API Gateway (v1) 资源,使用 Terraform。

locals {
  http_endpoints = [
    "/api",
    "/api/something",
    "/api/something/else"
  ]
}

resource "aws_api_gateway_resource" "http_function" {
  for_each     = {for path in local.http_endpoints : path => {
      path_part   = compact(split("/", path))[length(compact(split("/", path)))-1]
      parent_path = "/${join("/", slice(compact(split("/", path)), 0, length(compact(split("/", path))) -1))}"
    }
  }

  rest_api_id  = module.gateway.api_gateway_id
  parent_id    = each.value.parent_path == "/" ? module.gateway.api_gateway_root_id : aws_api_gateway_resource.http_function[each.value.parent_path].id
  path_part    = each.value.parts[length(each.value.parts) - 1]
}

for_each 表达式生成如下的映射:

{
  "/api" = { path_part = "api", parent_path = "/" }
  "/api/something" = { path_part = "something", parent_path = "/api" }
  "/api/something/else" = { path_part = "else", parent_path = "/api/something" }
}

我希望 Terraform 能识别资源实例之间的依赖关系并按顺序创建它们,以便每个资源能与正确的父资源关联:

  1. aws_api_gateway_resource.http_function["/api"]
  2. aws_api_gateway_resource.http_function["/api/something"]
  3. aws_api_gateway_resource.http_function["/api/something/else"]

但我遇到了循环错误,列出了所有的 aws_api_gateway_resource 实例。

错误: 循环: aws_api_gateway_resource.http_function["/api/something/else"], 
aws_api_gateway_resource.http_function["/api/something"], 
aws_api_gateway_resource.http_function["/api"]

有简单的方法可以解决这个问题吗?我知道可以使用 OpenAPI 方法构建 API Gateway,但希望避免这样做。

英文:

I am trying to dynamically create a set of AWS API Gateway (v1) resources in Terraform based on a list of paths.

locals {
  http_endpoints = [
    "/api"
    "/api/something"
    "/api/something/else"
  ]
}

resource "aws_api_gateway_resource" "http_function" {
  for_each     = {for path in local.http_endpoints : path => {
      path_part   = compact(split("/", path))[length(compact(split("/", path)))-1]
      parent_path = "/${join("/", slice(compact(split("/", path)), 0, length(compact(split("/", path))) -1))}"
    }
  }

  rest_api_id  = module.gateway.api_gateway_id
  parent_id    = each.value.parent_path == "/" ? module.gateway.api_gateway_root_id : aws_api_gateway_resource.http_function[each.value.parent_path].id
  path_part    = each.value.parts[length(each.value.parts) - 1]
}

The for_each expression results in a map like so:

{
  "/api" = { path_part = "api", parent_path = "/" }
  "/api/something" = { path_part = "something", parent_path = "/api" }
  "/api/something/else" = { path_part = "else", parent_path = "/api/something" }
}

I am hoping that terraform will see the dependencies between the resources instances and create them in order, so that each resource can be linked to the correct parent:

  1. aws_api_gateway_resource.http_function["/api"]
  2. aws_api_gateway_resource.http_function["/api/something"]
  3. aws_api_gateway_resource.http_function["/api/something/else"]

But I am getting a cycle error listing all of the aws_api_gateway_resource instances.

Error: Cycle: aws_api_gateway_resource.http_function["/api/something/else"], 
aws_api_gateway_resource.http_function["/api/something"], 
aws_api_gateway_resource.http_function["/api"]

Is there a simple fix to make this work?
I know that I can use the OpenAPI method of constructing an API Gateway, but would like to avoid that.

答案1

得分: 1

以下是翻译好的内容:

资源的一个实例不可能引用同一资源的另一个实例,因为 Terraform 必须在评估 for_each 之前解析依赖图:for_each 表达式本身具有自己的依赖关系需要考虑。

特别是对于 Amazon API Gateway,一个典型的解决方案是使用 aws_api_gateway_rest_apibody 参数,它允许您使用单个 OpenAPI 架构文档来声明整个 API,从而避免引用任何特定的 API 网关资源 ID,因为 API 网关 API 会自动创建必要的资源层次结构来表示您在架构中描述的路径。

这种方法也更适合您的 local.http_endpoints 数据结构,因为 OpenAPI 期望路径以字符串的形式给出,就像您在该列表中所拥有的那样,而不需要将每个路径段分别声明为嵌套对象。

英文:

It isn't possible for one instance of a resource to refer to another instance of the same resource, because Terraform must resolve the dependency graph before it can evaluate for_each: the for_each expression has dependencies of its own that need to be taken into account.

For Amazon API Gateway in particular, a typical answer is to use the body argument to aws_api_gateway_rest_api which allows you to specify the entire API declaratively using a single OpenAPI schema document, which then avoids the need to refer to any specific API gateway resource IDs because the API gateway API automatically creates the necessary resource heirarchies to represent the paths you describe in your schema.

That approach is also a better fit for your local.http_endpoints data structure, because OpenAPI expects paths given as strings like you have in that list rather than requiring each path segment to be declared separately as nested objects.

huangapple
  • 本文由 发表于 2023年5月18日 01:50:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/76274910.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定