[Terraform functions ứng dụng] Count conditional create với variable type là object trong Terraform

1. Tình huống

Object variable:

variable "autoscaling_read" {
  description = "A map of read autoscaling settings."
  type        = object({
    max_capacity = optional(number)
    scale_in_cooldown = optional(number)
    scale_out_cooldown = optional(number)
    target_value = optional(number)
  })
  default     = {}
}

Bây giờ bạn muốn một tình huống như sau:

Nếu biến này không được khai báo, thì sẽ không tạo ra resource nào cả, nhưng chỉ cần có một parameter được khai báo thôi thì sẽ tạo resource.

Nếu bạn tạo điều kiện bằng for_each thì dễ quá rồi, nhưng có một số trường hợp, tôi lại muốn tạo điều kiện bằng count cơ. Tôi sẽ dùng length biến này chăng? Không được!

Mặc định khi biến tạo ra, đã luôn có length bằng 4 rồi.

2. Giải quyết

Code xử lý:

resource "aws_appautoscaling_target" "table_read" {
  count = var.create_table && var.autoscaling_enabled && anytrue([for i in var.autoscaling_read : i != null]) ? 1 : 0

  max_capacity       = var.autoscaling_read["max_capacity"]
  min_capacity       = var.read_capacity
  resource_id        = "table/${try(aws_dynamodb_table.autoscaled[0].name, aws_dynamodb_table.autoscaled_gsi_ignore[0].name)}"
  scalable_dimension = "dynamodb:table:ReadCapacityUnits"
  service_namespace  = "dynamodb"
}

Nếu bạn dùng điều kiện length(var.autoscaling_enabled) == 0 thì sẽ không đúng! Điều kiện length chỉ đúng khi bạn define biến là 1 list chứ không phải 1 object. Nếu bạn viết dạng: var.autoscaling_read.max_capacity == null && var.autoscaling_read.scale_in_cooldown && var.autoscaling_read.scale_out_cooldown && var.autoscaling_read.target_value thì quá mức dài, và nếu object có nhiều attribute khác thì sao? => anytrue hoặc alltrue là giải pháp cho trường hợp này!

Nếu type của variable là map of object, không phải là 1 object nữa:

variable "autoscaling_read" {
  description = "A map of read autoscaling settings."
  type        = map(object({
    max_capacity = optional(number)
    scale_in_cooldown = optional(number)
    scale_out_cooldown = optional(number)
    target_value = optional(number)
  }))
  default     = {
    1 = {
        max_capacity = 15
    }
    2 = {
        max_capacity = 40
    }
    3 = {}
  }
}

Check thử các điều kiện bằng terraform console:

> alltrue([for i in var.autoscaling_read : i != null])
true

> anytrue([for i in var.autoscaling_read : i != null])
true

> anytrue([for i in var.autoscaling_read : i == null])
false

> alltrue([for i in var.autoscaling_read : i == null])
false

> anytrue([for i in var.autoscaling_read : i.max_capacity == null])
true

> alltrue([for i in var.autoscaling_read : i.max_capacity == null])
false

Dựa vào giá trị true hoặc false trả về của terraform console, bạn có thể define các condition cho phù hợp.

3. Bonus:

Conditional create a list of object:

variable.tf:

variable "instances" {
  description = "List of instances"
  type        = list(object({
    name          = string
    create        = bool
    instance_type = string
  }))
  default = [
    {
      name          = "instance1"
      create        = true
      instance_type = "t2.micro"
    },
    {
      name          = "instance2"
      create        = false
      instance_type = "t2.micro"
    },
  ]
}

Code:

resource "aws_instance" "example" {
  for_each      = { for i in var.instances : i.name => i if i.create }
  ami           = "ami-0c94855ba95c574c8"
  instance_type = each.value.instance_type

  tags = {
    Name = each.key
  }
}