Terraform assign default to local variable

Viewed 1895

I have the following code in my variables.tfvars:

variable "is_premium_service_bus_required" {
  description = "When set to 1, premium service bus will be created"
  type        = "string"
  default     = "0"
}

variable "service_bus_type_cloud" {
  description = "Type of service bus to be created, value can only be standard or premium"
  type        = "string"
}

Following code to create the azure resource:

resource "azurerm_servicebus_namespace" "premium-ffdac-cloud-servicebus" {
  count               = "${var.is_premium_service_bus_required}"
  name                = "${terraform.workspace}-ffdac-cloud-sbus"
  location            = "west europe"
  resource_group_name = "fusson"
  sku                 = "Premium"
  capacity            = "1"   
}

resource "azurerm_servicebus_namespace" "ffdac-cloud-servicebus" {
  name                = "${terraform.workspace}-ffdac-cloud-servicebus"
  location            = "west europe"
  resource_group_name = "fusson"
  sku                 = "Standard"
}

As it can be seen, we manipulate the creation of a resource on Azure by setting the variable value: is_premium_service_bus_required either to 0(not created) or 1 (gets created)

And I have the following local variables:

locals {
  standard_service_bus_cloud_connection_string = "${azurerm_servicebus_namespace.ffdac-cloud-servicebus.default_primary_connection_string};TransportType=Amqp"
}


locals {
  premium_service_bus_cloud_connection_string = "${azurerm_servicebus_namespace.premium-ffdac-cloud-servicebus.default_primary_connection_string};TransportType=Amqp"
}

which simply is responsible for manipulating the default connection string and adding the protocol at the end.

and we have the following code which determines based on the value of "service_bus_type_cloud", what value should be assigned to "service_bus_cloud_connection_string" variable which later is used in a different terraform file.

locals {
  service_bus_type_cloud_names = {
    "premium"  = "${local.premium_service_bus_cloud_connection_string}"
    "standard" = "${local.standard_service_bus_cloud_connection_string}"
  }

  cloud_connection_string_default = "${local.standard_service_bus_cloud_connection_string}"

  service_bus_cloud_connection_string = "${lookup(local.service_bus_type_cloud_names, var.service_bus_type_cloud, local.cloud_connection_string_default)}"
}

The problem now is, when the value of "is_premium_service_bus_required" is set to "0", premium service bus azure service is not created and the local variable "premium_service_bus_cloud_connection_string" value is empty, and we end up getting the following error:

Error: Error running plan: 1 errors occurred:
    * local.premium_service_bus_cloud_connection_string: local.premium_service_bus_cloud_connection_string: Resource 'azurerm_servicebus_namespace.premium-ffdac-cloud-servicebus' not found for variable 'azurerm_servicebus_namespace.premium-ffdac-cloud-servicebus.default_primary_connection_string'

Is there a way we circumvent this error or a better way to rewrite the logic? We are running Terraform version 0.11, hence conditional operator mentioned here cannot be used as using the following code:

locals {
  service_bus_cloud_connection_string = "${var.service_bus_type_cloud == "premium" ? "${azurerm_servicebus_namespace.premium-ffdac-cloud-servicebus.default_primary_connection_string};TransportType=Amqp" : "${azurerm_servicebus_namespace.ffdac-cloud-servicebus.default_primary_connection_string};TransportType=Amqp"}"
}

will evaulate both value expressions even though only one is ever returned and it seems to be a bug that was fixed in 0.12 as seen here

3 Answers

You can still use the conditionals (Terraform v0.11.14). Here is the code.

variable "is_premium_service_bus_required" {
  description = "When set to 1, premium service bus will be created"
  type = "string"
  default     = "0"
}

locals {
  standard_service_bus_cloud_connection_string = "${var.is_premium_service_bus_required == "0" ? "non_premium_connection_string" : "premium_connection_string"}"
}

output "is_required" {
  value = "${local.standard_service_bus_cloud_connection_string}"
}

Here is the output.

[PS][7.0.2] tst > terraform11.exe apply -var "is_premium_service_bus_required=0"

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

is_required = non_premium_connection_string


[PS][7.0.2] tst > terraform11.exe apply -var "is_premium_service_bus_required=1"

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

is_required = premium_connection_string

As I see, you want to create a service bus with different types that according to the condition. And then get the connect string of the service bus. I do not know is the standard type is a necessary one. I assume it's not necessary. Then you can change into this:

variable "is_premium_service_bus_required" {
  description = "When set to 1, premium service bus will be created"
  type        = "bool"
  default     = true
}

resource "azurerm_servicebus_namespace" "ffdac-cloud-servicebus" {
  count               = "${var.is_premium_service_bus_required}" ? 1 : 0
  name                = "${terraform.workspace}-ffdac-cloud-servicebus"
  location            = "west europe"
  resource_group_name = "fusson"
  sku                 = "${var.is_premium_service_bus_required}" ? "Premium" : "Standard"
}

At this situation, you can get the connection string directly with "${azurerm_servicebus_namespace.ffdac-cloud-servicebus.default_primary_connection_string};TransportType=Amqp" as you displayed in the code.

But if the standard type is necessary, it would be a little more complex:

variable "is_premium_service_bus_required" {
  description = "When set to 1, premium service bus will be created"
  type        = "bool"
  default     = true
}

variable "service_bus_type_cloud" {
  description = "Type of service bus to be created, value can only be standard or premium"
  type        = "string"
}

resource "azurerm_servicebus_namespace" "premium-ffdac-cloud-servicebus" {
  count               = "${var.is_premium_service_bus_required}" ? 1 : 0
  name                = "${terraform.workspace}-ffdac-cloud-sbus"
  location            = "west europe"
  resource_group_name = "fusson"
  sku                 = "Premium"
  capacity            = "1"   
}

resource "azurerm_servicebus_namespace" "ffdac-cloud-servicebus" {
  name                = "${terraform.workspace}-ffdac-cloud-servicebus"
  location            = "west europe"
  resource_group_name = "fusson"
  sku                 = "Standard"
}

locals {
  service_bus_cloud_connection_string = "${var.is_premium_service_bus_required}" && "${var.service_bus_type_cloud}" == "premium" ? "${azurerm_servicebus_namespace.premium-ffdac-cloud-servicebus[0].default_primary_connection_string};TransportType=Amqp" : "${azurerm_servicebus_namespace.ffdac-cloud-servicebus.default_primary_connection_string};TransportType=Amqp"
}

At this situation, only when the variable is_premium_service_bus_required is true and the variable service_bus_type_cloud is "premium", then you get the premium service bus connection string, or you will get the standard.

should be much easier to create only one object and to adjust the parameters based on the input variable. To have a map with the params for standard and the params for premium.

Related