Monday, 28 March 2022

Introduction to Terraform


 

Terraform uses configuration files with extension .tf to define resources that need to be deployed.

General format of tf file content blocks is:
 
<block><parameters> {
    key1 = value1
    key2 = value2
}

block contains information about infrastructure platform and a set of resources within that platform that we want to create.
 
resource Block - A resource block declares a resource of a given type with a given local name. The name is used to refer to this resource from elsewhere in the same Terraform module, but has no significance outside of the scope of a module.

Example: Create a file on a local host where Terraform is installed. 


# https://www.terraform.io/language/expressions/references#filesystem-and-workspace-info
resource "local_file" "foo" {
    filename = "${path.cwd}/temp/foo.txt"
    content = "This is a text content of the foo file!"
}

resource is the reserved word and is the block name. Each resource is uniquely defined by the combination of the resource type and name. In our example:

  • "local_file" is a predefined string which denotes the resource type:
    • local - resource provider (by convention, resource type names start with their provider's preferred local name)
    • file - resource type
  • "foo" is the logical resource name; this is a local name that can be used from the same Terraform module

Inside the curly braces (resource block) are arguments for resource. They are specific for the given resource type. In this example, we are using local_file | Resources | hashicorp/local | Terraform Registry.

Here are some resource providers:
  • local
  • aws
  • azure
  • gcp
  • ...

Each resource type has its own set of arguments.


Example: Create Amazon Machine Image (AMI)

aws-ec2.tf:

resource "aws_instance" "my_webserver" {
    ami = "ami-0123456789abcdef" 
    instance_type = "t2.micro"
}


Example: S3

aws-s3.tf:

resource "aws_s3_bucket" "my_data" {
    bucket = "webserver-bucket-org-1234" 
    acl = "private"
}



Simple Terraform workflow:
  • write .tf file
  • (optional) run terraform fmt command which scans .tf files in current working directory and formats them in the canonical format. This improves the readability of configuration files.
  • run terraform init command. It:
    • checks the .tf config file
    • initializes the working directory containing .tf file
    • from .tf file it finds out what type of resource(s) we want to create
    • it initializes specified providers - it downloads plugin(s) required in order to work on these resources
    • is a safe command. It can be many times without affecting the infrastructure that is being deployed.
  • (optional) run terraform validate to validate configuration file syntax
  • run terraform plan command in order to review the execution plan 
  • run terraform apply command to apply changes
  • run terraform show command in order to see the changes made; it prints the current state of the infrastructure; it prints all resources and values of their attributes. Use -json flag to print it in JSON format.
  • run terraform destroy to destroy created resources
 

terraform init

 
Let's first initialize working directory where .tf file resides:
 
/demo-terraform/local_resources_demo$ ls -a
.  ..  create_local_file_demo.tf
 
/demo-terraform/local_resources_demo$ cat create_local_file_demo.tf
resource "local_file" "foo" {
    filename = "${path.cwd}/temp/foo.txt"
    content = "This is a text content of the foo file!"
}
 
/demo-terraform/local_resources_demo$ terraform init

Initializing the backend...

Initializing provider plugins...
- Finding latest version of hashicorp/local...
- Installing hashicorp/local v2.2.2...
- Installed hashicorp/local v2.2.2 (signed by HashiCorp)

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

 
 
From the output above, we can see that Terraform used resource type information ("local_file") to deduct that it needs to download and install hashicorp/local plugin.

hashicorp/local is an example of the source address. It is the identifier used by Terraform to locate and download the plugin from the registry. The first value (e.g. hashicorp) represents the organisational namespace and the second one is type which is the name of provider (e.g. local, aws, google etc...). Source address can also optionally start with the hostname which is the name of the registry where plugin is located:

registry.terraform.io/hashicorp/local
 
By default, Terraform downloads the latest version of plugins but it is possible to specify desired version as well, if we want to prevent using the (latest) version which introduces breaking changes.
 
If we look at the directory, we can see that terraform init created one directory and one file:
 
/demo-terraform/local_resources_demo$ ls -a
.  ..  create_local_file_demo.tf  .terraform  .terraform.lock.hcl

 
 
.terraform directory contains downloaded plugins (executable binaries) for providers that are specified in .tf file. In our case, provider is named local:

/demo-terraform/local_resources_demo/.terraform$ ls -la providers/registry.terraform.io/hashicorp/local/2.2.2/linux_amd64/terraform-provider-local_v2.2.2_x5
-rwxr-xr-x 1 bojan bojan 13864960 Mar 28 13:27 providers/registry.terraform.io/hashicorp/local/2.2.2/linux_amd64/terraform-provider-local_v2.2.2_x5

.hcl file contains list of providers with their details. This is something like package-lock.json file in Node projects:

/demo-terraform/local_resources_demo$ cat .terraform.lock.hcl
# This file is maintained automatically by "terraform init".
# Manual edits may be lost in future updates.

provider "registry.terraform.io/hashicorp/local" {
  version = "2.2.2"
  hashes = [
    "h1:5UYW2wJ320IggrzLt8tLD6MowePqycWtH1b2RInHZkE=",
    "zh:027e4873c69da214e2fed131666d5de92089732a11d096b68257da54d30b6f9d",
    "zh:0ba2216e16cfb72538d76a4c4945b4567a76f7edbfef926b1c5a08d7bba2a043",
    "zh:1fee8f6aae1833c27caa96e156cf99a681b6f085e476d7e1b77d285e21d182c1",
    "zh:2e8a3e72e877003df1c390a231e0d8e827eba9f788606e643f8e061218750360",
    "zh:719008f9e262aa1523a6f9132adbe9eee93c648c2981f8359ce41a40e6425433",
    "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
    "zh:9a70fdbe6ef955c4919a4519caca116f34c19c7ddedd77990fbe4f80fe66dc84",
    "zh:abc412423d670cbb6264827fa80e1ffdc4a74aff3f19ba6a239dd87b85b15bec",
    "zh:ae953a62c94d2a2a0822e5717fafc54e454af57bd6ed02cd301b9786765c1dd3",
    "zh:be0910bdf46698560f9e86f51a4ff795c62c02f8dc82b2b1dab77a0b3a93f61e",
    "zh:e58f9083b7971919b95f553227adaa7abe864fce976f0166cf4d65fc17257ff2",
    "zh:ff4f77cbdbb22cc98182821c7ef84dce16298ab0e997d5c7fae97247f7a4bcb0",
  ]
}

 

terraform validate


It requires terraform init to have been executed. If not, if configuration directory is not initialized, we might get the error like:

$ terraform validate
Error: Missing required provider
│ 
│ This configuration requires provider registry.terraform.io/hashicorp/local, but that provider isn't available. You may be able to
│ install it automatically by running:
│   terraform init

Error: Missing required provider
│ 
│ This configuration requires provider registry.terraform.io/hashicorp/tls, but that provider isn't available. You may be able to
│ install it automatically by running:
│   terraform init

terraform apply might fail in spite of terraform validate reporting no errors. This is because the validate command only carries out a general verification of the configuration. It validates the resource block and the argument syntax but not the values the arguments expect for a specific resource.


terraform plan


Before creating resource we can see the execution plan that will be carried out by Terraform. It is always good to review these actions before they get executed. terraform plan shows actions that will be used to create resources. The output is similar to the one of git diff:

/demo-terraform/local_resources_demo$ terraform plan

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # local_file.foo will be created
  + resource "local_file" "foo" {
      + content              = "This is a text content of the foo file!"
      + directory_permission = "0777"
      + file_permission      = "0777"
      + filename             = "/home/bojan/dev/github/demo-terraform/local_resources_demo/temp/foo.txt"
      + id                   = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.


+ symbol denotes resources that will be created.
Resource is listed with all its attributes showing default values for those that we didn't specify explicitly in our .tf file.

terraform apply



This command creates resources but it also shows the plan first and asks us to confirm to go ahead with it:
 
/demo-terraform/local_resources_demo$ terraform apply

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # local_file.foo will be created
  + resource "local_file" "foo" {
      + content              = "This is a text content of the foo file!"
      + directory_permission = "0777"
      + file_permission      = "0777"
      + filename             = "/home/bojan/dev/github/demo-terraform/local_resources_demo/temp/foo.txt"
      + id                   = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

local_file.foo: Creating...
local_file.foo: Creation complete after 0s [id=db5ca40b5588d44e9ec6c1b4005e11a6fd0c910e]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
 
File is created indeed:
 
/demo-terraform/local_resources_demo$ cat ./temp/foo.txt
This is a text content of the foo file!
 
terraform apply also creates terraform.tfstate file which contains details of the created resource:
 
/demo-terraform/local_resources_demo$ cat terraform.tfstate
{
  "version": 4,
  "terraform_version": "1.1.7",
  "serial": 1,
  "lineage": "921cfa36-9ad5-9a2e-66db-d2ef62e7509b",
  "outputs": {},
  "resources": [
    {
      "mode": "managed",
      "type": "local_file",
      "name": "foo",
      "provider": "provider[\"registry.terraform.io/hashicorp/local\"]",
      "instances": [
        {
          "schema_version": 0,
          "attributes": {
            "content": "This is a text content of the foo file!",
            "content_base64": null,
            "directory_permission": "0777",
            "file_permission": "0777",
            "filename": "/home/bojan/dev/github/demo-terraform/local_resources_demo/temp/foo.txt",
            "id": "db5ca40b5588d44e9ec6c1b4005e11a6fd0c910e",
            "sensitive_content": null,
            "source": null
          },
          "sensitive_attributes": [],
          "private": "bnVsbA=="
        }
      ]
    }
  ]
}

 

If we want to prevent terraform plan|apply commands to print out the file content in their output in terminal, we can use sensitive_content argument (instead of content):
 
sensitive_content = "This is a text content of the foo file!"
 
Execution plan in terminal will now contain this line:
 
    + sensitive_content    = (sensitive value)
 
 

terraform show

 
 To see details of the resource created we can use terraform show command:
 
/demo-terraform/local_resources_demo$ terraform show
# local_file.foo:
resource "local_file" "foo" {
    content              = "This is a text content of the foo file!"
    directory_permission = "0777"
    file_permission      = "0777"
    filename             = "/home/bojan/dev/github/demo-terraform/local_resources_demo/temp/foo.txt"
    id                   = "db5ca40b5588d44e9ec6c1b4005e11a6fd0c910e"
}

 
 

Updating already created resources

 
 
In the example above, we created a file with permissions 0777. Let's say we want to change this to permissions 0700.

We first need to edit our original .tf file:
 
/demo-terraform/local_resources_demo$ cat create_local_file_demo.tf
resource "local_file" "foo" {
    filename = "${path.cwd}/temp/foo.txt"
    content = "This is a text content of the foo file!"
    file_permission = "0700"
}
 

Let's review the changes:

/demo-terraform/local_resources_demo$ terraform plan
local_file.foo: Refreshing state... [id=db5ca40b5588d44e9ec6c1b4005e11a6fd0c910e]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
-/+ destroy and then create replacement

Terraform will perform the following actions:

  # local_file.foo must be replaced
-/+ resource "local_file" "foo" {
      ~ file_permission      = "0777" -> "0700" # forces replacement
      ~ id                   = "db5ca40b5588d44e9ec6c1b4005e11a6fd0c910e" -> (known after apply)
        # (3 unchanged attributes hidden)
    }


Plan: 1 to add, 0 to change, 1 to destroy.

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.

-/+ means that resource will be deleted and then recreated. 
 
Line with # forces replacement comment shows the attribute whose change actually forces the resource replacement.
 
This type of infrastructure is called an immutable infrastructure: change of a single attribute requires re-creation of the entire resource.

demo-terraform/local_resources_demo$  terraform apply
local_file.foo: Refreshing state... [id=db5ca40b5588d44e9ec6c1b4005e11a6fd0c910e]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
-/+ destroy and then create replacement

Terraform will perform the following actions:

  # local_file.foo must be replaced
-/+ resource "local_file" "foo" {
      ~ file_permission      = "0777" -> "0700" # forces replacement
      ~ id                   = "db5ca40b5588d44e9ec6c1b4005e11a6fd0c910e" -> (known after apply)
        # (3 unchanged attributes hidden)
    }

Plan: 1 to add, 0 to change, 1 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

local_file.foo: Destroying... [id=db5ca40b5588d44e9ec6c1b4005e11a6fd0c910e]
local_file.foo: Destruction complete after 0s
local_file.foo: Creating...
local_file.foo: Creation complete after 0s [id=db5ca40b5588d44e9ec6c1b4005e11a6fd0c910e]

Apply complete! Resources: 1 added, 0 changed, 1 destroyed.

 
Let's check new permissions on the file:

 /demo-terraform/local_resources_demo$ ls -la ./temp/
total 12
-rwx------ 1 bojan bojan   39 Mar 28 16:17 foo.txt


Deleting resources



To delete created resources we need to use terraform destroy command:


$ terraform destroy
local_file.foo: Refreshing state... [id=db5ca40b5588d44e9ec6c1b4005e11a6fd0c910e]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # local_file.foo will be destroyed
  - resource "local_file" "foo" {
     
- content              = "This is a text content of the foo file!" -> null
     
- directory_permission = "0777" -> null
     
- file_permission      = "0700" -> null
     
- filename             = "/home/bojan/dev/github/demo-terraform/local_resources_demo/temp/foo.txt" -> null
     
- id                   = "db5ca40b5588d44e9ec6c1b4005e11a6fd0c910e" -> null
    }

Plan: 0 to add, 0 to change, 1 to destroy.

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

local_file.foo: Destroying... [id=db5ca40b5588d44e9ec6c1b4005e11a6fd0c910e]
local_file.foo: Destruction complete after 0s

Destroy complete! Resources: 1 destroyed.


We can verify that temp folder does not contain the test file. Note that temp folder itself remained, although it was created in process of creating a file resource.



Configuration Directory


Configuration directory is the one which contains one or more configuration (.tf) files. Each configuration file can specify one or more resources (resource blocks required to provision the infrastructure). 

We can combine all resources from multiple (smaller) configuration file into a single (large) configuration file.  The common convention is to name that file main.tf

Configuration files can be organised as here:
  • main.tf - main config file containing definition of resources
  • variables.tf - contains variable declarations
  • outputs.tf - contains outputs from resources
  • provider.tf - contains provider definitions

It is possible to use multiple providers (e.g. local, random etc...) in the same configuration directory. 

Whenever we add a resource for a provider that has not been used so far in the configuration directory, we have to initialize the directory by running terraform init command.




TBC...

2 comments:

Unknown said...

Welcome to the future! Financing made easy with Prof. Mrs. DOROTHY JEAN INVESTMENTS

Hello, Have you been looking for financing options for your new business plans, Are you seeking for a loan to expand your existing business, Do you find yourself in a bit of trouble with unpaid bills and you don’t know which way to go or where to turn to? Have you been turned down by your banks? MRS. DOROTHY JEAN INVESTMENTS says YES when your banks say NO. Contact us as we offer financial services at a low and affordable interest rate of 2% for long and short term loans. Interested applicants should contact us for further loan acquisition procedures via profdorothyinvestments@gmail.com

We invest in all profitable projects with cryptocurrencies. I'm here to share an amazing life changing opportunity with you. its called Bitcoin / Forex trading options, Are you interested in earning a consistent income through binary/forex trade? or crypto currency trading. An investment of $100 or $200 can get you a return of $2,840 in 7 days of trading and you get to do this from the comfort of your home/work. It goes on and on The higher the investment, the higher the profits. Your investment is safe and secured and payouts assured 100%. if you wish to know more about investing in Cryptocurrency and earn daily, weekly OR Monthly in trading on bitcoin or any cryptocurrency and want a successful trade without losing Contact MRS.DOROTHY JEAN INVESTMENTS Email profdorothyinvestments@gmail.com


YOURS IN SERVICE
Mrs. Dorothy Pilkenton Jean
Financial Advisor on Bank Instruments,
Private Banking and Client Services
Email Address: profdorothyinvestments@gmail.com
Operation: We provide Financial Service Such As Bank Instrument
From AA Rate Banks, Cash Loan,BG,SBLC,BOND,PPP,MTN,TRADING,FUNDING MONETIZING etc.

Taylor said...

I just have to introduce this hacker that I have been working with him on getting my credit score been boosted across the Equifax, TransUnion and Experian report. He made a lot of good changes on my credit report by erasing all the past eviction, bad collections and DUI off my credit report history and also increased my FICO score above 876 across my three credit bureaus report you can contact him for all kind of hacks . Email him here support@wavedrive.tech go on their website wavedrive.tech for more details,Whatsapp No:+14106350697 if you want to chat them up,One thing i can assure you would not regret this at all he is 100% legit