Terra Week Challenge Day 2

Hashi Corp Language

The native syntax of the Terraform language, which is a rich language designed to be relatively easy for humans to read and write. This low-level syntax of the Terraform language is defined in terms of a syntax called HCL, which is also used by configuration languages in other applications, and, in particular, other HashiCorp products.

HCL uses blocks to define resources. In this article, we will go through HCL block types and what they are used for.

Basic Syntax:

type "label_1" "label_2" {
  argument_1 = value_1
  argument_2 = value_2
}

Terraform block types

As a part of learning HCL, we will cover these block types:

  1. terraform block: It contains required_providers block inside which specifies the versions of the providers we need as well as where Terraform should download these providers from.

     terraform {
       required_providers {
         aws = {
           source  = "hashicorp/aws"
           version = "~> 2.0"
         }
       }
       required_version = ">= 1.0.1"
     }
    
  2. provider block: Provider blocks specify a special type of module that allows Terraform to interact with various cloud-hosting platforms or data centers.

     provider "aws"{}
    
  3. resource block: Resource blocks are used to manage resources such as compute instances, virtual networks, databases, buckets, or DNS resources.

     resource "aws_instance" "example_resource" {
       ami           = "ami-005e54dee72cc1d00" 
       instance_type = "t2.micro"
       }
    
  4. variable block: Variable block provides parameters for terraform modules and allows users to customize the data provided to other terraform modules without modifying the source.

     variable "example_variable" {
       type = var_type
       description = var_description 
       default = value_1 
     }
    
  5. locals block: This block is used to keep frequently referenced values or expressions in order to keep the code clean and tidy.

     locals {
       service_name = "forum"
       owner        = "Community Team"
       instance_ids = concat(aws_instance.blue.*.id, aws_instance.green.*.id)
     }
    
  6. data block: Data block's primary purpose is to load or query data from APIs other than Terraform's.

     data "data_type" "data_name" {
       variable_1 = expression
     }
    
  7. module block: Modules are containers for multiple resources that are used together. It is the primary way to package and reuse resources in Terraform.

  8. output block: It allows Terraform to output structured data about your configuration.

     output "test_server_public_ip" {
       description = "My test output for EC2 public IP"
       value = aws_instance.test_web_server.public_ip
     }
    

Key aspects of HCL:

  • Comments: Single-line comments start with a # symbol, while multi-line comments are enclosed between /* and */.

  • Blocks: Configuration elements are defined within blocks. Blocks have a block type and optional labels. They are enclosed by curly braces {}.

  • Attributes: Within blocks, you define attributes using the key = value syntax. Each attribute has a unique key and a corresponding value. Example: instance_type = "t2.micro".

Data types in HCL :

  • In HCL (HashiCorp Configuration Language), there are several data types that you can use in your configuration files. Here are the commonly used data types in HCL along with examples:

    1. String: Strings represent a sequence of characters and are enclosed in double quotes. Example: name = "John Doe"

    2. Number: Numbers can be integers or floating-point values. Example: age = 25 or height = 1.75

    3. Boolean: Booleans can have two values: true or false. Example: enabled = true

    4. List: Lists are ordered collections of values, enclosed in square brackets and separated by commas. Example: fruits = ["apple", "banana", "orange"]

    5. Tuple: Tuples are ordered collections of values that can be of different types. They are enclosed in parentheses and separated by commas. Example: point = (10, 20)

    6. Object: Objects allow you to define complex data structures with nested attributes. They use the same syntax as blocks.

    7. Null: Null represents the absence of a value. Example: parent = null

    8. Map: Maps or key-value pairs are unordered collections of values, enclosed in curly braces. Keys and values are separated by an equals sign (=), and each key-value pair is separated by a comma.

Maps in HCL:

variable "usersage" {
  type = map(any)
  default = {
    shivam  = 20
    shubham = 19
  }
}

variable "username" {
  type = string
}

