Terraform's "generic" local-exec provisioner executes a command on the system where Terraform is running. A given resource in a Terraform configuration may contain multiple provisioners, and they are executed in the order in which they appear in the resource. Local-exec provisioners have four arguments that you can set:

  • The required command argument specifies the command string to execute.
  • The optional working_dir argument establishes the working directory for the command.
  • The optional environment argument defines values for a set of environment variables that will be used when executing the command. This argument is a map containing name-value assignments for each variable.
  • The optional interpreter argument defines the shell to use when running the command string, along with any required arguments. If it isn't provided a default will be used, which may lead to undesirable results.

An Example

To try an example of a local-exec provisioner, download the file localexec.tf into the Terraform configuration directory you have been using. This example "pings" the leader instance created in our ongoing example:


resource "null_resource" "local_provisioners" {
  depends_on = [openstack_compute_floatingip_associate_v2.leader]

  provisioner "local-exec" {
    environment = { FIP = openstack_networking_floatingip_v2.leader.address }
    command = "ping -c 10 $FIP"
    interpreter = ["bash", "-c"]
  }
}

The null resource containing the provisioner must have a name that is unique within the configuration. The resource depends on the creation of a floating IP address association for the leader instance, so we know that address will be available when the provisioner is executed. Local-exec provisioners do not need a Connection block to provide credentials, as they are being run on the local system. However, if they are issuing a command that accesses a remote instance, they can use variables and attributes from the Terraform configuration to access connection information.

This provisioner defines an environment variable named FIP to hold the floating IP address of the leader instance (line 5). It then uses that variable in the command that is executed to ping that address ten times (line 6). To ensure that the command is executed correctly, we run it in the "bash" shell, whose "-c" argument specifies that the following string argument should be interpreted as a command to execute. We do this because a different shell might not be able to interpret the environment variable reference we are using.

An alternative implementation of this provisioner could have skipped using the environment block and instead had Terraform substitute the IP address from its attribute directly into the command string, like this:


command = "ping ${openstack_networking_floatingip_v2.leader.address}"

Waiting for an Instance

Try redeploying your configuration with terraform apply -var-file=terratest.tfvars and after entering "yes" at the prompt, watch the output carefully. Was the ping command able to connect to the leader instance immediately, or at all? While Terraform knew the floating IP address where it could reach the instance, the instance may still have been booting up and initializing, making it initially unresponsive. What we would really like is for our command to be delayed until the instance will be responsive.

A resource's provisioners are run in order starting as soon as their parent resource is created. Local-exec provisioners just charge ahead when executing their command, but remote-exec provisioners wait until they can communicate with the instance before trying to execute their commands. To give your local-exec provisioners this same sort of patience, all you need to do is place at least one remote-exec provisioner before your local-exec. Terraform will not proceed to your local-exec until the preceding remote-exec has been successful.

 
©  |   Cornell University    |   Center for Advanced Computing    |   Copyright Statement    |   Inclusivity Statement