Understanding local-exec provisioner in terraform

Terraform Provisioners can be used to do specific actions on the local machine or on a remote machine in order to prepare servers or other infrastructure resources.

Provisioners can be used to execute/copy local script or remote script and pass data/file/script to instances at the time of their creation such that the data is immediately available on system boot. such as Amazon EC2: user_data or user_data_base64 on aws_instance, aws_launch_template, and aws_launch_configuration is doing similar work.

local-exec Provisioner
The local-exec provisioner invokes a local executable after a resource is created. This invokes a process on the machine running Terraform, not on the resource.

Example of local-exec Provisioner

resource "aws_instance" "web" {
  # ...

  provisioner "local-exec" {
    command = "echo ${aws_instance.web.private_ip} >> private_ips.txt"
  }
}

The following arguments are supported:

command – (Required) This is the command to execute. It can be provided as a relative path to the current working directory or as an absolute path. It is evaluated in a shell, and can use environment variables or Terraform variables.

working_dir – (Optional) If provided, specifies the working directory where command will be executed. It can be provided as as a relative path to the current working directory or as an absolute path. The directory must exist.

interpreter – (Optional) If provided, this is a list of interpreter arguments used to execute the command. The first argument is the interpreter itself. It can be provided as a relative path to the current working directory or as an absolute path. The remaining arguments are appended prior to the command. This allows building command lines of the form “/bin/bash”, “-c”, “echo foo”. If interpreter is unspecified, sensible defaults will be chosen based on the system OS.

environment – (Optional) block of key value pairs representing the environment of the executed command. inherits the current process environment.

Example of multiple local-exec Provisioners:

resource "aws_instance" "web" {
  ami           = "ami-5b673c34"
  instance_type = "t2.micro"

  tags = {
    Name = "HelloWorld"
  }

 provisioner "local-exec" {
    command = "echo 'Welcome to Terraform Allianz Classx' >> /Users/rajeshkumar/terraform/local-exec.txt"
  }

 provisioner "local-exec" {
    command = "/bin/bash deploy.sh"
  }

 provisioner "local-exec" {
    command = "open WFH, '>completed.txt' and print WFH scalar localtime"
    interpreter = ["perl", "-e"]
  }
}

Creation-Time Provisioners
By default, provisioners run when the resource they are defined within is created. Creation-time provisioners are only run during creation, not during updating or any other lifecycle.

If a creation-time provisioner fails, the resource is marked as tainted. A tainted resource will be planned for destruction and recreation upon the next terraform apply.

Destroy-Time Provisioners

If when = “destroy” is specified, the provisioner will run when the resource it is defined within is destroyed. Destroy provisioners are run before the resource is destroyed. If they fail, Terraform will error and rerun the provisioners again on the next terraform apply.

resource "aws_instance" "web" {
  # ...

  provisioner "local-exec" {
    when    = "destroy"
    command = "echo 'Destroy-time provisioner'"
  }
}

Failure Behavior

By default, provisioners that fail will also cause the Terraform apply itself to fail. The on_failure setting can be used to change this. The allowed values are:

continue” – Ignore the error and continue with creation or destruction.

fail” – Raise an error and stop applying (the default behavior). If this is a creation provisioner, taint the resource.

resource "aws_instance" "web" {
  # ...

  provisioner "local-exec" {
    command    = "echo The server's IP address is ${self.private_ip}"
    on_failure = "continue"
  }
}

Provisioners Without a Resource
If you need to run provisioners that aren’t directly associated with a specific resource, you can associate them with a null_resource.

Instances of null_resource are treated like normal resources, but they don’t do anything. Like with any other resource, you can configure provisioners and connection details on a null_resource.

resource "null_resource" "example1" {
  provisioner "local-exec" {
    command = "open WFH, '>completed.txt' and print WFH scalar localtime"
    interpreter = ["perl", "-e"]
  }
}

resource "null_resource" "example2" {
  provisioner "local-exec" {
    command = "Get-Date > completed.txt"
    interpreter = ["PowerShell", "-Command"]
  }
}
Rajesh Kumar
Follow me