Terraform - Sử dụng các vòng lặp lồng nhau với số lượng


18

Tôi đang cố gắng sử dụng một vòng lặp lồng nhau trong terraform. Tôi có hai biến danh sách list_of_allowed_accountslist_of_images, và tìm cách lặp qua danh sách list_of_imagesvà sau đó lặp qua danh sách list_of_allowed_accounts.

Đây là mã terraform của tôi.

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}"
}

Đây là một bash tương đương với những gì tôi đang cố gắng làm.

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

Câu trả lời:


34

Terraform không có hỗ trợ trực tiếp cho kiểu lặp lồng nhau này, nhưng chúng ta có thể giả mạo nó bằng một số số học.

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]}"
}

Vì chúng tôi muốn tạo một mẫu chính sách cho mọi kết hợp tài khoản và hình ảnh, nên counttrên template_filekhối dữ liệu là hai nhân với nhau. Sau đó chúng ta có thể sử dụng các phép toán chia và modulo để quay lại từ count.indexcác chỉ số riêng biệt vào mỗi danh sách.

Vì tôi không có bản sao mẫu chính sách của bạn, tôi chỉ sử dụng một mẫu giữ chỗ; cấu hình này do đó đưa ra kế hoạch sau:

+ 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"

Mỗi phiên bản chính sách áp dụng cho một cặp id tài khoản và hình ảnh khác nhau, bao gồm tất cả các kết hợp.


2
Sẽ gây rắc rối cho bạn nếu bạn muốn mở rộng cấu hình, như thêm tài khoản mới hoặc / và hình ảnh, hơn là tài nguyên của bạn sẽ ánh xạ tới các chỉ mục khác nhau, tuy nhiên nếu xóa và tạo lại chúng không phải là vấn đề thì điều này hoạt động tốt.
balazs

1
@ justin-grote có một điểm trong câu trả lời của anh ấy: trong terraform 0.12, bạn sẽ cần sử dụng hàm sàn bất cứ nơi nào bạn chia, nếu không bạn sẽ gặp lỗi về chỉ mục một phần. account_id = var.list_of_allowed_accounts[floor(count.index / length(var.list_of_images))]
chriscatfr

7

Các câu trả lời ở đây có tác dụng (ban đầu tôi đã sử dụng chúng), nhưng tôi nghĩ rằng tôi có một giải pháp tốt hơn bằng cách sử dụng chức năng setproduct của Terraform . Tôi đã không thấy nhiều ví dụ về nó được sử dụng xung quanh các interwebs, nhưng setproduct mất hai bộ (hoặc quan trọng hơn là hai danh sách) và tạo ra một danh sách các bộ với mọi hoán vị của đầu vào. Trong trường hợp của tôi, tôi đang tạo các tham số 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"] }
}

Điều này tạo ra các tham số SSM có tên:

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

Bộ não nhỏ bé đáng sợ của tôi có thể phân tích điều này dễ hơn một chút so với phép thuật modulo trong các câu trả lời khác!


Tôi sẽ thử giải pháp của bạn. Tôi đồng ý nó có vẻ tốt hơn nhiều. Nhưng tại sao bạn sử dụng ${length(var.list1) * length(var.list2)}thay vì ${length(local.product)}cho số lượng?
chriscatfr

Tôi sẽ phải đợi cho đến khi khách hàng của tôi bắt đầu sử dụng v0.12 :( không có lý do tại sao bạn không tìm thấy nhiều nguồn.
chriscatfr

Không có lý do, ${length(local.product)}có lẽ làm cho nhiều hơn kể từ đó. Ngoài ra, tôi khá chắc chắn setproduct()tồn tại trước 0,12, (thông điệp ở đầu trang được liên kết chỉ là một cảnh báo chung cho tất cả các tài liệu 0.11 của họ, tôi nghĩ vậy?)
Kyle

4

FYI nếu bất cứ ai đến từ Google, nếu bạn đang sử dụng terraform 0.12, bạn sẽ cần sử dụng chức năng sàn bất cứ nơi nào bạn chia, nếu không bạn sẽ gặp lỗi về chỉ mục một phần.

account_id = var.list_of_allowed_accounts [ sàn (Count.index / length (var.list_of_images))]


Tôi ước tôi đã đọc hết trang SO để khám phá viên ngọc này trước khi tôi thử phương pháp toán học. Đây là cách tôi làm cho nó hoạt động với sàn (Count.index / 8). Cảm ơn vì đăng.
bytejunkie

với 0,12 setproduct () từ giải pháp của @kyle có vẻ dễ dàng hơn.
chriscatfr

Nếu bạn đang ở trên Terraform 0.12, thì tại sao không sử dụng mới được thêm vào for, for_eachvà / hoặc cấu trúc năng động lồng khối ngôn ngữ để thực hiện một cái gì đó một chút ít khó hiểu?
TrinitronX

0

Về cơ bản, vấn đề nằm ở dữ liệu "template_file", tài khoản_id không thể được đặt theo cách bạn nghĩ vì số đếm trong trường hợp của bạn chỉ là một var không bao giờ được tăng / thay đổi. Chỉ cần nói vì tôi nhớ để xem chính xác câu hỏi của bạn là gì.


0

Tôi không có đủ điểm danh tiếng để thêm nhận xét cho câu trả lời do @ Martin Atkins cung cấp , vì vậy tôi đang đăng câu trả lời của anh ấy với một sửa đổi nhỏ, hoạt động xung quanh vấn đề 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]}"
} 
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.