Posted on Leave a comment

Create and use terraform modules

Terraform modules are useful in various scenarios when working with Infrastructure as Code (IaC) using Terraform. Modules provide a way to encapsulate and reuse infrastructure configurations, making it easier to manage and scale your infrastructure code.

Every Terraform configuration has at least one module, known as its root module, which consists of the resources defined in the .tf files in the main working directory.

A module can call other modules, which lets you include the child module’s resources into the configuration in a concise way. Modules can also be called multiple times, either within the same configuration or in separate configurations, allowing resource configurations to be packaged and re-used.

Lets take a look how we can create and use terraform modules. The first thing that you will need to do is to structure your code somehow. A most common way to create a structure would be to create folders and name them after your module. For example if you have to deploy a cloud solution with multiple components you could create a module for each component. In my structure you can find two folders with the name module1 and module2. The module2 will call module1 to reuse its code inside the terraform configuration.

The module1 folder contains the files that are shown.

provider.tf file will be used to fetch all the necessary providers. In my example I use the random provider to generate a random string with terraform.

terraform {
  required_providers {
    random = {
      source  = "hashicorp/random"
      version = "~> 3.5"
    }
  }
}

kati.tf will call the random code to generate the string.

resource "random_string" "module1_random" {
  length           = 16
  special          = true
  override_special = "/@£$"
}

And finally the outputs.tf file will be used to mark the string as an output and print it in the console.

The module2 folder will only include a main.tf which will call module1. In order to make a module in terraform we will only need to specify the location of the folder. We do not need complex actions or definitions. In this example module2 will call module1 to generate the random string.

the main.tf file will only call the module1

module "kati" {
    source = "../module1"
}

In order to call the module I will need to perform an apply on module2.

cd module2; terraform apply

As we have not specified an output variable in module2 the result will not be printed in the console, you can see from below screenshot that module2 is calling kati file from module1 to generate the random string.

However we can find the result by navigating in the terraform.tfstate file of module2.

When we have more complex scenarios we will need to pass variables inside the calling modules. In order to learn how to pass variables in the calling modules you can read my previous article.

You can find the example on GitHub

https://github.com/geralexgr/terraform-modules-blog-example

Modules – Configuration Language | Terraform | HashiCorp Developer

Youtube video:

Posted on 10 Comments

Pass variables values inside terraform modules

In this article I will explain two different ways to pass variables values inside terraform modules. Modules let you separate your code into small units and help the engineer structure its project better.

https://www.terraform.io/language/modules/syntax

Modules in terraform (terraform files) can be placed on folders and their location should be provided on the module directive. Lets say for example that you host a main.tf on your current working directory which should call two modules. The first module would be a storage account and the second would be an app service. Your main.tf file should look like below.

module "app_service_test" {
  source                  = "./modules/appservice"
}
module "storage_account_test" {
  source                  = "./modules/storageaccount"
}

However you want to pass some variables inside the child modules for example the resource group name, location etc.

First method – Define variables on root module

The first way you can pass variables inside your child modules would be to define a variables.tf file on your main module and a terraform.tfvars. Then you should also define a variables.tf file inside each module and contain the definition of each module.

terraform.tfvars (root module)

app_service_plan_name   = "ger-plan-test"
app_service_name        = "ger-site-test"
resource_group_name     = "geralexgr-terraform-rg"
resource_group_location = "West Europe"
storage_account_name    = "geralexgrsgv2"

variables.tf (root module)

variable "storage_account_name" {
  type        = string
  description = "Storage account name"
  default     = ""
}

variable "resource_group_name" {
  type        = string
  description = "RG name in Azure"
}

variable "app_service_plan_name" {
  type        = string
  description = "App Service Plan name in Azure"
}

variable "app_service_name" {
  type        = string
  description = "Name for the app service"
}

variable "resource_group_location" {
  type        = string
  description = "RG location in Azure"
}

variables.tf (storageaccount module)

variable "storage_account_name" {
    type        = string
    description = "Storage account name"
}
variable "resource_group_name" {
    type        = string
    description = "RG name in Azure"
}

variable "resource_group_location" {
    type        = string
    description = "RG location in Azure"
}

variables.tf (appservice module)

