github.com/muratcelep/terraform@v1.1.0-beta2-not-internal-4/website/upgrade-guides/0-15.html.markdown (about) 1 --- 2 layout: "language" 3 page_title: "Upgrading to Terraform v0.15" 4 sidebar_current: "upgrade-guides-0-15" 5 description: |- 6 Upgrading to Terraform v0.15 7 --- 8 9 # Upgrading to Terraform v0.15 10 11 Terraform v0.15 is a major release and so it includes some small changes in 12 behavior that you may need to consider when upgrading. This guide is intended 13 to help with that process. 14 15 The goal of this guide is to cover the most common upgrade concerns and 16 issues that would benefit from more explanation and background. The exhaustive 17 list of changes will always be 18 [the Terraform Changelog](https://github.com/muratcelep/terraform/blob/v0.15/CHANGELOG.md). 19 After reviewing this guide, we recommend reviewing the Changelog to check for 20 specific notes about less-commonly-used features. 21 22 This guide is also not intended as an overview of the new features in 23 Terraform v0.15. This release includes other enhancements that don't need any 24 special attention during upgrade, but those are described in the changelog and 25 elsewhere in the Terraform documentation. 26 27 This guide focuses on changes from v0.14 to v0.15. Terraform supports upgrade 28 tools and features only for one major release upgrade at a time, so if you are 29 currently using a version of Terraform prior to v0.14 please upgrade through 30 the latest minor releases of all of the intermediate versions first, reviewing 31 the previous upgrade guides for any considerations that may be relevant to you. 32 33 Unlike the previous few Terraform major releases, v0.15's upgrade concerns are 34 largely conclusions of deprecation cycles left over from previous releases, 35 many of which already had deprecation warnings in v0.14. If you previously 36 responded to those while using Terraform v0.14 then you hopefully won't need 37 to make any special changes to upgrade, although we still recommend reviewing 38 the content below to confirm, particularly if you see new errors or unexpected 39 behavior after upgrading from Terraform v0.14. 40 41 -> If you run into any problems during upgrading that are not addressed by the 42 information in this guide, please feel free to start a topic in 43 [The Terraform community forum](https://discuss.hashicorp.com/c/terraform-core), 44 describing the problem you've encountered in enough detail that other readers 45 may be able to reproduce it and offer advice. 46 47 Upgrade guide sections: 48 49 * [Sensitive Output Values](#sensitive-output-values) 50 * [Legacy Configuration Language Features](#legacy-configuration-language-features) 51 * [Alternative (Aliased) Provider Configurations Within Modules](#alternative-provider-configurations-within-modules) 52 * [Commands Accepting a Configuration Directory Argument](#commands-accepting-a-configuration-directory-argument) 53 * [Microsoft Windows Terminal Support](#microsoft-windows-terminal-support) 54 * [Other Minor Command Line Behavior Changes](#other-minor-command-line-behavior-changes) 55 * [Azure Backend `arm_`-prefixed Arguments](#azure-backend-removed-arguments) 56 57 ## Sensitive Output Values 58 59 Terraform v0.14 previously introduced the ability for Terraform to track and 60 propagate the "sensitivity" of values through expressions that include 61 references to sensitive input variables and output values. For example: 62 63 ```hcl 64 variable "example" { 65 type = string 66 sensitive = true 67 } 68 69 resource "example" "example" { 70 # The following value is also treated as sensitive, because it's derived 71 # from var.example. 72 name = "foo-${var.example}" 73 } 74 ``` 75 76 As part of that feature, Terraform also began requiring you to mark an output 77 value as sensitive if its definition includes any sensitive values itself: 78 79 ```hcl 80 output "example" { 81 value = "foo-${var.example}" 82 83 # Must mark this output value as sensitive, because it's derived from 84 # var.example that is declared as sensitive. 85 sensitive = true 86 } 87 ``` 88 89 Terraform v0.15 extends this mechanism to also work for values derived from 90 resource attributes that the provider has declared as being sensitive. 91 Provider developers will typically mark an attribute as sensitive if the 92 remote system has documented the corresponding field as being sensitive, such 93 as if the attribute always contains a password or a private key. 94 95 As a result of that, after upgrading to Terraform v0.15 you may find that 96 Terraform now reports some of your output values as invalid, if they were 97 derived from sensitive attributes without also being marked as sensitive: 98 99 ``` 100 ╷ 101 │ Error: Output refers to sensitive values 102 │ 103 │ on sensitive-resource-attr.tf line 5: 104 │ 5: output "private_key" { 105 │ 106 │ Expressions used in outputs can only refer to sensitive values if the 107 │ sensitive attribute is true. 108 ╵ 109 ``` 110 111 If you were intentionally exporting a sensitive value, you can address the 112 error by adding an explicit declaration `sensitive = true` to the output 113 value declaration: 114 115 ```hcl 116 output "private_key" { 117 value = tls_private_key.example.private_key_pem 118 sensitive = true 119 } 120 ``` 121 122 With that addition, if this output value was a root module output value then 123 Terraform will hide its value in the `terraform plan` and `terraform apply` 124 output: 125 126 ``` 127 Changes to Outputs: 128 + private_key = (sensitive value) 129 ``` 130 131 -> **Note:** The declaration of an output value as sensitive must be made 132 within the module that declares the output, so if you depend on a third-party 133 module that has a sensitive output value that is lacking this declaration then 134 you will need to wait for a new version of that module before you can upgrade 135 to Terraform v0.15. 136 137 The value is only hidden in the main UI, and so the sensitive value 138 will still be recorded in the state. If you declared this output value in order 139 to use it as part of integration with other software, you can still retrieve 140 the cleartext value using commands intended for machine rather than human 141 consumption, such as `terraform output -json` or `terraform output -raw`: 142 143 ```shellsession 144 $ terraform output -raw private_key 145 -----BEGIN RSA PRIVATE KEY----- 146 MIIEowIBAAKCAQEAoahsvJ1rIxTIOOmJZ7yErs5eOq/Kv9+5l3h0LbxW78K8//Kb 147 OMU3v8F3h8jp+AB/1zGr5UBYfnYp5ncJm/OTCXLFAHxGibEbRnf1m2A3o0hEaWsw 148 # (etc...) 149 ``` 150 151 If you consider Terraform's treatment of a sensitive value to be too 152 conservative and you'd like to force Terraform to treat a sensitive value as 153 non-sensitive, you can use 154 [the `nonsensitive` function](/docs/language/functions/nonsensitive.html) to 155 override Terraform's automatic detection: 156 157 ```hcl 158 output "private_key" { 159 # WARNING: Terraform will display this result as cleartext 160 value = nonsensitive(tls_private_key.example.private_key_pem) 161 } 162 ``` 163 164 For more information on the various situations where sensitive values can 165 originate in Terraform, refer to the following sections: 166 167 * [Sensitive Input Variables](/docs/language/values/variables.html#suppressing-values-in-cli-output) 168 * [Sensitive Resource Attributes](/docs/language/expressions/references.html#sensitive-resource-attributes) 169 * [Sensitive Output Values](/docs/language/values/outputs.html#sensitive) 170 171 -> **Note:** The new behavior described in this section was previously 172 available in Terraform v0.14 as the 173 [language experiment](/docs/language/settings/#experimental-language-features) 174 `provider_sensitive_attrs`. That experiment has now concluded, so if you were 175 participating in that experiment then you'll now need to remove the experiment 176 opt-in from your module as part of upgrading to Terraform v0.15. 177 178 ## Legacy Configuration Language Features 179 180 Terraform v0.12 introduced new syntax for a variety of existing Terraform 181 language features that were intended to make the language easier to read and 182 write and, in some cases, to better allow for future changes to the language. 183 184 Many of the old forms remained available but deprecated from v0.12 through to 185 v0.14, with these deprecations finally concluding in the v0.15 release. Those 186 who used the `terraform 0.12upgrade` command when upgrading from Terraform v0.11 187 to v0.12 will have had these updated automatically, but we've summarized the 188 changes below to help with any remaining legacy forms you might encounter while 189 upgrading to Terraform v0.15: 190 191 * The built-in functions `list` and `map` were replaced with first-class syntax 192 `[ ... ]` and `{ ... }` in Terraform v0.12, and we've now removed the 193 deprecated functions in order to resolve the ambiguity with the syntax used 194 to declare list and map type constraints inside `variable` blocks. 195 196 If you need to update a module which was using the `list` function, you 197 can get the same result by replacing `list(...)` with `tolist([...])`. 198 For example: 199 200 ```diff 201 - list("a", "b", "c") 202 + tolist(["a", "b", "c"]) 203 ``` 204 205 If you need to update a module which was using the `map` function, you 206 can get the same result by replacing `map(...)` with `tomap({...})`. 207 For example: 208 209 ```diff 210 - map("a", 1, "b", 2) 211 + tomap({ a = 1, b = 2 }) 212 ``` 213 214 The above examples include the type conversion functions `tolist` and 215 `tomap` to ensure that the result will always be of the same type as 216 before. However, in most situations those explicit type conversions won't 217 be necessary because Terraform can infer the necessary type conversions 218 automatically from context. In those cases, you can just use the 219 `[ ... ]` or `{ ... }` syntax directly, without a conversion function. 220 221 * In `variable` declaration blocks, the `type` argument previously accepted 222 v0.11-style type constraints given as quoted strings. This legacy syntax 223 is removed in Terraform v0.15. 224 225 To update an old-style type constraint to the modern syntax, start by 226 removing the quotes so that the argument is a bare keyword rather than 227 a string: 228 229 ```hcl 230 variable "example" { 231 type = string 232 } 233 ``` 234 235 Additionally, if the previous type constraint was either `"list"` or 236 `"map`", add a type argument to specify the element type of the collection. 237 Terraform v0.11 typically supported only collections of strings, so in 238 most cases you can set the element type to `string`: 239 240 ```hcl 241 variable "example" { 242 type = list(string) 243 } 244 245 variable "example" { 246 type = map(string) 247 } 248 ``` 249 250 * In `lifecycle` blocks nested inside `resource` blocks, Terraform previously 251 supported a legacy value `["*"]` for the `ignore_changes` argument, which 252 is removed in Terraform v0.15. 253 254 Instead, use the `all` keyword to indicate that you wish to ignore changes 255 to all of the resource arguments: 256 257 ```hcl 258 lifecycle { 259 ignore_changes = all 260 } 261 ``` 262 263 * Finally, Terraform v0.11 and earlier required all non-constant expressions 264 to be written using string interpolation syntax, even if the result was 265 not a string. Terraform v0.12 introduced a less confusing syntax where 266 arguments can accept any sort of expression without any special wrapping, 267 and so the interpolation-style syntax has been redundant and deprecated 268 in recent Terraform versions. 269 270 For this particular change we have not made the older syntax invalid, but 271 we do still recommend updating interpolation-only expressions to bare 272 expressions to improve readability: 273 274 ```diff 275 - example = "${var.foo}" 276 + example = var.foo 277 ``` 278 279 This only applies to arguments where the value is a single expression without 280 any string concatenation. You must continue to use the `${ ... }` syntax for 281 situations where you are combining string values together into a larger 282 string. 283 284 The `terraform fmt` command can detect and repair simple examples of the 285 legacy interpolation-only syntax, and so we'd recommend running 286 `terraform fmt` on your modules once you've addressed any of the other 287 situations above that could block configuration parsing in order to update 288 your configurations to the typical Terraform language style conventions. 289 290 ## Alternative Provider Configurations Within Modules 291 292 Terraform's provider configuration scheme includes the idea of a "default" 293 (unaliased) provider configuration along with zero or more alternative 294 (aliased) provider configurations. 295 296 The `required_providers` block now has a new field for providers to indicate 297 aliased configuration names, replacing the need for an empty "proxy 298 configuration block" as a placeholder. In order to declare 299 [configuration aliases](/docs/language/modules/develop/providers.html#provider-aliases-within-modules), 300 add the desired names to the `configuration_aliases` argument for the provider 301 requirements. 302 303 ```hcl 304 terraform { 305 required_providers { 306 aws = { 307 source = "hashicorp/aws" 308 version = ">= 2.7.0" 309 configuration_aliases = [ aws.alternate ] 310 } 311 } 312 } 313 ``` 314 315 Warnings will be emitted now where empty configuration blocks are present but 316 no longer required, though they continue to work unchanged in the 0.15 release. 317 There are a few cases where existing configurations may return new errors: 318 319 * The `providers` map in a module call cannot override a provider configured 320 within the module. This is not a supported configuration, but was previously 321 missed in validation and now returns an error. 322 323 * A provider alias within a module that has no configuration _requires_ a 324 provider configuration be supplied in the module `providers` map. 325 326 * All entries in the `providers` map in a module call must correspond to a 327 provider name within the module. Passing in a configuration to an undeclared 328 provider is now an error. 329 330 ## Commands Accepting a Configuration Directory Argument 331 332 A subset of Terraform's CLI commands have historically accepted a final 333 positional argument to specify which directory contains the root module of 334 the configuration, overriding the default behavior of expecting to find it 335 in the current working directory. 336 337 However, the design of that argument was flawed in a number of ways due to 338 it being handled at the wrong level of abstraction: it only changed where 339 Terraform looks for configuration and not any of the other files that Terraform 340 might search for, and that could therefore violate assumptions that Terraform 341 configurations might make about the locations of different files, leading 342 to confusing error messages. It was also not possible to support this usage 343 pattern across all commands due to those commands using positional arguments 344 in other ways. 345 346 To address these design flaws, Terraform v0.14 introduced a new global option 347 `-chdir` which you can use before the subcommand name, causing Terraform to 348 run the subcommand as if the given directory had been the current working 349 directory: 350 351 ```shellsession 352 $ terraform -chdir=example init 353 ``` 354 355 This command causes the Terraform process to actually change its current 356 working directory to the given directory before launching the subcommand, and 357 so now any relative paths accessed by the subcommand will be treated as 358 relative to that directory, including (but not limited to) the following key 359 directory conventions: 360 361 * As with the positional arguments that `-chdir` replaces, Terraform will look 362 for the root module's `.tf` and `.tf.json` files in the given directory. 363 364 * The `.tfvars` and `.tfvars.json` files that Terraform automatically searches 365 for, and any relative paths given in `-var-file` options, will be searched 366 in the given directory. 367 368 * The `.terraform` directory which Terraform creates to retain the working 369 directory internal state will appear in the given directory, rather than 370 the current working directory. 371 372 After treating the v0.14 releases as a migration period for this new behavior, 373 Terraform CLI v0.15 no longer accepts configuration directories on any 374 command except `terraform fmt`. (`terraform fmt` is special compared to the 375 others because it primarily deals with configuration files in isolation, 376 rather than modules or configurations as a whole.) 377 378 If you built automation which previously relied on overriding the configuration 379 directory alone, you will need to transition to using the `-chdir` command line 380 option before upgrading to Terraform v0.15. 381 382 Since the `-chdir` argument behavior is more comprehensive than the positional 383 arguments it has replaced, you may need to make some further changes in the 384 event that your automation was relying on the limitations of the old mechanism: 385 386 * If your system depends on the `.terraform` directory being created in the 387 _real_ current working directory while using a root module defined elsewhere, 388 you can use the `TF_DATA_DIR` environment variable to specify the absolute 389 path where Terraform should store its working directory internal state: 390 391 ```bash 392 TF_DATA_DIR="$PWD/.terraform" 393 ``` 394 395 * If your system uses `.tfvars` or `.tfvars.json` files either implicitly found 396 or explicitly selected in the current working directory, you must either 397 move those variables files into the root module directory or specify your 398 files from elsewhere explicitly using the `-var-file` command line option: 399 400 ```bash 401 terraform plan -var-file="$PWD/example.tfvars" 402 ``` 403 404 As a special case for backward compatibility, Terraform ensures that the 405 language expression `path.cwd` will return the _original_ working directory, 406 before overriding with `-chdir`, so that existing configurations referring to 407 files in that directory can still work. If you want to refer to files in the 408 directory given in `-chdir` then you can use `path.root`, which returns the 409 directory containing the configuration's root module. 410 411 ## Microsoft Windows Terminal Support 412 413 Until the first Windows 10 update, Microsoft Windows had a console window 414 implementation with an API incompatible with the virtual terminal approach 415 taken on all other platforms that Terraform supports. 416 417 Previous versions of Terraform accommodated this by using an API translation 418 layer which could convert a subset of typical virtual terminal sequences into 419 corresponding Windows Console API function calls, but as a result this has 420 prevented Terraform from using more complex terminal features such as progress 421 indicators that update in place, menu prompts, etc. 422 423 Over the course of several updates to Windows 10, Microsoft has introduced 424 virtual terminal support similar to other platforms and 425 [now recommends the virtual terminal approach for console application developers](https://docs.microsoft.com/en-us/windows/console/classic-vs-vt). 426 In response to that recommendation, Terraform v0.15 no longer includes the 427 terminal API translation layer and consequently it will, by default, produce 428 incorrectly-formatted output on Windows 8 and earlier, and on non-updated 429 original retail Windows 10 systems. 430 431 If you need to keep using Terraform on an older version of Windows, there are 432 two possible workarounds available in the v0.15.0 release: 433 434 * Run Terraform commands using the `-no-color` command line option to disable 435 the terminal formatting sequences. 436 437 This will cause the output to be unformatted plain text, but as a result 438 will avoid the output being interspersed with uninterpreted terminal 439 control sequences. 440 441 * Alternatively, you can use Terraform v0.15.0 in various third-party 442 virtual terminal implementations for older Windows versions, including 443 [ConEmu](https://conemu.github.io/), [Cmder](https://cmder.net/), 444 and [mintty](https://mintty.github.io/). 445 446 Although we have no immediate plans to actively block running Terraform on 447 older versions of Windows, we will not be able to test future versions of 448 Terraform on those older versions and so later releases may contain 449 unintended regressions. We recommend planning an upgrade to a modern Windows 450 release on any system where you expect to continue using Terraform CLI. 451 452 ## Other Minor Command Line Behavior Changes 453 454 Finally, Terraform v0.15 includes a small number of minor changes to the 455 details of some commands and command line arguments, as part of a general 456 cleanup of obsolete features and improved consistency: 457 458 * Interrupting Terraform commands with your operating system's interrupt 459 signal (`SIGINT` on Unix systems) will now cause Terraform to exit with 460 a non-successful exit code. Previously it would, in some cases, exit with 461 a success code. 462 463 This signal is typically sent to Terraform when you press 464 Ctrl+C or similar interrupt keyboard shortcuts in an interactive terminal, 465 but might also be used by automation in order to gracefully cancel a 466 long-running Terraform operation. 467 468 * The `-lock` and `-lock-timeout` options are no longer available for the 469 `terraform init` command. Locking applies to operations that can potentially 470 change remote objects, to help ensure that two concurrent Terraform processes 471 don't try to run conflicting operations, but `terraform init` does not 472 interact with any providers in order to possibly effect such changes. 473 474 These options didn't do anything in the `terraform init` command before, 475 and so you can remove them from any automated calls with no change 476 in behavior. 477 478 * The `-verify-plugins` and `-get-plugins` options to `terraform init` are 479 no longer available. These have been non-functional since Terraform v0.13, 480 with the introduction of the new Terraform Registry-based provider installer, 481 because in practice there are very few operations Terraform can perform which 482 both require a `terraform init` but can also run without valid provider 483 plugins installed. 484 485 If you were using these options in automated calls to `terraform init`, 486 remove them from the command line for compatibility with Terraform v0.15. 487 There is no longer an option to initialize without installing the 488 required provider plugins. 489 490 * The `terraform destroy` command no longer accepts the option `-force`. This 491 was a previous name for the option in earlier Terraform versions, but we've 492 since adopted `-auto-approve` for consistency with the `terraform apply` 493 command. 494 495 If you are using `-force` in an automated call to `terraform destroy`, 496 change to using `-auto-approve` instead. 497 498 ## Azure Backend Removed Arguments 499 500 In an earlier release the `azure` backend changed to remove the `arm_` prefix 501 from a number of the configuration arguments: 502 503 | Old Name | New Name | 504 |-----------------------|-------------------| 505 | `arm_client_id` | `client_id` | 506 | `arm_client_secret` | `client_secret` | 507 | `arm_subscription_id` | `subscription_id` | 508 | `arm_tenant_id` | `tenant_id` | 509 510 The old names were previously deprecated, but we've removed them altogether 511 in Terraform v0.15 in order to conclude that deprecation cycle. 512 513 If you have a backend configuration using the old names then you may see 514 errors like the following when upgrading to Terraform v0.15: 515 516 ``` 517 ╷ 518 │ Error: Invalid backend configuration argument 519 │ 520 │ The backend configuration argument "arm_client_id" given on 521 │ the command line is not expected for the selected backend type. 522 ╵ 523 ``` 524 525 If you see errors like this, rename the arguments in your backend configuration 526 as shown in the table above and then run the following to re-initialize your 527 backend configuration: 528 529 ``` 530 terraform init -reconfigure 531 ``` 532 533 The `-reconfigure` argument instructs Terraform to just replace the old 534 configuration with the new configuration directly, rather than offering to 535 migrate the latest state snapshots from the old to the new configuration. 536 Migration would not be appropriate in this case because the old and new 537 configurations are equivalent and refer to the same remote objects.