Lưu ý về null và ” “, try và coalesce khi khai báo biến Terraform

Vấn đề với try và default value của biến:

Ta có đoạn code như sau:

variable "example" {
  type    = string
  default = null
}

resource "aws_instance" "example_instance" {
  ami           = var.example != null ? var.example : "ami-0e047ce9149262f82"
  instance_type = "t2.micro"
}

output "ami_variable" {
  value = aws_instance.example_instance.ami
}

Kết quả:

Outputs:

ami_variable = "ami-0e047ce9149262f82"

1. Đặt default value là null và sử dụng try:

Sửa lại code như sau:

variable "example" {
  type    = string
  default = null
}

resource "aws_instance" "example_instance" {
  ami           = try(var.example, "ami-0e047ce9149262f82")
  instance_type = "t2.micro"
}

output "ami_variable" {
  value = aws_instance.example_instance.ami
}

Terraform apply:

aws_instance.example_instance: Refreshing state... [id=i-0d5ad3a92ec224e76]
╷
│ Error: Missing required argument
│
│   with aws_instance.example_instance,
│   on a.tf line 12, in resource "aws_instance" "example_instance":
│   12:   ami           = try(var.example, "ami-0e047ce9149262f82")
│
│ "ami": one of `ami,launch_template` must be specified

Nếu đặt default là null, mà dùng try thì sẽ lỗi! Tuy nhiên nếu đảo ngược lại vị trí như sau:

variable "example" {
  type    = string
  default = null
}

resource "aws_instance" "example_instance" {
  ami           = try("ami-0e047ce9149262f82", var.example)
  instance_type = "t2.micro"
}

output "ami_variable" {
  value = aws_instance.example_instance.ami
}

Thì kết quả trả về lại như sau:

Outputs:

ami_variable = "ami-0e047ce9149262f82"

Và nếu ta khai báo trong tfvars:

example = "ami-0464f90f5928bccb8"

Khi thực hiện apply lại:

Outputs:

ami_variable = "ami-0e047ce9149262f82"

try( ) không nhận giá trị mà ta truyền vào tfvars nữa, dù ta có destroy đi tạo lại do đã nhận được giá trị not null là ami-0464f90f5928bccb8 rồi.

Trường hợp này, kể cả dùng coalesce cũng không nhận giá trị tfvars do coalesce có đặc điểm tương tự try: nhận giá trị đầu tiên không phải null.

2. Default value là “” và sử dụng try:

variable "example" {
  type    = string
  default = ""
}

resource "aws_instance" "example_instance" {
  ami           = try(var.example, "ami-0e047ce9149262f82")
  instance_type = "t2.micro"
}

output "ami_variable" {
  value = aws_instance.example_instance.ami
}

Sẽ gặp lỗi như sau:

aws_instance.example_instance: Creating...
╷
│ Error: creating EC2 Instance: MissingParameter: The request must contain the parameter ImageId
│       status code: 400, request id: 8f5bc7e5-11ce-482b-ba6e-a1fe23d0f4bf
│
│   with aws_instance.example_instance,
│   on a.tf line 6, in resource "aws_instance" "example_instance":
│    6: resource "aws_instance" "example_instance" {
│

Với trường hợp đặt default là “” và không khai báo tfvars, sẽ chỉ đúng khi sử dụng coalesce!

Thử với coalesce:

Không sử dụng try nữa, mà dùng coalesce:

variable "example" {
  type    = string
  default = null
}

resource "aws_instance" "example_instance" {
  ami           = coalesce(var.example, "ami-0e047ce9149262f82")
  instance_type = "t2.micro"
}

output "ami_variable" {
  value = aws_instance.example_instance.ami
}

Kết quả:

Outputs:
ami_variable = "ami-0e047ce9149262f82"

Tiếp tục sửa như sau:

variable "example" {
  type    = string
  default = ""
}

resource "aws_instance" "example_instance" {
  ami           = coalesce(var.example, "ami-0e047ce9149262f82")
  instance_type = "t2.micro"
}

output "ami_variable" {
  value = aws_instance.example_instance.ami
}

Kết quả:

Outputs:
ami_variable = "ami-0e047ce9149262f82"

Bonus:

Trường hợp nếu tạo các AWS policy document khi sử dụng Terraform để tạo, mà lại dùng try, nếu không truyền policy nào thì chúng ta nên để default value = null, vì nếu để bằng “” thì try sẽ hiểu giá trị policy document = “”, mà IAM policy document lại không thể có giá trị là “”, sẽ dẫn tới việc Terraform cố gắng tạo resource rất lâu, rồi cuối cùng trả lỗi!