レビューの差分が空白だらけになった
한국어 원문으로 표시합니다.
목표
서식 판정·구조 검사·표현식 콘솔 세 가지를 직접 돌려 보고, 각각이 무엇을 잡고 무엇을 못 잡는지 경계를 확인합니다. 마지막에는 셋을 묶어 커밋 전에 도는 게이트를 손으로 만듭니다.
왜 중요한가
적용해 봐야 아는 것과 적용 전에 알 수 있는 것을 가르는 일이 이 모듈의 주제입니다. 서식은 도구가 정답을 하나로 정해 두었으므로 사람이 논쟁할 필요가 없습니다 — 판정만 하는 모드가 따로 있고 종료 코드가 다르게 나오니 그대로 게이트가 됩니다. 구조 검사는 설정 파일만 읽어 참조가 존재하는지, 필수 인자가 있는지, 타입이 스키마와 맞는지를 봅니다. 상태도 실물도 보지 않으므로 값이 틀린 것은 잡지 못합니다. 그 경계를 모르면 두 가지 사고가 납니다. 하나는 통과했으니 안전하다고 믿는 것이고, 다른 하나는 정적 검사로 잡을 수 있는 것을 계획까지 끌고 가 시간을 버리는 것입니다. 콘솔은 그 사이를 메웁니다 — 헷갈리는 표현식 하나 때문에 적용을 반복하는 대신 한 줄로 값을 확인합니다.
단계
/root/tfb-fmt/src/main.tf와/root/tfb-fmt/src/modules/net/main.tf를 만들되 들여쓰기와 등호 정렬을 일부러 어긋나게 쓰세요./root/tfb-fmt/src에서tofu fmt -check -diff -recursive를 돌려 출력을/root/tfb-fmt/fmt-before.txt에 저장하고, 마지막 줄에exit=<종료 코드>를 덧붙이세요./root/tfb-fmt/src에서tofu fmt -recursive로 실제로 고치고, 고쳐진 파일 이름 목록을/root/tfb-fmt/fmt-files.txt에 저장하세요. 그다음tofu fmt -check -recursive를 다시 돌려 출력과exit=<종료 코드>를/root/tfb-fmt/fmt-after.txt에 저장하세요./root/tfb-fmt/broken/main.tf에 값이 빠진 인자(예:filename =뒤에 아무것도 없음)를 두어 문법을 깨뜨리세요. 그 디렉터리에서tofu fmt -check -recursive를 돌려 출력과exit=<종료 코드>를/root/tfb-fmt/fmt-broken.txt에 저장하세요. 이 파일은 고치지 말고 그대로 둡니다./root/tfb-fmt/invalid/main.tf에 선언하지 않은 변수를 참조하는 리소스와, 문자열 자리에 목록을 넣은 리소스를 함께 두고 init 하세요.tofu validate -json출력을/root/tfb-fmt/validate.json에 저장하고, 거기서 읽은 값으로/root/tfb-fmt/validate-summary.txt에errors=<오류 개수>와summaries=<요약들을 사전순으로 콤마로 이은 것>두 줄을 적으세요./root/tfb-fmt/blind/main.tf에 기본값 없는 변수seed_path와, 그 경로를file()로 읽어 파일을 만드는 리소스를 두고 init 하세요.tofu validate는 통과하는데tofu plan은 두 가지 이유로 실패합니다. 값을 주지 않은 plan 과 없는 경로를 준 plan 을 각각 돌려 뒤쪽 출력을/root/tfb-fmt/blind-plan.txt에 저장하고,/root/tfb-fmt/blind-report.txt에validate=<종료 코드>,plan_novar=<종료 코드>,plan_missing=<종료 코드>세 줄을 적으세요. 없는 경로로는./inputs/seed.txt를 주고, 그 파일은 만들지 마세요./root/tfb-fmt/src를 init 하고/root/tfb-fmt/console-in.txt에 네 줄의 표현식을 적으세요 —join("-", [var.env, var.app, "01"]),length(toset(["a", "a", "b"])),"5" + 5,1 == "1". 그 파일을tofu console에 흘려 넣어 결과를/root/tfb-fmt/console-out.txt에 저장하세요./root/tfb-fmt/src/name.tf에local.name을 6단계 첫 표현식과 똑같이 정의하고, 그 값을 한 줄로 쓰는local_file.name으로name.txt를 만드세요. 새 파일도 서식이 맞아야 하고(fmt -check -recursive가 0),validate가 통과해야 하며, apply 까지 마치세요./root/tfb-fmt/precheck.sh를 만드세요. 첫 인자로 받은 디렉터리에 대해 서식 판정을 먼저 하고 통과하면 구조 검사를 합니다. 서식에서 걸리면fmt한 낱말을 찍고 0 이 아닌 코드로, 구조에서 걸리면validate를 찍고 0 이 아닌 코드로, 둘 다 통과하면ok를 찍고 0 으로 끝나야 합니다./root/tfb-fmt/src에 돌린 결과를/root/tfb-fmt/precheck-src.txt에,/root/tfb-fmt/broken에 돌린 결과를/root/tfb-fmt/precheck-broken.txt에 저장하고 각 파일 끝에exit=<종료 코드>를 덧붙이세요.
참고
tofu fmt는 판정만 하는 모드와 실제로 고치는 모드가 다릅니다. 게이트에는 저장소를 바꾸지 않는 쪽을 씁니다.tofu validate와tofu console은 프로바이더 스키마가 필요해서 init 을 먼저 해야 합니다.tofu fmt는 init 없이도 돕니다.- 흔한 실수: 3단계의 깨진 파일을 고쳐 버리는 것. 이 단계는 읽을 수 없는 파일일 때의 종료 코드를 남기는 것이 과제입니다.
- 흔한 실수: 5단계에서
./inputs/seed.txt를 만들어 plan 을 성공시키는 것. 이 단계는 정적 검사가 못 보는 것을 보이는 것이 과제입니다. - tofu fmt · tofu validate · tofu console · 함수 목록 · terraform fmt (HashiCorp)
서식이 어긋난 트리를 찾아낸다
/root/tfb-fmt/src/main.tf 와 /root/tfb-fmt/src/modules/net/main.tf 를 만들되 들여쓰기와 등호 정렬을 일부러 어긋나게 쓰세요. /root/tfb-fmt/src 에서 tofu fmt -check -diff -recursive 를 돌려 출력을 /root/tfb-fmt/fmt-before.txt 에 저장하고, 마지막 줄에 exit=<종료 코드> 를 덧붙이세요.
이 명령은 파일을 고치지 않고 판정만 합니다. 고칠 것이 있을 때의 종료 코드가 0 과 다르다는 점이 게이트로 쓸 수 있는 이유입니다. -diff 는 무엇을 어떻게 고칠지 보여 줍니다.
고치고 다시 확인한다
/root/tfb-fmt/src 에서 tofu fmt -recursive 로 실제로 고치고, 고쳐진 파일 이름 목록을 /root/tfb-fmt/fmt-files.txt 에 저장하세요. 그다음 tofu fmt -check -recursive 를 다시 돌려 출력과 exit=<종료 코드> 를 /root/tfb-fmt/fmt-after.txt 에 저장하세요.
고치는 모드는 바꾼 파일의 이름만 한 줄씩 찍습니다. 하위 디렉터리까지 도는 옵션이 없으면 루트의 파일만 봅니다 — 둘 다 목록에 들어와야 합니다.
문법이 깨진 파일은 서식 판정과 종료 코드가 다르다
/root/tfb-fmt/broken/main.tf 에 값이 빠진 인자(예: filename = 뒤에 아무것도 없음)를 두어 문법을 깨뜨리세요. 그 디렉터리에서 tofu fmt -check -recursive 를 돌려 출력과 exit=<종료 코드> 를 /root/tfb-fmt/fmt-broken.txt 에 저장하세요. 이 파일은 고치지 말고 그대로 둡니다.
서식을 고치려면 먼저 파일을 읽을 수 있어야 합니다. 읽을 수 없을 때의 종료 코드는 '고칠 것이 있다' 와 또 다릅니다. 게이트를 만들 때 이 둘을 한 덩어리로 다뤄도 되는지 생각해 보세요.
validate 가 잡는 것 — 참조·필수 인자·타입
/root/tfb-fmt/invalid/main.tf 에 선언하지 않은 변수를 참조하는 리소스와, 문자열 자리에 목록을 넣은 리소스를 함께 두고 init 하세요. tofu validate -json 출력을 /root/tfb-fmt/validate.json 에 저장하고, 거기서 읽은 값으로 /root/tfb-fmt/validate-summary.txt 에 errors=<오류 개수> 와 summaries=<요약들을 사전순으로 콤마로 이은 것> 두 줄을 적으세요.
validate 는 값이 아니라 구조를 봅니다. 참조가 존재하는지, 필수 인자가 있는지, 넣은 값의 타입이 스키마와 맞는지입니다. -json 을 쓰면 사람이 아니라 CI 가 읽을 수 있습니다.
validate 가 못 잡는 것 — 값
/root/tfb-fmt/blind/main.tf 에 기본값 없는 변수 seed_path 와, 그 경로를 file() 로 읽어 파일을 만드는 리소스를 두고 init 하세요. tofu validate 는 통과하는데 tofu plan 은 두 가지 이유로 실패합니다. 값을 주지 않은 plan 과 없는 경로를 준 plan 을 각각 돌려 뒤쪽 출력을 /root/tfb-fmt/blind-plan.txt 에 저장하고, /root/tfb-fmt/blind-report.txt 에 validate=<종료 코드>, plan_novar=<종료 코드>, plan_missing=<종료 코드> 세 줄을 적으세요. 없는 경로로는 ./inputs/seed.txt 를 주고, 그 파일은 만들지 마세요.
정적 검사는 설정 파일만 읽습니다. 변수에 어떤 값이 들어올지, 그 경로에 파일이 있는지는 설정 파일 밖의 사실이라 알 수 없습니다. 그래서 validate 통과는 '적용해도 된다' 는 뜻이 아닙니다.
표현식은 콘솔에서 한 줄로 확인한다
/root/tfb-fmt/src 를 init 하고 /root/tfb-fmt/console-in.txt 에 네 줄의 표현식을 적으세요 — join("-", [var.env, var.app, "01"]), length(toset(["a", "a", "b"])), "5" + 5, 1 == "1". 그 파일을 tofu console 에 흘려 넣어 결과를 /root/tfb-fmt/console-out.txt 에 저장하세요.
콘솔은 지금 디렉터리의 변수와 locals 를 그대로 읽습니다. 뒤 두 줄은 일부러 헷갈리는 것입니다 — 더하기에서 일어나는 변환과 같다 비교에서 일어나지 않는 변환이 다릅니다.
확인한 표현식을 설정에 넣는다
/root/tfb-fmt/src/name.tf 에 local.name 을 6단계 첫 표현식과 똑같이 정의하고, 그 값을 한 줄로 쓰는 local_file.name 으로 name.txt 를 만드세요. 새 파일도 서식이 맞아야 하고(fmt -check -recursive 가 0), validate 가 통과해야 하며, apply 까지 마치세요.
콘솔에서 확인한 표현식을 그대로 옮기면 값이 맞는지 다시 고민할 필요가 없습니다. 파일을 새로 만들었으니 서식 판정도 다시 통과해야 합니다 — 게이트를 만들기 전에 몸에 익혀 둘 순서입니다.
커밋 전에 도는 정적 검사 게이트를 만든다
/root/tfb-fmt/precheck.sh 를 만드세요. 첫 인자로 받은 디렉터리에 대해 서식 판정을 먼저 하고 통과하면 구조 검사를 합니다. 서식에서 걸리면 fmt 한 낱말을 찍고 0 이 아닌 코드로, 구조에서 걸리면 validate 를 찍고 0 이 아닌 코드로, 둘 다 통과하면 ok 를 찍고 0 으로 끝나야 합니다. /root/tfb-fmt/src 에 돌린 결과를 /root/tfb-fmt/precheck-src.txt 에, /root/tfb-fmt/broken 에 돌린 결과를 /root/tfb-fmt/precheck-broken.txt 에 저장하고 각 파일 끝에 exit=<종료 코드> 를 덧붙이세요.
순서가 중요합니다. 읽을 수 없는 파일이 섞여 있으면 구조 검사도 의미가 없으니 서식 판정이 먼저입니다. 판정만 하고 고치지 않는 옵션을 써야 게이트가 저장소를 바꾸지 않습니다.