Terraform - Deploying Azure Service Bus Topics
In our previous post, we looked at how to use Terraform to set up namespaces in Azure Service Bus. Now, we’re moving on to the next step: creating topics in Azure Service Bus. Topics are a key feature for applications that need to send messages to multiple subscribers efficiently. Unlike queues, which are designed for direct, point-to-point communication, topics allow a single message to be sent to multiple interested parties.
This tutorial will guide you through the process of creating topics in Azure Service Bus using Terraform. By the end, you’ll be able to manage Service Bus topics efficiently with Terraform.
Let’s get started.
Prerequisites #
- You need Terraform CLI on your local machine, if you’re new to using Terraform to deploy Microsoft Azure resources, then I recommend you check out this link.
- A text editor or IDE of your choice (Visual Studio Code with terraform extension is my recommendation)
Declare Azure Provider in Terraform #
The provider.tf file in Terraform is used to specify and configure the providers used in your Terraform configuration. A provider is a service or platform where the resources will be managed. This could be a cloud provider like Microsoft Azure, AWS, Google Cloud, etc.
This file is important because it tells Terraform which provider’s API to use when creating, updating, and deleting resources. Without it, Terraform wouldn’t know where to manage your resources.
provider "azurerm" {
features {}
}
Deploy Azure Resources Using Terraform #
In the case of Azure Service Bus Topic deployment, the main.tf file contains the following key components:
- Resource Block for Azure Service Bus Topics: This is the core part where Azure Service Bus topics are actually created and configured. The block uses the for_each construct to iterate over each topic defined in var.servicebus_topics, creating a Service Bus topic for each. It maps each property from the variable like enable_partitioning, max_size_in_megabytes, default_message_ttl, etc., to the corresponding properties of the Azure Service Bus topic resource.
This approach allows for dynamic creation and configuration of multiple topics based on the input variable, facilitating a flexible and scalable deployment strategy for messaging infrastructure.
# Resource definition for Azure Service Bus Topics with updated parameters
resource "azurerm_servicebus_topic" "topic" {
# Loop through each topic in the servicebus_topics variable
for_each = { for sbt in var.servicebus_topics : sbt.name => sbt }
name = each.value.name
namespace_id = each.value.namespace_id
status = each.value.status
auto_delete_on_idle = each.value.auto_delete_on_idle
default_message_ttl = each.value.default_message_ttl
duplicate_detection_history_time_window = each.value.duplicate_detection_history_time_window
enable_batched_operations = each.value.enable_batched_operations
enable_express = each.value.enable_express
enable_partitioning = each.value.enable_partitioning
max_message_size_in_kilobytes = each.value.max_message_size_in_kilobytes
max_size_in_megabytes = each.value.max_size_in_megabytes
requires_duplicate_detection = each.value.requires_duplicate_detection
support_ordering = each.value.support_ordering
}
Declaration of input variables #
The variables.tf file in Terraform defines the variables I will use in the main.tf file. These variables allow for more flexibility and reusability in the code.
In this example, the variables are defined in the variables.tf include:
-
servicebus_topics: This variable is a list of objects, where each object represents the configuration for an Azure Service Bus topic. It includes various properties for each topic, such as namespace_id, name, enable_partitioning, default_message_ttl, duplicate_detection_history_time_window, and others. This structure allows for defining multiple topics with their specific configurations in a structured and reusable manner.
-
Validations: Within the variable definitions, there are validations to ensure that the input values meet specific criteria. These validations act as a first line of defense against configuration errors, enhancing the overall robustness of your infrastructure as code. For instance, validations can be included to ensure that a topic’s name meets Azure’s length and pattern requirements, or that numerical values for max_size_in_megabytes fall within the allowed ranges for Azure Service Bus.
# Variable definition for Service Bus Topics
variable "servicebus_topics" {
description = "List of Service Bus Topics to be created"
type = list(object({
name = string
namespace_id = string
status = optional(string)
auto_delete_on_idle = optional(string)
default_message_ttl = optional(string)
duplicate_detection_history_time_window = optional(string)
enable_batched_operations = optional(bool)
enable_express = optional(bool)
enable_partitioning = optional(bool)
max_message_size_in_kilobytes = optional(number)
max_size_in_megabytes = optional(number)
requires_duplicate_detection = optional(bool)
support_ordering = optional(bool)
}))
validation {
# Ensure all topic names are not empty and meet naming conventions
condition = alltrue([for t in var.servicebus_topics : t.name != "" && length(t.name) <= 50])
error_message = "All topic names must be non-empty strings of no more than 50 characters."
}
validation {
# Validate namespace_id is not empty
condition = alltrue([for t in var.servicebus_topics : t.namespace_id != ""])
error_message = "Each topic must have a non-empty namespace_id."
}
validation {
# Validate that if enable_partitioning is true, max_size_in_megabytes must be one of the supported values for partitioned entities
condition = alltrue([for t in var.servicebus_topics :
!t.enable_partitioning || (t.enable_partitioning && contains([1024, 2048, 3072, 4096, 5120], t.max_size_in_megabytes))])
error_message = "For partitioned topics, max_size_in_megabytes must be one of the following values: 1024, 2048, 3072, 4096, 5120."
}
validation {
# Validate status field to ensure it's either "Active" or "Disabled" if provided
condition = alltrue([for t in var.servicebus_topics :
t.status == null || contains(["Active", "Disabled"], t.status)])
error_message = "The status, if provided, must be either 'Active' or 'Disabled'."
}
}
Declaration of output values #
The output.tf file in Terraform extracts and displays information about the resources created or managed by your Terraform configuration. These outputs are defined using the output keyword and can be used to return information that can be useful for the user, for other Terraform configurations, or for programmatically using the information in scripts or other tools.
In this specific example, the output.tf file is configured to return information about the Azure Service Bus Topics that were created. This is accomplished using the output keyword in Terraform:
- A for loop is used within the output block to iterate over each Service Bus topic created in the azurerm_servicebus_topic resource.
- For each topic, the output collects and displays the topic_id and topic_name, as well as the namespace_id to which each topic belongs.
# Output definition for Service Bus Topic details
output "servicebus_topic_details" {
description = "A map of Service Bus topic details, including each topic's ID and name."
value = {
for sbt in azurerm_servicebus_topic.topic : sbt.name => {
topic_id = sbt.id # The unique identifier of the topic
topic_name = sbt.name # The name of the topic
}
}
}
Executing the Terraform Deployment #
Now that you’ve declared the resources correctly, it’s time to take the following steps to deploy them in your Azure environment.
-
Initialization: To begin, execute the terraform init command. This will initialize your working directory that holds the .tf files and download the provider specified in the provider.tf file, and configure the Terraform backend. If you want to know how, check this link.
-
Planning: Next, execute the terraform plan. This command creates an execution plan and shows Terraform’s actions to achieve the desired state defined in your .tf files. This gives you a chance to review the changes before applying them.
-
Apply: When you’re satisfied with the plan, execute the terraform apply command. This will implement the required modifications to attain the intended infrastructure state. Before making any changes, you will be asked to confirm your decision.
-
Inspection: After applying the changes, you can use terraform show command to see the current state of your infrastructure.
-
Destroy (optional): when a project is no longer needed or when resources have become outdated. You can use the terraform destroy command. This will remove all the resources that Terraform has created.
References and useful links #
Thank you for taking the time to read my post. I sincerely hope that you find it helpful.