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 ```