Search code examples
azureterraformazureservicebusterraform-provider-azureterraform0.12+

How to create an Azure Service Bus Namespace instance per Developer using Terraform & saving it in the State


The developer should be able to create his own Azure Service Bus Namespace using terraform (terraform apply).

But with our current configuration, Developer A creates the service bus namespace A-service-bus-dev, but if Developer B creates B-service-bus-dev, A-service-bus-dev gets destroyed & replaced by the newly created service bus namespace of Developer B.

This should not be the case, because every developer needs his own instance of the service bus.

The developer should only need to change the locals value servicebus_namespace in main.tf.

Is this needed behavior even possible with Terraform? What needs to be changed to get there?

The Terraform State File is saved inside a Storage Container (which is created by the account module) inside of Azure.

There is no automatic deployment for the dev environment, every developer should create his instance manually using terraform apply.

If you need any more information, please let me know.


main.tf

locals {
  subscription_id      = "ID"
  macroservice_name    = "name"
  servicebus_namespace = "A-service-bus-dev"
}

provider "azurerm" {
  features {}

  subscription_id = local.subscription_id
}

resource "azurerm_resource_group" "this" {
  name     = local.macroservice_name
  location = "West Europe"
}

module "account" {
  source            = "../../modules/account"
  location          = "West Europe"
  resource_group    = local.macroservice_name
  environment_name  = "development"
  storage_account   = "dev"
  storage_container = "terraformstate"
  subscription_id   = local.subscription_id
}

module "servicebus" {
  source               = "../../modules/servicebus"
  location             = "West Europe"
  resource_group       = azurerm_resource_group.this.name
  servicebus_namespace = local.servicebus_namespace
  servicebus_objects = [
    {
      topic_name        = "x"
      subscription_name = "x"
    },
    {
      topic_name        = "y"
      subscription_name = "y"
    }
  ]
}

modules/servicebus/servicebus.tf

resource "azurerm_servicebus_namespace" "this" {
  name                = var.servicebus_namespace
  location            = var.location
  resource_group_name = var.resource_group
  sku                 = "Standard"
}

resource "azurerm_servicebus_topic" "this" {
  for_each     = {for k, v in var.servicebus_objects :  k => v}
  name         = each.value.topic_name
  namespace_id = azurerm_servicebus_namespace.this.id

  enable_partitioning = true
}

resource "azurerm_servicebus_subscription" "this" {
  for_each                             = azurerm_servicebus_topic.this
  name                                 = var.servicebus_objects[index(var.servicebus_objects.*.topic_name, each.value.name)].subscription_name
  topic_id                             = each.value.id
  max_delivery_count                   = 1
  dead_lettering_on_message_expiration = true
}

I added the Account Module to save the Terraform State in Azure, thinking that it would result in the wanted behavior, but it did not.


Solution

  • One of the solutions would be to loop over a set/dict with a for_each argument in the module block. Additionally, to ease the process on the devs you could import the set/dict from a yaml file. i.e:

    locals{
        foo = "foo.yaml"
        bar = fileexists(foo) ? yamldecode(file(foo)) : {} 
    }
    
    ...
    
    module "servicebus" {
      for_each = local.bar
    
      source               = "../../modules/servicebus"
      location             = azurerm_resource_group.this.location
      resource_group       = azurerm_resource_group.this.name
      servicebus_namespace = each.value
      servicebus_objects = [
        {
          topic_name        = "x"
          subscription_name = "x"
        },
        {
          topic_name        = "y"
          subscription_name = "y"
        }
      ]
    }