아래와 같은 변수를 사용한다고 생각해보자
variable "subnet_cidrs" {
description = "Subnet CIDRs"
type = map(string)
default = {
pub-bastion = "10.0.0.0/24"
pri-db = "10.0.1.0/24"
pri-glue = "10.0.2.0/24"
pri-ecs = "10.0.3.0/24"
}
}
위 변수를 가지고 for_each
를 돌리게 된다면,
pub-bastion 과 pri-db 등의 이름들은 모두 each.key
로 분류되고, CIDR들은 모두 each.value
로 분류된다
이 때, 각 key들의 이름이 pub 또는 pri로 시작하게 강제하고 싶으므로 validation
구문을 사용해보겠다
Terraform Validation
https://www.terraform.io/language/values/variables#custom-validation-rules
예시 코드는 아래와 같다
# 가이드 제공 Code
variable "image_id" {
type = string
description = "The id of the machine image (AMI) to use for the server."
validation {
condition = length(var.image_id) > 4 && substr(var.image_id, 0, 4) == "ami-"
error_message = "The image_id value must be a valid AMI id, starting with \"ami-\"."
}
}
variable "image_id" {
type = string
description = "The id of the machine image (AMI) to use for the server."
validation {
# regex(...) fails if it cannot find a match
condition = can(regex("^ami-", var.image_id))
error_message = "The image_id value must be a valid AMI id, starting with \"ami-\"."
}
}
variable block
에 validation block
을 넣을 수 있으며, condition
조건에 맞지 않는 경우 error_message
의 문구를 내뱉는다
표현식이 실패했는지 아닌지로 condition
조건을 걸고 싶다면 can
함수를 사용할 수 있다
https://www.terraform.io/language/functions/can
+ can
은 이 validation
구문에서만 사용되도록 권장되는 듯 하다. 다른 부분에서는 try
함수를 사용하도록 하자.
아무튼 예시는 string
형식의 변수를 검사하는 것인데, 나는 map
변수의 모든 값을 검사하고 싶다
-> 당연히...validation
구문에서 dynamic block
을 사용하면 되지 않을까? 싶어서 아래 코드를 작성해봤다
variable "subnet_cidrs" {
description = "Subnet CIDRs"
type = map(string)
default = {
pub-bastion = "10.0.0.0/24"
pri-db = "10.0.1.0/24"
pri-glue = "10.0.2.0/24"
pri-ecs = "10.0.3.0/24"
}
dynamic "validation" {
for_each = var.subnet_cidrs
content {
condition = contains(["pub", "pri"], substr(validation.key, 0, 3))
error_message = "Subnet Name must start with pub or pri."
}
}
}
각 key의 앞 3글자를 따 왔을 때, pub or pri 인지를 확인할 수 있도록 했다
can은 오류가 있는지를 찾는 함수이기 때문에 여기선 필요가 없다
즉 false는 오류가 아니기 때문에, can(false)
는 true를 반환하므로, 위와 같이 contains
함수 등을 통해 true or false를 내뱉는 경우라면 can
을 사용하면 안된다
+ 참고로 error_message
는 .
또는 ?
로 끝나는 완전한 문장이지 않으면 오류가 난다
대체 왜,,,,,,하며 찾다가 아래 토론을 보게 되었다
https://github.com/hashicorp/terraform/issues/26205
음,,,암튼 이유가 있어서 validation
에서 dynamic
을 못쓰게 해둔 것 같다
그래도 for 표현식 사용해서 모두 맞는 표현인지를 검사할 수 있다는 솔루션을 얻었으므로 다시 시도해 보았다
우선 for 표현식부터 제대로 사용해보자
참조 : https://www.terraform.io/language/expressions/for
참조 (홍랩) : https://honglab.tistory.com/216
key값(인덱스)를 반환하기 위해선 한 쌍의 임시 기호를 써줘야 하더라
아무튼 이제 인덱스를 반환할 수 있게 되었으니, 인덱스를 검사하기만 하면 끝이다
> [for k in var.subnet_cidrs : k]
[
"10.0.1.0/24",
"10.0.3.0/24",
"10.0.2.0/24",
"10.0.0.0/24",
]
> [for k,s in var.subnet_cidrs : k]
[
"pri-db",
"pri-ecs",
"pri-glue",
"pub-bastion",
]
> [for k,s in var.subnet_cidrs : substr(k,0,3)]
[
"pri",
"pri",
"pri",
"pub",
]
> [for k,s in var.subnet_cidrs : contains(["pub","pri"],substr(k,0,3))]
[
true,
true,
true,
true,
]
> alltrue([for k,s in var.subnet_cidrs : contains(["pub","pri"],substr(k,0,3))])
true
참고로 위와 같이 테라폼 식 확인을 위한 대화형 cli는 terraform console 명령으로 사용할 수 있다
아무튼 alltrue 함수까지 사용해서 모든 인덱스 값이 pub or pri 로 시작하는지를 검사할 수 있게 되었으니, 실제 validation
구문에 적용해보자
variable "subnet_cidrs" {
description = "Subnet CIDRs"
type = map(string)
default = {
pub-bastion = "10.0.0.0/24"
pri-db = "10.0.1.0/24"
pri-glue = "10.0.2.0/24"
pri-ecs = "10.0.3.0/24"
}
validation {
condition = alltrue([for k,s in var.subnet_cidrs : contains(["pub", "pri"], substr(k, 0, 3))])
error_message = "Subnet Name must start with pub or pri."
}
}
일부러 서브넷 이름 하나를 바꿔서 plan
을 때려보았다
에러 메세지도 잘 나오는걸 확인할 수 있었다
끝
댓글