DEV Community 👩‍💻👨‍💻

SerDigital64
SerDigital64

Posted on • Originally published at serdigital64.github.io

Terraform Scripting Concepts: Part 2 of 2

Overview

This is the second part of the tutorial. If not done already, please read the first part: Terraform Scripting Concepts: Part 1 of 2

Using functions

Another particular characteristic of the Terraform Language is that it doesn't support user-defined functions. Instead, it provides groups of built-in functions that can be used when assigning value to variables and attributes:

  • Numeric
  • String
  • Collection
  • Encoding
  • Filesystem
  • Date and Time
  • Hash and Crypto
  • Networking
  • Type conversion

Use the following template for calling functions: FUNCTION_NAME(PARAMETER1, PARAMETER2, PARAMETERN)

For example:

locals {
  # Find the maximum value from a list of numbers
  numeric_max = max(2, 3, 10, 1, 20)
  # Find the minimum value from a list of numbers
  numeric_min = min(2, 3, 10, 1, 20)
  # Conver string to lowercase
  string_lower = lower("ServerX.DomainY")
  # Extrat dir from path
  filesystem_dir = dirname("/full/path/to/file")
  # Extrat file name from path
  filesystem_file = basename("/full/path/to/file")
  # Record timestamp
  date_time_timestamp = timestamp()
}
Enter fullscreen mode Exit fullscreen mode

Managing infrastructure

Up until now, the script takes no action. In order for Terraform to actually manage the target infrastructure and make changes to reach the required end-state, the script needs providers.

Terraform defines the following block types for working with the target infrastructure:

  • terraform: used to set workspace-wide run-time options.
  • required_providers: used to declare what providers will be used
  • provider: used to define provider-specific options.
  • resource: used to create a logical representation of the managed resource. Each provider will further specialize the resource with attributes and subtypes.
  • data: optional block that is used to query infrastructure resources managed by the provider. The query result is then made available for other blocks to use as variables.

Declare Providers

Providers are declared by adding a required_providers nested block to the terraform block. Each provider will be assigned to an attribute of type map:

  • Map name: used to reference the provider from other blocks.
  • Attribute version: used to define version requirements.
  • Attribute source: defines from where the provider will be downloaded.

Additional provider-specific attributes can be defined by using the provider block. The block will use the same label as the map name in required_providers.

The following example declares two providers: aws and azure:

terraform {
  required_providers {
    aws = {
      version = ">= 3.0.0"
      source = "hashicorp/aws"
    }
    azurerm = {
      version = ">= 2.0.0"
      source = "hashicorp/azurerm"
    }
  }
}
provider "aws" {
  region = "us-east-1"
}
provider "azurerm" {
  features {}
}
Enter fullscreen mode Exit fullscreen mode

Define Managed Resources

Once the provider has been declared, it will make available additional resource and data types. For example:

  • Provider: AWS
    • Resource Type: aws_instance
    • Data Type: aws_ami
  • Provider: Azure
    • Resource Type: azurerm_linux_virtual_machine
    • Data Type: azurerm_image

Use the following template to define blocks:

data "RESOURCE_TYPE" "RESOURCE_LABEL" {
  ATTRIBUTE1 = VALUE
  ATTRIBUTEN = VALUE
}

resource "RESOURCE_TYPE" "RESOURCE_LABEL" {
  ATTRIBUTE1 = VALUE
  ATTRIBUTEN = VALUE
}
Enter fullscreen mode Exit fullscreen mode

The data and resource blocks can be used together to improve automation. In the following example, the data block is used to query AWS for a particular AMI and then the resource block will use the resulting AMI ID to create the VM instance:

data "aws_ami" "coreos" {
  most_recent = true    # Return the latest one if more than one result is available

  filter {              # Look for fedora coreos v35
    name   = "name"
    values = ["fedora-coreos-35**"]
  }

  filter {              # Look for HVM virtualization
    name   = "virtualization-type"
    values = ["hvm"]
  }

  owners = ["125523088429"]     # CentOS / Fedora account that owns AMIs
}

resource "aws_instance" "aws_test_instance" {
  ami = data.aws_ami.coreos.id    # Use the AMI that was found in the data query
  instance_type = "t2.micro"      # Select the instance size
}
Enter fullscreen mode Exit fullscreen mode

Next Steps

Explore Terraform resources:

Learn advanced features:

Understand provider-specific implementation details:

Copyright information

This article is licensed under a Creative Commons Attribution 4.0 International License. For copyright information on the product or products mentioned inhere refer to their respective owner.

Disclaimer

Opinions presented in this article are personal and belong solely to me, and do not represent people or organizations associated with me in a professional or personal way. All the information on this site is provided "as is" with no guarantee of completeness, accuracy or the results obtained from the use of this information.

Top comments (0)

Timeless DEV post

Git Concepts I Wish I Knew Years Ago