Use a Simulated CASE Statement in Terraform to Manage the Oracle Process Value

Introduction

Below is an example on how to use a simulated CASE statement in Terraform to manage the Oracle process value.

In this example, we need to use the process value to set an a variable which will be used to configure an alarm for "too many processes" in Oracle.

The challenge

The challenge is, the process value in AWS is derived from the instance memory, which changes by instance type.

The process parameter for any given instance is configured using the following formula

processes = LEAST({DBInstanceClassMemory/9868951}, 20000)

Furthermore, we want to alert when the number of processes in Terraform reaches 80% of the maximum.

So first of all, we need to know the process value for any given instance. Here is the values for thr rgi class of machines. You will need to capture the values for other classes yourself, if you are running Oracle on a different class.

r6i_large_process= 1655
r6i_xlarge_process= 3341
r6i_2xlarge_process= 6715
r6i_4xlarge_process= 13462
r6i_8xlarge_process= 20000
r6i_12xlarge_process= 20000
r6i_16xlarge_process= 20000
r6i_24xlarge_process= 20000
r6i_32xlarge_process= 20000

You can see from above that from 8xlarge onwards the process value is fixed at 20,000. This is due to the formula above.

Simulating a CASE Statement

Having captured the process values in a Terraform variable, we can now use those variables and create a simulated case statement to set the threshold for the Process alert. Normally a case statement would look something like this

case $LIST in
  value1)  do something
  value2) do something else
  value3) etc
  *) every other value
esac

Well we cant do anything like that in Terraform. This is because Terraform is not know for its logic capability. If, then, else is possible (of sorts), case is not. (currently) But due to the limited if, then, else capability, you can simulate a case statement. So we can set a variable based on some logic. The format is as follows

myVariable = condition ? then logic : else logic

So, how can we use this construct for our CASE statement. Well, lets take a previously set instance class variable and use that in our check condition, along with one of our instance class process variables above in the then condition. And place the result into a new Terraform variable called rds_connections_large. Like this

rds_connections_large = "${var.rds_instance_class == "db.r6i.large" ? var.r6i_large_process*0.8 : ""}"

So this is saying, if the rds_instance_cless = db.r6i.large, then set the rds_connections_large variable to var.r6i_large_process*0.8, otherwise set the variable to "".

The result is, rds_connections_large gets set to 80% of the process value. e.g. Our alert threshold will be set to 80%

But this only deals with a single instance type. e.g. db.r6i.large No problem lets add the others, like this

  rds_connections_large = "${var.rds_instance_class == "db.r6i.large" ? var.r6i_large_process*0.8 : ""}"
  rds_connections_xlarge = "${var.rds_instance_class == "db.r6i.xlarge" ? var.r6i_xlarge_process*0.8 : ""}"
  rds_connections_2xlarge = "${var.rds_instance_class == "db.r6i.2xlarge" ? var.r6i_2xlarge_process*0.8 : ""}"
  rds_connections_4xlarge = "${var.rds_instance_class == "db.r6i.4xlarge" ? var.r6i_4xlarge_process*0.8 : ""}"
  rds_connections_8xlarge = "${var.rds_instance_class == "db.r6i.8xlarge" ? var.r6i_8xlarge_process*0.8 : ""}"
  rds_connections_12xlarge = "${var.rds_instance_class == "db.r6i.12xlarge" ? var.r6i_12xlarge_process*0.8 : ""}"
  rds_connections_16xlarge = "${var.rds_instance_class == "db.r6i.16xlarge" ? var.r6i_16xlarge_process*0.8 : ""}"
  rds_connections_24xlarge = "${var.rds_instance_class == "db.r6i.24xlarge" ? var.r6i_24xlarge_process*0.8 : ""}"
  rds_connections_32xlarge = "${var.rds_instance_class == "db.r6i.32xlarge" ? var.r6i_32xlarge_process*0.8 : ""}"

However, this just provides a number of different threshold variables based on the instance class. We need a single variable to pass into our threshold parameter variable.

The way we do this, is to coalesce all the variables into one using this bit of code

rds_connections = "${coalesce(local.rds_connections_large, local.rds_connections_xlarge, local.rds_connections_2xlarge, local.rds_connections_4xlarge, local.rds_connections_8xlarge, local.rds_connections_12xlarge, local.rds_connections_16xlarge, local.rds_connections_24xlarge,local.rds_connections_32xlarge)}"

So there you have it. A simulated case statement, albeit without a catch all. The variable rds_connections will get set to the threashold based on the instance type and can be used for the alert threashold.

NOTE - I think its fair to say, that what I describe above is not meant to be elegant, or even a good piece of code. If fact, its ugly. Very ugly. But it can get you out of a bind when you need a CASE like logic block.

Here is the code in full

Code

variable "r6i_large_process" {
  default = 1655
}

variable "r6i_xlarge_process" {
  default = 3341
}

variable "r6i_2xlarge_process" {
  default = 6715
}

variable "r6i_4xlarge_process" {
  default = 13462
}

variable "r6i_8xlarge_process" {
  default = 20000
}

variable "r6i_12xlarge_process" {
  default = 20000
}

variable "r6i_16xlarge_process" {
  default = 20000
}

variable "r6i_24xlarge_process" {
  default = 20000
}

variable "r6i_32xlarge_process" {
  default = 20000
}

locals {
  rds_connections_large = "${var.rds_instance_class == "db.r6i.large" ? var.r6i_large_process*0.8 : ""}"
  rds_connections_xlarge = "${var.rds_instance_class == "db.r6i.xlarge" ? var.r6i_xlarge_process*0.8 : ""}"
  rds_connections_2xlarge = "${var.rds_instance_class == "db.r6i.2xlarge" ? var.r6i_2xlarge_process*0.8 : ""}"
  rds_connections_4xlarge = "${var.rds_instance_class == "db.r6i.4xlarge" ? var.r6i_4xlarge_process*0.8 : ""}"
  rds_connections_8xlarge = "${var.rds_instance_class == "db.r6i.8xlarge" ? var.r6i_8xlarge_process*0.8 : ""}"
  rds_connections_12xlarge = "${var.rds_instance_class == "db.r6i.12xlarge" ? var.r6i_12xlarge_process*0.8 : ""}"
  rds_connections_16xlarge = "${var.rds_instance_class == "db.r6i.16xlarge" ? var.r6i_16xlarge_process*0.8 : ""}"
  rds_connections_24xlarge = "${var.rds_instance_class == "db.r6i.24xlarge" ? var.r6i_24xlarge_process*0.8 : ""}"
  rds_connections_32xlarge = "${var.rds_instance_class == "db.r6i.32xlarge" ? var.r6i_32xlarge_process*0.8 : ""}"
  rds_connections = "${coalesce(local.rds_connections_large, local.rds_connections_xlarge, local.rds_connections_2xlarge, local.rds_connections_4xlarge, local.rds_connections_8xlarge, local.rds_connections_12xlarge, local.rds_connections_16xlarge, local.rds_connections_24xlarge,local.rds_connections_32xlarge)}"
}

Published 7th November 2023

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License