Terraform basics
Tags: terraform
Published: 2022-11-27 15:07:02

The following article describes the basic terminology and concepts of Terraform and can be used as a first step in working with Terraform.

Terraform is a tool to manage your infrastructure. Basicaly it calls vendors API to create infrastructure resources.

# Resources
Terraform resource is anything that can be managed via Terraform:) For example, it could be Azure resource group or AWS S3 bucket or GitHub repository, or anything else what supports terraform.

![Terraform resources](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eayegd9riawof4rntz1y.png)

# Provider
For creating Azure resources like Azure Key Vault or Azure SQL Database, Terraform needs to call Azure API. Terraform uses [Azure provider](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs) for this purpose. Terraform provider is a plugin for Terraform. The provider incapsulates API Client for vendor API.  You can use multipe providers in your project at the same time.

![Terraform provider diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d6dr1u6ouh4cptvjj6nk.png)

Providers are supplied by Hashicorp, API owners, or enthusiasts. You can find list of publicly available providers in [Hashicorp Provider Registry](https://registry.terraform.io/browse/providers).  
# HCL
You need to use Hashicorp configuration language (HCL) to declare resources you want to have. Instead of describing operations to create resource, you describe resources in declarative manner. 
Terraform project is a set of .tf files. You can use Visual Studio Code or Jetbrains IDEA to work on it.
The following example declares Azure Resource Group:
 
```hcl
resource "azurerm_resource_group" "resource_group" {
  location = "westeurope"
  name     = "demo-rg"
  tags     = {
    "asset-owner" = "Alexey Ryazhskikh"
  }
}
```


# Terraform state

Terraform state is a database storing the information of existing resources. As soon as Terraform creates a resource, it writes information into the state database.
Then Terraform compares HCL declaration of resources and information about resources stored in the state. 
Terraform keeps the state and the declaration synchronized. It creates missing resources, deletes resources if they were removed from declaration, etc.
The following example shows the state for the resource group described above. As you see, it stores not only resource id in Azure but also properties like `name` and `tags`.

![Terraform state for resource group](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rlhmg6302shx6o8uz1h0.png)

You can trigger changes with Terraform CLI.

# Terraform `plan` command
Terraform `plan` command calculates which resources needs to be created, updated or deleted. The `plan` command generates tfplan file describing all needed modifications.

![Terraform Plan: plan(hcl, state) = plan](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iailnyio0ffey8bcoxdj.png)

# Terraform `apply` command
Terraform `apply` command performs planned changes via Terraform providers and updates terraform state.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7ft0y58tq0g270p4ayqi.png)


# Terraform module

Terraform module is the way how you can declare multiple resources at once with some parameters. So you can think about the module as a function that declares a group of resources.
The following example shows a module usage example that creates an azure resource group and role assignments under the hood:

```hcl
module "resource_group" {
  source   = "app.terraform.io/my-corp/resource_group/azurerm"
  version  = "1.0.0"
  location = var.location
  name     = "my-demo-rg"
  role_assignments = {
    "contributors" = {
      role_definition_name = "Contributor"
      principal_id         = "d3a2437e-15f1-4495-ba65-e10bf91578f2"
    }
  }
}

```

Modules allow the creation of abstraction layers in your terraform code. For example, you can create a database module to add Azure SQL database. After some time, you might need to implement backup logic for all databases you declared. You can extend your database module with storage account declaration, and all databases declared with your module will get the storage account after updating to the new version of the module.
Modules can be declared localy for each terraform project, or can be published to private or public module registry: https://registry.terraform.io/browse/modules