terraform provisioners provisioning - ghdrako/doc_snipets GitHub Wiki

Terrafor Provisioners

creating some resources and you need to run some sort of script or operations that you want to perform locally or on the remote resource. You can fulfill this expectation using Terraform provisioners. The execution of Terraform provisioners does not need to be idempotent or atomic, since it is executing an arbitrary script or instruction. Terraform will not be able to track the results and status of provisioners in the same way it is used to doing for other resources. Because of this, HashiCorp recommends the use of Terraform provisioners as a last resort when you don't have any other option to complete your goal.

Usecasess:

  • Loading data into a virtual machine
  • Bootstrapping a virtual machine for a config manager
  • Saving data locally on your system

The remote-exec provisioner connects to a remote machine via WinRM or SSH and helps you to run a script remotely. The remote machine should allow remote connection; otherwise, the Terraform remote-exec provisioner will not be able to run the provided script. Instead of using remote-exec to pass data to a virtual machine, most cloud providers provide built-in tools to pass data, such as the user_data argument in AWS or custom_data in Azure. All of the public clouds support some sort of data exchange that doesn't require remote access to the machine; for further reading about built-in tools to pass data in different clouds, you can refer to https://www.terraform.io/docs/language/resources/provisioners/syntax.html.

There are many Linux OS images, such as Red Hat, Ubuntu, and SUSE, that have an built-in software called cloud-init that allows you to run arbitrary scripts and perform some basic system configuration during the initial deployment of the server itself, and because of this, you won't be required to take SSH of the server explicitly.

In addition to the remote-exec provisioner, there are also configuration management provisioners for Chef, Puppet, Salt, and so on. They allow you to bootstrap the virtual machine to use your config manager of choice. One of the best alternatives is to create a custom image with the config manager software already installed and get it to register with your config management server at bootup using one of the data loading options mentioned in the previous paragraph.

Terraform provisioner types:

Terraform supports two types of provisioners.

  • Inline provisioners: Inline provisioners are defined directly within the Terraform configuration file.
  • External provisioners: External provisioners are separate scripts or commands executed by Terraform.

obraz

  • local-exec provisioner
resource "aws_instance" "example" {
  # ...
  provisioner "local-exec" {
    command = "echo The EC2 server IP address is ${self.private_ip}"
  }
}

Defined an object named self that represents the provisioner's parent resource and has the ability to extract all of that resource's attributes. In our case, we have defined self.public_ip, which is referencing aws_instance's public_ip attribute.

  • file provisioner File provisioners provide a way to copy required files or artifacts from the host machine where Terraform is running to the target resources that Terraform is creating or modifying. File provisioners come in handy when you want to transport certain script files, configuration files, artifacts, etc., in the form of JAR files or binaries. These file provisioners can talk to the destination resource when the resource is created or boots for the first time. File provisioners create a connection block between the Terraform host and destination resource to transfer the required files or scripts.

  • remote-exec provisioner

provider "vsphere" {
  user = var.vsphere_username
  password = var.vsphere_password
  vsphere_server = var.vsphere_server
  allow_unverified_ssl = true
}
resource "vsphere_virtual_machine" "example_vm" {
  name = "my-vm"
  resource_pool_id = data.vsphere_resource_pool.pool.id
  datastore_id = data.vsphere_datastore.datastore.id
  template_uuid = data.vsphere_virtual_machine.template.id
  num_cpus = 2
  memory = 4096
  network_interface {
    network_id = data.vsphere_network.network.id
  }
  provisioner "remote-exec" {
    inline = [
      "echo 'Hello, Provisioner!'",
      "echo 'This is an example of an inline provisioner.'",
      "echo 'You can run custom scripts or commands here.'",
    ]
  }
}

The local-exec provisioner executes a command locally on the machine running Terraform, not the VM instance itself. You're using this provisioner versus the others so we don't have to worry about specifying any connection info right now.

resource "google_compute_instance" "vm_instance" {
  name         = "terraform-instance"
  machine_type = "f1-micro"
  tags         = ["web", "dev"]
  provisioner "local-exec" {
    command = "echo ${google_compute_instance.vm_instance.name}:  ${google_compute_instance.vm_instance.network_interface[0].access_config[0].nat_ip} >> ip_address.txt"
  }
  # ...
}
Use an External Provisioner
resource "null_resource" "configure_vm" {
  triggers = {
    vm_id = vsphere_virtual_machine.my_vm.id
  }
  provisioner "local-exec" {
    command = "powershell -Command \".\\join_domain.ps1\""
  }
  depends_on = [vsphere_virtual_machine.my_vm]
} 
# PowerShell script to join a Windows VM to a domain
$domain = "example.com"
$username = "admin"
$password = "password"
Add-Computer -DomainName $domain -Credential (Get-Credential
-UserName $username -Password $password)

Terraform treats provisioners differently from other arguments. Provisioners only run when a resource is created, but adding a provisioner does not force that resource to be destroyed and recreated.

Use terraform taint to tell Terraform to recreate the instance:
terraform taint google_compute_instance.vm_instance

Failed Provisioners and Tainted Resources

If a resource is successfully created but fails a provisioning step, Terraform will error and mark the resource as tainted. A resource that is tainted still exists, but shouldn't be considered safe to use, since provisioning failed.

When you generate your next execution plan, Terraform will remove any tainted resources and create new resources, attempting to provision them again after creation.

Destroy Provisioners

Provisioners can also be defined that run only during a destroy operation. These are useful for performing system cleanup, extracting data, etc.

For many resources, using built-in cleanup mechanisms is recommended if possible (such as init scripts), but provisioners can be used if necessary.

This lab won't show any destroy provisioner examples. If you need to use destroy provisioners, please see the provisioner documentation.

The execution of Terraform provisioners does not need to be idempotent or atomic, since it is executing an arbitrary script or instruction. Terraform will not be able to track the results and status of provisioners in the same way it is used to doing for other resources. Because of this, HashiCorp recommends the use of Terraform provisioners as a last resort when you don't have any other option to complete your goal.

The remote-exec provisioner connects to a remote machine via WinRM or SSH and helps you to run a script remotely. The remote machine should allow remote connection; otherwise, the Terraform remote-exec provisioner will not be able to run the provided script. Instead of using remote-exec to pass data to a virtual machine, most cloud providers provide built-in tools to pass data, such as the user_data argument in AWS or custom_data in Azure

  • Google Cloud Platform metadata on google_compute_instance or google_compute_instance_group
  • Microsoft Azure custom_data on azurerm_virtual_machine or azurerm_virtual_machine_scale_set

For further reading about built-in tools to pass data in different clouds, you can refer to https://www.terraform.io/docs/language/resources/provisioners/syntax.html.