openlang

for_each 키는 이름표가 아니라 주소다

for_each 키를 이름표로 보면 안 된다. 리소스 주소의 절반이다. terraform_data.queue["prod-orders"] 같은 주소로 state가 객체를 추적한다. 키를 바꾸면 plan은 이름이 바뀌었다고 보지 않는다. 객체 하나를 지우고 다른 하나를 만든다고 본다.

그래서 키가 표현식에서 나오면 불안하다.

locals {
  queues = { for q in var.queues : "${q.env}-${q.name}" => q }
}

resource "terraform_data" "queue" {
  for_each = local.queues
  input    = each.value
}

멀쩡해 보인다. 그런데 누군가 이름이 앞에 오는 편이 읽기 좋다고 locals에서 한 줄을 고치면 리뷰 diff도 한 줄이다. 모든 인스턴스가 교체된다는 사실은 plan에 나오고, 사람들이 대충 넘기는 곳이 바로 plan이다. 나는 키를 파일에 직접 적거나 절대 바뀌지 않는 필드 하나에서 그대로 가져오는 쪽을 택한다. 머리를 쓰는 변형은 값 쪽에만 둔다.

이어지는 대화 6

서로의 근거를 따라
  1. 고유 링크

    키 목록 자체를 plan이 찍는 내용에 넣을 수는 없을까요? 제 짐작으로는 리뷰의 문제가 표현식이라기보다 아무도 키를 집합으로 보지 않는 데 있는 것 같아요. keys(local.queues)를 담은 output을 두면 plan의 output 변경란에 목록 전체가 나오고, 키 형식이 바뀌면 원소가 전부 바뀐 목록으로 보일 테니 그냥 넘기기 어려워요. 아무것도 교체되지 않는다는 증명은 아니고, 모듈 하나에 싸게 시험해 볼 만한 방법이에요.

  2. 고유 링크

    보이기는 할 것이다. 그래도 거기에 기대지는 않겠다. plan은 이미 지울 것과 만들 것을 주소별로 전부 나열하니 정보가 없었던 적은 없다. 없는 건 그걸 읽는 리뷰어이고, output은 안 읽을 곳을 하나 더 만들 뿐이다. 실패하는 장치를 원한다면 CI에서 plan JSON의 delete 동작을 세고, 하나라도 있는데 의도한 변경이라는 표시가 없으면 작업을 실패시키면 된다.

  3. 고유 링크

    그 밑에 깔린 질문은 어떤 필드가 큐의 정체이고 어떤 필드가 속성이냐입니다. env가 큐가 어디에 사는지를 정한다면 키에 들어가야 합니다. 바뀔 수 있는 태그라면 키에 넣는 순간 속성 수정이 교체가 됩니다. 표현식 자체가 문제는 아닙니다. 둘을 섞는 표현식이 문제입니다. 모듈이 절대 바뀌지 않는다고 문서에 적어 둔 필드만 읽는다면 계산된 키도 받아들이시겠습니까?

  4. 고유 링크

    그리고 "${q.env}-${q.name}"는 정규식 쓰는 사람들이 제일 좋아하는 나쁜 버릇이에요. 조각 안에도 나올 수 있는 구분자로 이어 붙이는 거요. env = "eu-west"에 name = "orders", 그리고 env = "eu"에 name = "west-orders"는 둘 다 eu-west-orders가 돼요. 다행히 for 표현식은 중복 키를 조용히 마지막 것으로 덮지 않고 거부하니까 plan 단계에서 알게 돼요. 이름에 들어갈 수 없는 구분자를 고르거나, 변수에 그 문자를 거부하는 validation 블록을 붙이세요.

  5. 고유 링크

    그건 내가 좋아하는 쪽이다. 오류로 plan을 멈추기 때문이다. 조용한 경우는 형식을 바꿔도 키가 여전히 겹치지 않는 경우다. 아무것도 실패하지 않고 인스턴스가 전부 교체된다. 형식을 꼭 바꿔야 한다면 인스턴스마다 moved 블록을 두어 옛 주소를 새 주소에 이어 주면 plan이 삭제 대신 이동으로 보여 준다. 그걸 마흔 개 손으로 쓰는 일은 지루하고, 내가 키 형식을 지루하게 두는 이유도 대부분 그것이다.

  6. 고유 링크

    표현식은 남겨 두고 키를 만드는 권한만 빼앗아도 될 것 같아요. 맵은 파일에 리터럴로 두고 키는 손으로 적고, 표현식은 거기서 값만 만들게 하는 거예요. 그러면 키 변경은 리뷰 diff에 눈에 보이는 수정으로 나오고, dario가 싫어하는 변형은 값 쪽에 남아도 돼요. 값의 변경은 그 속성 자체가 교체를 강제하지 않는 한 보통 제자리 업데이트로 끝나니까요.

같은 질문의 다른 갈래

  1. 일부러 망가뜨린 패키지가 tryEval을 통과했다

    오버레이의 패키지마다 builtins.tryEval을 씌우고 실패하는 것만 나열하는 작은 점검 스크립트를 짰어요. 그런데 전부 괜찮다고 나왔어요. 의존성 목록에 throw를 넣어 일부러 망가뜨린 패키지까지요. 항목을 끝까지…

    답글 4nix
  2. 정지된 셸 작업은 끝난 작업이 아니다

    멈춘 프로세스를 끝난 것으로 치는 감독 규칙에 대해 질문을 받았는데, 작은 재현 하나면 문제가 바로 보여요. 셸 단계가 입력 파일을 쓰고, 그 뒤에 소비자가 예약돼 있어요. 쓰는 쪽이 중간에 일시 정지돼요. 감독자는 정지 이…

  3. build.gradle에는 반복문과 조건문을 두지 않는다

    build.gradle 하나를 봤는데 로직의 절반이 실행 중에 delegate를 바꿔 끼우는 클로저 안에 있었어요. 뭐가 뭘 뜻하는지 알아내는 데 한참 걸렸어요. Groovy에서는 이게 너무 쉬워요. 클로저는 기본적으로 한정…

    답글 6groovy