Terraform-개수와 함께 중첩 루프 사용


18

테라 폼에서 중첩 루프를 사용하려고합니다. 두 개의 목록 변수가 list_of_allowed_accounts있고 list_of_images목록 list_of_images을 반복 한 다음 목록을 반복하려고 합니다 list_of_allowed_accounts.

여기 내 테라 폼 코드가 있습니다.

variable "list_of_allowed_accounts" {
  type    = "list"
  default = ["111111111", "2222222"]
}

variable "list_of_images" {
  type    = "list"
  default = ["alpine", "java", "jenkins"]
}

data "template_file" "ecr_policy_allowed_accounts" {
  template = "${file("${path.module}/ecr_policy.tpl")}"

  vars {
    count = "${length(var.list_of_allowed_accounts)}"
    account_id = "${element(var.list_of_allowed_accounts, count.index)}"
  }
}

resource "aws_ecr_repository_policy" "repo_policy_allowed_accounts" {
  count = "${length(var.list_of_images)}"
  repository = "${element(aws_ecr_repository.images.*.id, count.index)}"
  count = "${length(var.list_of_allowed_accounts)}"
  policy = "${data.template_file.ecr_policy_allowed_accounts.rendered}"
}

이것은 내가하려고하는 것과 동등한 bash입니다.

for image in alpine java jenkins
do 
  for account_id in 111111111 2222222
  do 
    // call template here using variable 'account_id' and 'image'
  done
done

답변:


34

Terraform은 이러한 종류의 중첩 반복을 직접 지원하지 않지만 산술로 위조 할 수 있습니다.

variable "list_of_allowed_accounts" {
  type = "list"
  default = ["1111", "2222"]
}

variable "list_of_images" {
  type = "list"
  default = ["alpine", "java", "jenkins"]
}

data "template_file" "ecr_policy_allowed_accounts" {
  count = "${length(var.list_of_allowed_accounts) * length(var.list_of_images)}"

  template = "${file("${path.module}/ecr_policy.tpl")}"

  vars {
    account_id = "${var.list_of_allowed_accounts[count.index / length(var.list_of_images)]}"
    image      = "${var.list_of_images[count.index % length(var.list_of_images)]}"
  }
}

resource "aws_ecr_repository_policy" "repo_policy_allowed_accounts" {
  count = "${data.template_file.ecr_policy_allowed_accounts.count}"

  repository = "${var.list_of_images[count.index % length(var.list_of_images)]}"
  policy = "${data.template_file.ecr_policy_allowed_accounts.*.rendered[count.index]}"
}

계정과 이미지의 모든 조합에 대한 정책 템플릿을 만들려고 count하므로 template_file데이터 블록에 두 개가 곱해집니다. 그런 다음 나누기 및 모듈로 연산을 사용하여 count.index각 목록의 개별 인덱스로 돌아갈 수 있습니다 .

정책 템플릿 사본이 없으므로 자리 표시 자 템플릿을 사용했습니다. 따라서이 구성은 다음 계획을 제시했습니다.

+ aws_ecr_respository_policy.repo_policy_allowed_accounts.0
    policy:     "policy allowing 1111 to access alpine"
    repository: "alpine"

+ aws_ecr_respository_policy.repo_policy_allowed_accounts.1
    policy:     "policy allowing 1111 to access java"
    repository: "java"

+ aws_ecr_respository_policy.repo_policy_allowed_accounts.2
    policy:     "policy allowing 1111 to access jenkins"
    repository: "jenkins"

+ aws_ecr_respository_policy.repo_policy_allowed_accounts.3
    policy:     "policy allowing 2222 to access alpine"
    repository: "alpine"

+ aws_ecr_respository_policy.repo_policy_allowed_accounts.4
    policy:     "policy allowing 2222 to access java"
    repository: "java"

+ aws_ecr_respository_policy.repo_policy_allowed_accounts.5
    policy:     "policy allowing 2222 to access jenkins"
    repository: "jenkins"

각 정책 인스턴스는 모든 조합을 포함하는 다른 계정 ID 및 이미지 쌍에 적용됩니다.


2
리소스를 다른 인덱스에 매핑하는 것보다 새 계정이나 이미지를 추가하는 등 구성을 확장하려는 경우 문제가 발생하지만, 삭제 및 재생성에 문제가없는 경우에는 문제가 없습니다.
balazs

1
@ justin-grote는 그의 대답에 요점을 가지고 있습니다 : terraform 0.12에서는 나누는 곳마다 바닥 기능을 사용해야하거나 그렇지 않으면 부분 인덱스에 대한 오류가 발생합니다. account_id = var.list_of_allowed_accounts[floor(count.index / length(var.list_of_images))]
chriscatfr

7