output "userage" {
  value = "My name is ${var.username} and my age is ${lookup(var.usersage, "${var.username}")}"
}

Functions in HCL:

The Terraform language includes several built-in functions that you can call from within expressions to transform and combine values. The general syntax for function calls is a function name followed by comma-separated arguments in parentheses.

To get an idea for Terraform functions, go through

https://developer.hashicorp.com/terraform/language/functions

Example:

variable "users" {
  type    = list(any)
  default = ["Shivam", "Shubham", "Anand"]
}

output "func_example" {
  value = join(",", var.users)
}

output "toUpper" {
  value = upper(var.users[0])
}

Output :

Expressions in HCL:

Expressions are the core of HCL itself – the logic muscle of the entire language. Terraform expressions allow you to get a value from somewhere, and calculate or evaluate it. You can use them to refer to the value of something, or extend the logic of a component – for example, make one copy of the resource for each value contained within a variable, using it as an argument.

Conditionals: Sometimes, you might run into a scenario where you’d want the argument value to be different, depending on another value.

Syntax:

bucket_name = var.test == true ? "dev" : "prod"

Splat Expressions:

Consider an example

test_variable = [
 {
   name  = "Arthur",
   test  = "true"
 },
 {
   name  = "Martha"
   test  = "true"
 }
]

To print the output as : ["Arthur", "Martha"] , one can use

For Loop :>
[for o in var.test_variable : o.name]
One can also use a splat expression:
var.test_variable[*].name

For_each loop:

As mentioned earlier, sometimes you might want to create resources with distinct values associated with each one – such as names or parameters (memory or disk size for example). Consider the following example

my_instances = {
 instance_1 = {
   ami   = "ami-00124569584abc",
   type  = "t2.micro"
 },
 instance_2 = {
   ami   = "ami-987654321xyzab",
   type  = "t2.large"
 },
}

resource "aws_instance" "test" {
 for_each = var.my_instances

 ami           = each.value["ami"]
 instance_type = each.value["type"]
}

Magic happens using for_each loop as it leverages the resource or module to create multiple instances of itself, each with multiple declared variable values

Assigning value to Input Variable:

Once a variable is declared in your configuration, you can set it:

  • Individually, with the -var foo=bar command line option.

  • In variable definitions files, either specified on the command line with the -var-files values.pkrvars.hcl or automatically loaded (*.auto.pkrvars.hcl).

  • As environment variables, for example: PKR_VAR_foo=bar

terraform appply -var='image_id_list=["ami-abc123","ami-def456"]'
export PKR_VAR_image_id=ami-abc123

Variable Precedence

Terraform loads variables in the following order, with later sources taking precedence over earlier ones:

  1. Environment variables

  2. The terraform.tfvars file, if present.

  3. The terraform.tfvars.json file, if present.

  4. Any .auto.tfvars or .auto.tfvars.json files are processed in the lexical order of their filenames.

  5. Any -var and -var-file options on the command line, in the order they are provided. (This includes variables set by a Terraform Cloud workspace.)

A basic example using Terraform:

resource "local_file" "file_temp"{
    filename="demo.txt"
    content="This is an example of local resource"
}

resource "random_string" "random"{
    length=15
}

output "random_string"{
    value=random_string.random[*].result
}

Output will look like this:

Basic Commands for Terraform:

  1. Terraform init: Initializes a Terraform working directory, downloading provider plugins and setting up the backend configuration.

  2. Terraform plan: Generates an execution plan that describes the changes Terraform will make to the infrastructure, without actually applying those changes.

  3. Terraform apply: Applies the changes specified in the Terraform configuration, creating, modifying, or deleting resources as necessary.

  4. Terraform fmt: Rewrites Terraform configuration files in a consistent format, making them easier to read and maintain.

  5. Terraform validate: Validates the syntax and configuration of Terraform files, checking for errors and warnings without making any changes.

#TerraWeek #Terraform

Thank you for reading the article, I appreciate the time and effort invested in the same. I would love to hear a feedback.