github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/website/docs/language/resources/provisioners/syntax.mdx (about)

     1  ---
     2  page_title: Provisioners
     3  description: >-
     4    Provisioners run scripts on a local or remote machine during resource creation
     5    or destruction. Learn how to declare provisioners in a configuration.
     6  ---
     7  
     8  # Provisioners
     9  
    10  You can use provisioners to model specific actions on the local machine or on
    11  a remote machine in order to prepare servers or other infrastructure objects
    12  for service.
    13  
    14  -> **Note:** We removed the Chef, Habitat, Puppet, and Salt Masterless provisioners in Terraform v0.15.0. Information about these legacy provisioners is still available in the documentation for [Terraform v1.1 (and earlier)](/terraform/language/v1.1.x/resources/provisioners/syntax).
    15  
    16  ## Provisioners are a Last Resort
    17  
    18  > **Hands-on:** Try the [Provision Infrastructure Deployed with Terraform](/terraform/tutorials/provision?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorials to learn about more declarative ways to handle provisioning actions.
    19  
    20  Terraform includes the concept of provisioners as a measure of pragmatism,
    21  knowing that there are always certain behaviors that cannot be directly
    22  represented in Terraform's declarative model.
    23  
    24  However, they also add a considerable amount of complexity and uncertainty to
    25  Terraform usage. Firstly, Terraform cannot model the actions of provisioners
    26  as part of a plan because they can in principle take any action. Secondly,
    27  successful use of provisioners requires coordinating many more details than
    28  Terraform usage usually requires: direct network access to your servers,
    29  issuing Terraform credentials to log in, making sure that all of the necessary
    30  external software is installed, etc.
    31  
    32  The following sections describe some situations which can be solved with
    33  provisioners in principle, but where better solutions are also available. We do
    34  not recommend using provisioners for any of the use-cases described in the
    35  following sections.
    36  
    37  Even if your specific use-case is not described in the following sections, we
    38  still recommend attempting to solve it using other techniques first, and use
    39  provisioners only if there is no other option.
    40  
    41  ### Passing data into virtual machines and other compute resources
    42  
    43  When deploying virtual machines or other similar compute resources, we often
    44  need to pass in data about other related infrastructure that the software on
    45  that server will need to do its job.
    46  
    47  The various provisioners that interact with remote servers over SSH or WinRM
    48  can potentially be used to pass such data by logging in to the server and
    49  providing it directly, but most cloud computing platforms provide mechanisms
    50  to pass data to instances at the time of their creation such that the data
    51  is immediately available on system boot. For example:
    52  
    53  * Alibaba Cloud: `user_data` on
    54    [`alicloud_instance`](https://registry.terraform.io/providers/aliyun/alicloud/latest/docs/resources/instance)
    55    or [`alicloud_launch_template`](https://registry.terraform.io/providers/aliyun/alicloud/latest/docs/resources/launch_template).
    56  * Amazon EC2: `user_data` or `user_data_base64` on
    57    [`aws_instance`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance),
    58    [`aws_launch_template`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/launch_template),
    59    and [`aws_launch_configuration`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/launch_configuration).
    60  * Amazon Lightsail: `user_data` on
    61    [`aws_lightsail_instance`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lightsail_instance).
    62  * Microsoft Azure: `custom_data` on
    63    [`azurerm_virtual_machine`](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_machine)
    64    or [`azurerm_virtual_machine_scale_set`](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_machine_scale_set).
    65  * Google Cloud Platform: `metadata` on
    66    [`google_compute_instance`](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance)
    67    or [`google_compute_instance_group`](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance_group).
    68  * Oracle Cloud Infrastructure: `metadata` or `extended_metadata` on
    69    [`oci_core_instance`](https://registry.terraform.io/providers/hashicorp/oci/latest/docs/resources/core_instance)
    70    or [`oci_core_instance_configuration`](https://registry.terraform.io/providers/hashicorp/oci/latest/docs/resources/core_instance_configuration).
    71  * VMware vSphere: Attach a virtual CDROM to
    72    [`vsphere_virtual_machine`](https://registry.terraform.io/providers/hashicorp/vsphere/latest/docs/resources/virtual_machine)
    73    using the `cdrom` block, containing a file called `user-data.txt`.
    74  
    75  Many official Linux distribution disk images include software called
    76  [cloud-init](https://cloudinit.readthedocs.io/en/latest/) that can automatically
    77  process in various ways data passed via the means described above, allowing
    78  you to run arbitrary scripts and do basic system configuration immediately
    79  during the boot process and without the need to access the machine over SSH.
    80  
    81  > **Hands-on:** Try the [Provision Infrastructure with Cloud-Init](/terraform/tutorials/provision/cloud-init?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial.
    82  
    83  If you are building custom machine images, you can make use of the "user data"
    84  or "metadata" passed by the above means in whatever way makes sense to your
    85  application, by referring to your vendor's documentation on how to access the
    86  data at runtime.
    87  
    88  This approach is _required_ if you intend to use any mechanism in your cloud
    89  provider for automatically launching and destroying servers in a group,
    90  because in that case individual servers will launch unattended while Terraform
    91  is not around to provision them.
    92  
    93  Even if you're deploying individual servers directly with Terraform, passing
    94  data this way will allow faster boot times and simplify deployment by avoiding
    95  the need for direct network access from Terraform to the new server and for
    96  remote access credentials to be provided.
    97  
    98  ### Provisioning files using cloud-config
    99  
   100  You can add the [`cloudinit_config`](https://registry.terraform.io/providers/hashicorp/cloudinit/latest/docs) data source to your Terraform configuration and specify the files you want to provision as `text/cloud-config` content. The `cloudinit_config` data source renders multi-part MIME configurations for use with [cloud-init](https://cloudinit.readthedocs.io/en/latest/). Pass the files in the `content` field as YAML-encoded configurations using the `write_files` block. 
   101  
   102  In the following example, the `my_cloud_config` data source specifies a `text/cloud-config` MIME part named `cloud.conf`. The `part.content` field is set to [`yamlencode`](/terraform/language/functions/yamlencode), which encodes the `write_files` JSON object as YAML so that the system can provision the referenced files.
   103  
   104  ```hcl
   105  data "cloudinit_config" "my_cloud_config" {
   106    gzip          = false
   107    base64_encode = false
   108  
   109    part {
   110      content_type = "text/cloud-config"
   111      filename     = "cloud.conf"
   112      content = yamlencode(
   113        {
   114          "write_files" : [
   115            {
   116              "path" : "/etc/foo.conf",
   117              "content" : "foo contents",
   118            },
   119            {
   120              "path" : "/etc/bar.conf",
   121              "content" : file("bar.conf"),
   122            },
   123            {
   124              "path" : "/etc/baz.conf",
   125              "content" : templatefile("baz.tpl.conf", { SOME_VAR = "qux" }),
   126            },
   127          ],
   128        }
   129      )
   130    }
   131  }
   132  ```
   133  
   134  ### Running configuration management software
   135  
   136  As a convenience to users who are forced to use generic operating system
   137  distribution images, Terraform includes a number of specialized provisioners
   138  for launching specific configuration management products.
   139  
   140  We strongly recommend not using these, and instead running system configuration
   141  steps during a custom image build process. For example,
   142  [HashiCorp Packer](https://www.packer.io/) offers a similar complement of
   143  configuration management provisioners and can run their installation steps
   144  during a separate build process, before creating a system disk image that you
   145  can deploy many times.
   146  
   147  > **Hands-on:** Try the [Provision Infrastructure with Packer](/terraform/tutorials/provision/packer?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial.
   148  
   149  If you are using configuration management software that has a centralized server
   150  component, you will need to delay the _registration_ step until the final
   151  system is booted from your custom image. To achieve that, use one of the
   152  mechanisms described above to pass the necessary information into each instance
   153  so that it can register itself with the configuration management server
   154  immediately on boot, without the need to accept commands from Terraform over
   155  SSH or WinRM.
   156  
   157  ### First-class Terraform provider functionality may be available
   158  
   159  It is technically possible to use the `local-exec` provisioner to run the CLI
   160  for your target system in order to create, update, or otherwise interact with
   161  remote objects in that system.
   162  
   163  If you are trying to use a new feature of the remote system that isn't yet
   164  supported in its Terraform provider, that might be the only option. However,
   165  if there _is_ provider support for the feature you intend to use, prefer to
   166  use that provider functionality rather than a provisioner so that Terraform
   167  can be fully aware of the object and properly manage ongoing changes to it.
   168  
   169  Even if the functionality you need is not available in a provider today, we
   170  suggest to consider `local-exec` usage a temporary workaround and to also
   171  open an issue in the relevant provider's repository to discuss adding
   172  first-class provider support. Provider development teams often prioritize
   173  features based on interest, so opening an issue is a way to record your
   174  interest in the feature.
   175  
   176  Provisioners are used to execute scripts on a local or remote machine
   177  as part of resource creation or destruction. Provisioners can be used to
   178  bootstrap a resource, cleanup before destroy, run configuration management, etc.
   179  
   180  ## How to use Provisioners
   181  
   182  -> **Note:** Provisioners should only be used as a last resort. For most
   183  common situations there are better alternatives. For more information, see
   184  the sections above.
   185  
   186  If you are certain that provisioners are the best way to solve your problem
   187  after considering the advice in the sections above, you can add a
   188  `provisioner` block inside the `resource` block of a compute instance.
   189  
   190  ```hcl
   191  resource "aws_instance" "web" {
   192    # ...
   193  
   194    provisioner "local-exec" {
   195      command = "echo The server's IP address is ${self.private_ip}"
   196    }
   197  }
   198  ```
   199  
   200  The `local-exec` provisioner requires no other configuration, but most other
   201  provisioners must connect to the remote system using SSH or WinRM.
   202  You must include [a `connection` block](/terraform/language/resources/provisioners/connection) so that Terraform knows how to communicate with the server.
   203  
   204  Terraform includes several built-in provisioners. You can also use third-party provisioners as plugins, by placing them
   205  in `%APPDATA%\terraform.d\plugins`, `~/.terraform.d/plugins`, or the same
   206  directory where the Terraform binary is installed. However, we do not recommend
   207  using any provisioners except the built-in `file`, `local-exec`, and
   208  `remote-exec` provisioners.
   209  
   210  All provisioners support the `when` and `on_failure` meta-arguments, which
   211  are described below (see [Destroy-Time Provisioners](#destroy-time-provisioners)
   212  and [Failure Behavior](#failure-behavior)).
   213  
   214  ### The `self` Object
   215  
   216  Expressions in `provisioner` blocks cannot refer to their parent resource by
   217  name. Instead, they can use the special `self` object.
   218  
   219  The `self` object represents the provisioner's parent resource, and has all of
   220  that resource's attributes. For example, use `self.public_ip` to reference an
   221  `aws_instance`'s `public_ip` attribute.
   222  
   223  -> **Technical note:** Resource references are restricted here because
   224  references create dependencies. Referring to a resource by name within its own
   225  block would create a dependency cycle.
   226  
   227  ## Suppressing Provisioner Logs in CLI Output
   228  
   229  The configuration for a `provisioner` block may use sensitive values, such as
   230  [`sensitive` variables](/terraform/language/values/variables#suppressing-values-in-cli-output) or
   231  [`sensitive` output values](/terraform/language/values/outputs#sensitive-suppressing-values-in-cli-output).
   232  In this case, all log output from the provisioner is automatically suppressed to
   233  prevent the sensitive values from being displayed.
   234  
   235  ## Creation-Time Provisioners
   236  
   237  By default, provisioners run when the resource they are defined within is
   238  created. Creation-time provisioners are only run during _creation_, not
   239  during updating or any other lifecycle. They are meant as a means to perform
   240  bootstrapping of a system.
   241  
   242  If a creation-time provisioner fails, the resource is marked as **tainted**.
   243  A tainted resource will be planned for destruction and recreation upon the
   244  next `terraform apply`. Terraform does this because a failed provisioner
   245  can leave a resource in a semi-configured state. Because Terraform cannot
   246  reason about what the provisioner does, the only way to ensure proper creation
   247  of a resource is to recreate it. This is tainting.
   248  
   249  You can change this behavior by setting the `on_failure` attribute,
   250  which is covered in detail below.
   251  
   252  ## Destroy-Time Provisioners
   253  
   254  If `when = destroy` is specified, the provisioner will run when the
   255  resource it is defined within is _destroyed_.
   256  
   257  ```hcl
   258  resource "aws_instance" "web" {
   259    # ...
   260  
   261    provisioner "local-exec" {
   262      when    = destroy
   263      command = "echo 'Destroy-time provisioner'"
   264    }
   265  }
   266  ```
   267  
   268  Destroy provisioners are run before the resource is destroyed. If they
   269  fail, Terraform will error and rerun the provisioners again on the next
   270  `terraform apply`. Due to this behavior, care should be taken for destroy
   271  provisioners to be safe to run multiple times.
   272  
   273  ~> **Note**: Destroy provisioners of this resource do not run if `create_before_destroy` is set to `true`. This [GitHub issue](https://github.com/hashicorp/terraform/issues/13549) contains more details.
   274  
   275  Destroy-time provisioners can only run if they remain in the configuration
   276  at the time a resource is destroyed. If a resource block with a destroy-time
   277  provisioner is removed entirely from the configuration, its provisioner
   278  configurations are removed along with it and thus the destroy provisioner
   279  won't run. To work around this, a multi-step process can be used to safely
   280  remove a resource with a destroy-time provisioner:
   281  
   282  * Update the resource configuration to include `count = 0`.
   283  * Apply the configuration to destroy any existing instances of the resource, including running the destroy provisioner.
   284  * Remove the resource block entirely from configuration, along with its `provisioner` blocks.
   285  * Apply again, at which point no further action should be taken since the resources were already destroyed.
   286  
   287  Because of this limitation, you should use destroy-time provisioners sparingly and with care.
   288  
   289  ~> **NOTE:** A destroy-time provisioner within a resource that is tainted _will not_ run. This includes resources that are marked tainted from a failed creation-time provisioner or tainted manually using `terraform taint`.
   290  
   291  ## Multiple Provisioners
   292  
   293  Multiple provisioners can be specified within a resource. Multiple provisioners
   294  are executed in the order they're defined in the configuration file.
   295  
   296  You may also mix and match creation and destruction provisioners. Only
   297  the provisioners that are valid for a given operation will be run. Those
   298  valid provisioners will be run in the order they're defined in the configuration
   299  file.
   300  
   301  Example of multiple provisioners:
   302  
   303  ```hcl
   304  resource "aws_instance" "web" {
   305    # ...
   306  
   307    provisioner "local-exec" {
   308      command = "echo first"
   309    }
   310  
   311    provisioner "local-exec" {
   312      command = "echo second"
   313    }
   314  }
   315  ```
   316  
   317  ## Failure Behavior
   318  
   319  By default, provisioners that fail will also cause the Terraform apply
   320  itself to fail. The `on_failure` setting can be used to change this. The
   321  allowed values are:
   322  
   323  * `continue` - Ignore the error and continue with creation or destruction.
   324  
   325  * `fail` - Raise an error and stop applying (the default behavior). If this is a creation provisioner,
   326    taint the resource.
   327  
   328  Example:
   329  
   330  ```hcl
   331  resource "aws_instance" "web" {
   332    # ...
   333  
   334    provisioner "local-exec" {
   335      command    = "echo The server's IP address is ${self.private_ip}"
   336      on_failure = continue
   337    }
   338  }
   339  ```