variable "app_service_plan_name" {
    type        = string
    description = "App Service Plan name in Azure"
}

variable "app_service_name" {
    type = string
    description = "Name for the app service"
}
variable "resource_group_name" {
    type        = string
    description = "RG name in Azure"
}

variable "resource_group_location" {
    type        = string
    description = "RG location in Azure"
}

Then on your main module you should call your child modules as follows:

module "app_service_test" {
  source                  = "./modules/appservice"
  app_service_plan_name   = var.app_service_plan_name
  app_service_name        = var.app_service_name
  resource_group_name     = var.resource_group_name
  resource_group_location = var.resource_group_location
}

module "storage_account_test" {
  source                  = "./modules/storageaccount"
  storage_account_name    = var.storage_account_name
  resource_group_name     = var.resource_group_name
  resource_group_location = var.resource_group_location
}

Second method – Pass variables on module call

With this approach you do not need to have variables.tf file and terraform.tfvars file inside your root module. You only need the definition as described above inside appservice and storageaccount folders (variables.tf).

variables.tf (appservice module)

variable "app_service_plan_name" {
    type        = string
    description = "App Service Plan name in Azure"
}

variable "app_service_name" {
    type = string
    description = "Name for the app service"
}
variable "resource_group_name" {
    type        = string
    description = "RG name in Azure"
}

variable "resource_group_location" {
    type        = string
    description = "RG location in Azure"
}

variables.tf (storageaccount module)

variable "storage_account_name" {
    type        = string
    description = "Storage account name"
}
variable "resource_group_name" {
    type        = string
    description = "RG name in Azure"
}
variable "resource_group_location" {
    type        = string
    description = "RG location in Azure"
}

Then your main.tf file should be:

module "app_service_test" {
  source                  = "./modules/appservice"
  app_service_plan_name   = "ger-plan-test"
  app_service_name        = "ger-site-test"
  resource_group_location = "West Europe"
  resource_group_name     = "geralexgr-terraform-rg"
}

module "storage_account_test" {
  source                  = "./modules/storageaccount"
  storage_account_name    = "geralexgrsgv2"
  resource_group_name     = "geralexgr-terraform-rg"
  resource_group_location = "West Europe"
}
Posted on Leave a comment

Structure python code with packages – import functions from different files

A modular application is an application composed of loosely coupled, functional units called modules, and these modules can be linked together to form a larger application. When you implement your python applications you should create such structures instead of big monoliths.

In this guide I will demonstrate how you can call python function from different folders and files (called packages). I have created a flask application which has as entrypoint the app.py file.

The solution is structured as shown below. The app folder is the root folder which contains all the code for the application. In the root hierarchy the app.py is placed along with other folders as templates, static and helpers.

As I need to create a helper function that will request data from an external API I created a file named github inside my helpers folder and I defined a function within it.

The function is very simple and returns a simple message. Code for github.py can be found below.

def my_function():
  return "Hello from function"

In order to call your helper functions from your main app or from another python package you should first import package

from helpers import github

and then use the function.

@app.route("/")
def home():
    return github.my_function()

This code will display on my flask main page the message of the function.

You can perform in such way any other activities by specifying your python file and then the function.

pythonFile.Function()
Posted on Leave a comment

Create multiple environments with Terraform modules – App service Azure example

In this article I will demonstrate how one can create different environments for development needs through terraform modules. Modules provide great extensibility and code reuse. In this example I will use an appservice resource on Azure cloud.

The result of the deployment will be two different resource groups with two app services. The code of the demonstration is located at the bottom of the page.

You should first init your module. Navigate to the module folder and perform init

cd modules; terraform init
cd .. ; terraform init

Then validate your terraform code

terraform validate

The last step is to apply your configuration

terraform apply

You may encounter an error during the creation of the resources because of the app service name. It should be globally unique.

Change your name and perform a terraform apply again. Terraform will read your .tfstate file and will only implement the differences on infrastructure.

After the successful run you will see the green result output from terraform cli.

On Azure there should be two resource groups created. One for prod environment and one for test.

Inside each resource group there should be a different app service the one that it is created through the module according with the settings provided.

Production app service plan

GitHub repository:

https://github.com/geralexgr/terraform-module-environments-deploy

Video tutorial on YouTube: