There are 3 type of provisioners which are commonly used:-

  1. File Provisioner
  2. Local-exec provisioner
  3. Remote exec provisioner



File Provisioner

File provisioner is used to copy files from the local server (where terraform code is being run) to the remote server instance on cloud like EC2

Local-exec provisioner

This provisioner runs any command or execute any code or invokes any executable locally on the server where terraform is installed after remote resource is created.

Remote-exec provisioner

This provisioner executes set of commands or initiates code on the remote resource after the resource gets created.

Important things to remember about Provisioners

  1. Provisioners block of code is integrated in the ‘Resource’ block.
  2. By default, provisioners run after the resource is created.
  3. If the provisioner fails, the resource is marked as ‘tainted’ This means that specific resource would be recreated after ‘terraform apply’ command would run next time. Moreover, if the provisioner would fail, terraform apply command itself would also fail.
  4. We can alter the default behaviour of provisioners and mention “when = destroy” This would mean that now that specific provision would NOT run at the time of resource creation, rather it would run when the resource would be destroyed (with ‘terraform destroy’ command). Example

resource “aws_instance” “web_jaspreet_server” {

  # Block of code goes here to create EC2 instance

  provisioner “local-exec” {

    when    = destroy

    command = “echo ‘Resource would be destroyed'”

  }

}

  • Terraform Apply command would fail if provisioner would fail, however, we can alter this behaviour by using on_faliure attribute by providing it a value of either continue or fail

resource “aws_instance” “web_jaspreet_server” {

  # Code to create resource would go here

  provisioner “local-exec” {

    command    = “echo The server’s IP address is ${self.private_ip}”

    on_failure = continue

  }

}

  • Because we would be using provisioner block of code inside the resource block and if there would be a need to use the IP of the same resource. As an example

resource “aws_instance” “web_jaspreet_server” {

  # Code to create resource would go here

  provisioner “local-exec” {

    command    = “echo The server’s IP address is ${self.private_ip}”

    on_failure = continue

  }

}

In this case, we would NOT use aws_instance. web_jaspreet_server.private_ip. Rather we would use the self object as highlighted in yellow.

  • Local-exec is the only provisioner where do NOT have to use the connection block. Connection block carries information like Username, Key info, protocol info etc to connect to EC2 instance. But since Local-exec provisioner would run on the local server, there is no need to have that block of info in provisioner block.

Let’s understand by doing a practical of Remote-Exec Provisioner

Create Public and Private key – We would use these key when we would provision Ec2 instance. Ran ssh-keygen command to generate the keys

We would use the Public key and Private key generated via ssh-keygen in Section 2 & Section 4 respectively in the code below

Above Code Explanation

Section 1- We defined List variable for ports that we would be using in Section 3 in the for_each loop

Section 2 – Key pair generated here. We would use this Key Name in Section 4, while creating EC2 instance.

Section 3– We are creating Security Group that we would associate with EC2 instance that would be created in Section 4.

Section 4 – EC2 instance would be created and once it would be created then terraform would connect with EC2 instance and execute the remote-exec provisioner to install nano by using the Connection block details.

Below code shows what happens when we execute (terraform apply) the above code

After we have applied the code, we would see the EC2 instance created in AWS with nano installed.

Now, to test further, we will run Terraform Destroy command. Since we have created remote-exec provisioner with when=destroy, Terraform would first connect to EC2 instance and initiate removal of nano package and then finally it would destroy the resource. We are doing just to test, how it works but in real world we generally would want to remove packages like Anti Virus agents. This would help in clean removal of antivirus agent from Antivirus Console.

Important links: Provisioners | Terraform by HashiCorp