여기에 대한 답변이 효과가 있지만 (처음에는 사용했습니다) Terraform의 setproduct 기능을 사용하는 더 나은 솔루션이 있다고 생각 합니다. 나는 인터 웹 주위에서 사용되는 많은 예제를 보지 못했지만 setproduct는 두 세트 (또는 더 중요한 것은 두 목록)를 취하고 입력의 모든 순열과 함께 세트 목록을 생성합니다. 내 경우에는 SSM 매개 변수를 만들고 있습니다.

variable "list1" {
  type    = "list"
  default = ["outer1", "outer2"]
}

variable "list2" {
  type    = "list"
  default = ["inner1", "inner2", "inner3"]
}

locals {
  product = "${setproduct(var.list1, var.list2)}"
}

resource "aws_ssm_parameter" "params" {
  count     = "${length(var.list1) * length(var.list2)}"
  name      = "/${element(local.product, count.index)[0]}/${element(local.product, count.index)[1]}"
  type      = "String"
  value     = "somevalue"
  overwrite = false
  lifecycle { ignore_changes = ["value"] }
}

그러면 다음과 같은 SSM 매개 변수가 작성됩니다.

/outer1/inner1
/outer1/inner2
/outer1/inner3
/outer2/inner1
/outer2/inner2
/outer2/inner3

내 멍청한 작은 뇌는 다른 답변의 모듈로 마술보다 이것을 쉽게 분석 할 수 있습니다!


나는 당신의 해결책을 시도 할 것입니다. 훨씬 나아 보인다는 데 동의합니다. 그러나 왜 카운트 ${length(var.list1) * length(var.list2)}대신에 사용 ${length(local.product)}합니까?
chriscatfr

고객이 v0.12를 사용하기 시작할 때까지 기다려야합니다. (여러 소스를 찾지 못한 이유는 당연합니다.
chriscatfr

아무 이유도 ${length(local.product)}없을 것입니다. 또한 setproduct()0.12 이전에 존재한다고 확신 합니다 (링크 된 페이지 상단의 메시지는 모든 0.11 문서에 대한 일반적인 경고 일뿐입니다)?
Kyle

4

참고로 누군가 Google에서 온 경우 terraform 0.12를 사용하는 경우 나누는 곳에서 바닥 기능을 사용해야합니다. 그렇지 않으면 부분 인덱스에 대한 오류가 발생합니다.

account_id = var.list_of_allowed_accounts [ (계수 색인 / 길이 (var.list_of_images))]


나는 수학 접근법을 시도하기 전에 SO 페이지를 끝까지 읽고이 보석을 발견하기를 바랍니다. 이것이 내가 floor (count.index / 8)로 작업하는 방법입니다. 게시 해 주셔서 감사합니다.
bytejunkie

@kyle의 솔루션에서 0.12 setproduct () 사용하면 더 쉬워 보입니다.
chriscatfr

당신이 Terraform 0.12에 있다면, 왜 새로 추가 된 사용하지 for, for_each혼란 좀 덜 뭔가를 구현 및 / 또는 동적 중첩 된 블록 언어 구조를?
TrinitronX

0

기본적으로 문제는 데이터 "template_file"에 있으며 account_id는 귀하의 경우 카운트가 증가 / 변경되지 않는 또 다른 var이기 때문에 원하는 방식으로 설정할 수 없습니다. 당신의 질문이 정확히 무엇인지보고 싶었 기 때문에 그냥 말하십시오.


0

@ Martin Atkins가 제공 한 답변에 의견을 추가 할만 큼 평판이 충분하지 않으므로 Terraform 문제 20567을 해결 하는 약간의 수정으로 답변을 게시하고 있습니다.

variable "list_of_allowed_accounts" {
  type = "list"
  default = ["1111", "2222"]
}

variable "list_of_images" {
  type = "list"
  default = ["alpine", "java", "jenkins"]
}

# workaround for TF issue https://github.com/hashicorp/terraform/issues/20567
locals {
  policy_count = "${length(var.list_of_allowed_accounts) * length(var.list_of_images)}"
}

data "template_file" "ecr_policy_allowed_accounts" {
  count = "${local.policy_count}"

  template = "${file("${path.module}/ecr_policy.tpl")}"

  vars {
    account_id = "${var.list_of_allowed_accounts[count.index / length(var.list_of_images)]}"
    image      = "${var.list_of_images[count.index % length(var.list_of_images)]}"
  }
}

resource "aws_ecr_repository_policy" "repo_policy_allowed_accounts" {
  count = "${local.policy_count}"

  repository = "${var.list_of_images[count.index % length(var.list_of_images)]}"
  policy = "${data.template_file.ecr_policy_allowed_accounts.*.rendered[count.index]}"
} 
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.