github.com/hugorut/terraform@v1.1.3/website/docs/language/upgrade-guides/0-12.mdx (about) 1 --- 2 page_title: Upgrading to Terraform 0.12 3 description: Upgrading to Terraform v0.12 4 --- 5 6 # Upgrading to Terraform v0.12 7 8 [Terraform v0.12 is a major release](https://hashicorp.com/blog/terraform-0-1-2-preview) 9 focused on configuration language improvements and thus includes some 10 changes that you'll need to consider when upgrading. The goal of this guide is 11 to cover the most common upgrade concerns and issues. 12 13 For most users, upgrading configuration should be completely automatic. Some 14 simple configurations will require no changes at all, and most other 15 configurations can be prepared by running 16 [the automatic upgrade tool](/cli/commands/0.12upgrade). Please read on 17 for more information and recommendations on the upgrade process. 18 19 -> If you are a developer maintaining a provider plugin, please see 20 [the documentation on 0.12 compatibility for providers](/plugin/sdkv2/guides/terraform-0.12-compatibility) 21 to learn more about the changes that are required. 22 23 ## Upgrade to Terraform 0.11 first 24 25 We strongly recommend completing an upgrade to the latest Terraform v0.11 26 release first. This will give you an opportunity to address any changes 27 required for the previous major version upgrades separately, rather than 28 making multiple changes at once. 29 30 In particular, if you are upgrading from a Terraform version prior to v0.9, 31 you _must_ first [upgrade to Terraform v0.9](/language/upgrade-guides/0-9) and 32 switch to initializing with `terraform init`, because v0.12 no longer includes 33 the functionality for automatically migrating from the legacy remote state 34 mechanism. 35 36 This guide focuses on changes from v0.11 to v0.12. Each previous major release 37 has its own upgrade guide, so please consult the other guides (available in the 38 navigation) to upgrade step-by-step to v0.11 first. 39 40 Terraform v0.11.14 (and any subsequent v0.11 releases) also include some 41 additional functionality to help smooth the upgrade, which we will use later 42 in this guide. 43 44 Prior versions of Terraform are available from 45 [the releases server](https://releases.hashicorp.com/terraform/). 46 47 ## Pre-upgrade Checklist 48 49 Terraform v0.11.14 introduced a temporary helper command 50 `terraform 0.12checklist`, which analyzes your configuration to detect any 51 required steps that will be easier to perform before upgrading. 52 53 To use it, first upgrade to [Terraform v0.11.14](https://releases.hashicorp.com/terraform/0.11.14/). 54 Then, perform the following steps: 55 56 * `terraform init` to ensure your working directory is fully initialized and 57 all required plugins are installed and selected. 58 * `terraform apply` to ensure that your real infrastructure and Terraform 59 state are consistent with the current configuration. The instructions 60 produced by the checklist command assume that configuration and state are 61 synchronized. 62 * `terraform 0.12checklist` to see if there are any pre-upgrade steps in the 63 checklist. 64 65 If all is well, the final command will produce a message like this: 66 67 ``` 68 Looks good! We did not detect any problems that ought to be 69 addressed before upgrading to Terraform v0.12 70 71 This tool is not perfect though, so please check the v0.12 upgrade 72 guide for additional guidance, and for next steps: 73 https://www.terraform.io/upgrade-guides/0-12.html 74 ``` 75 76 As the message suggests, the next step in that case is to read the remainder 77 of this page to prepare for and carry out the upgrade. 78 79 However, the checklist command may instead produce a list of one or more tasks 80 that we recommend you perform before upgrading to Terraform 0.12, because they 81 are easier to perform with a fully-functional Terraform 0.11 than with a 82 Terraform 0.12 that has encountered compatibility problems. 83 84 The tasks it may suggest you perform could include: 85 86 * Upgrading any provider versions that are not compatible with Terraform v0.12. 87 We recommend upgrading to the latest version of each provider before upgrading 88 because that will avoid changing many things in one step. 89 * Renaming any resources or provider aliases that have names that start with 90 digits, because that is no longer valid in Terraform 0.12. 91 * Upgrading any external modules the configuration uses which themselves have 92 the above problems. 93 94 In each case, the tool will give some direction on how to perform the task it 95 is suggesting. 96 97 The output from `terraform 0.12checklist` is in Markdown format so that it can 98 easily be pasted into a Markdown-compatible issue tracker, should you want 99 to track the necessary tasks or share the work with other team members. 100 101 After all of the tasks are complete, run `terraform 0.12checklist` one more time 102 to verify that everything is complete. If so, continue reading the following 103 sections to complete the upgrade! 104 105 ### Addendum: Invalid module names 106 107 There is one additional pre-upgrade checklist item that the Terraform team did 108 not become aware of until after the release of Terraform v0.11.14, and thus 109 cannot be detected automatically by the checklist tool: renaming modules which 110 have names that start with digits. 111 112 Terraform 0.11 inadvertently tolerated leading-digit names for modules as a 113 result of a validation bug, but Terraform 0.12 has corrected that bug and will 114 reject such module names. Unfortunately, module names are also recorded in 115 state snapshots and so a state snapshot created for a configuration with an 116 invalid module name will itself be invalid as far as Terraform 0.12 is 117 concerned. 118 119 You can address this in a similar way to what the checklist tool suggests for 120 invalid resource names and provider aliases: 121 122 * Rename the module in your configuration. 123 * Use `terraform state mv module.old module.new` _in Terraform 0.11.14_ to 124 update the state to use the new name instead of the old name. 125 126 As with all of the pre-upgrade checklist items, be sure to run `terraform apply` 127 once more before upgrading in order to ensure that the latest state snapshot is 128 synchronized with the latest configuration. 129 130 ## Upgrading to Terraform 0.12 131 132 Before switching to Terraform 0.12, we recommend using Terraform v0.11.14 (or 133 any later v0.11 release) to perform one last `terraform init` and 134 `terraform apply` to ensure that everything is initialized and synchronized. 135 136 Once `terraform apply` shows no changes pending, switch over to a Terraform 137 v0.12 release and run `terraform init` again to upgrade the working directory 138 metadata to v0.12 format. (Once you've done this, you'll need to delete the 139 `.terraform` directory if you wish to return to Terraform v0.11, but no 140 real infrastructure or persisted state will be upgraded yet.) 141 142 It is possible that your configuration may be using configuration constructs 143 that are not Terraform v0.12 compatible and thus require upgrade. In that case, 144 `terraform init` will produce the following message: 145 146 ``` 147 Terraform has initialized, but configuration upgrades may be needed. 148 149 Terraform found syntax errors in the configuration that prevented full 150 initialization. If you've recently upgraded to Terraform v0.12, this may be 151 because your configuration uses syntax constructs that are no longer valid, 152 and so must be updated before full initialization is possible. 153 154 Terraform has installed the required providers to support the configuration 155 upgrade process. To begin upgrading your configuration, run the following: 156 terraform 0.12upgrade 157 158 To see the full set of errors that led to this message, run: 159 terraform validate 160 ``` 161 162 As mentioned in the message, Terraform has partially initialized the directory 163 just enough to perform the configuration upgrade process, which is described 164 in the following section. 165 166 We recommend running the configuration upgrade tool even if you do not see 167 the above message, because it may detect and fix constructs that are 168 syntactically correct but still need some changes to work as expected with 169 Terraform v0.12. 170 171 ## Upgrading Terraform configuration 172 173 Terraform v0.12 includes a new command `terraform 0.12upgrade` that will 174 read the configuration files for a module written for Terraform 0.11 and 175 update them in-place to use the cleaner Terraform 0.12 syntax and also 176 adjust for use of features that have changed behavior in the 0.12 Terraform 177 language. 178 179 Simple configuration files are likely to be understood by Terraform 0.12 as-is, 180 because the language is still broadly compatible, but we recommend that everyone 181 run the upgrade tool nonetheless. Even if your configuration is already 182 compatible, the tool will update your configuration to use the cleaner syntax 183 available in Terraform 0.12, which should improve readability. 184 185 To run the command, first make sure that your local working directory is synced 186 with your version control system so that there are no changes outstanding. This 187 will make it easier to review the changes that the upgrade tool is proposing, 188 using the diff feature of your version control system. 189 190 With a fully-initialized working directory (all necessary providers and child 191 modules installed), run `terraform 0.12upgrade` to begin the process. By default 192 it will print some information about what it is about to do and prompt for 193 confirmation: 194 195 ``` 196 This command will rewrite the configuration files in the given directory so 197 that they use the new syntax features from Terraform v0.12, and will identify 198 any constructs that may need to be adjusted for correct operation with 199 Terraform v0.12. 200 201 We recommend using this command in a clean version control work tree, so that 202 you can easily see the proposed changes as a diff against the latest commit. 203 If you have uncommitted changes already present, we recommend aborting this 204 command and dealing with them before running this command again. 205 206 Would you like to upgrade the module in the current directory? 207 ``` 208 209 If you answer yes, the `.tf` and `.tfvars` files in your current working 210 directory will be rewritten in-place. 211 212 The upgrade tool may also print out warnings about constructs it wasn't able to 213 migrate fully automatically; in that case, it will also emit comments into the 214 rewritten source files containing the special marker `TF-UPGRADE-TODO`, as 215 a prompt for a decision you'll need to make to complete the upgrade. 216 217 Once the upgrade tool has successfully completed and you've resolved any 218 `TF-UPGRADE-TODO` prompts, use your version control tool to review the proposed 219 changes and then run `terraform plan` to see the effect of those changes. 220 221 In most cases, `terraform plan` should report that no changes are required, 222 because the updated configuration is equivalent to before. 223 224 The remaining sections below describe both some common changes that the upgrade 225 tool is able to make automatically, and some other upgrade situations that 226 the configuration tool may not be able to fully resolve. If you encounter 227 any errors during the upgrade or during the subsequent `terraform plan`, the 228 sections below may give some additional context for how to proceed. 229 230 Once you're happy with the updated configuration, commit it to version control 231 in the usual way and apply it with Terraform 0.12. 232 233 ### Remote state references 234 235 The `terraform_remote_state` data source has changed slightly for the v0.12 236 release to make all of the remote state outputs available as a single map 237 value, rather than as top-level attributes as in previous releases. 238 239 In previous releases, a reference to a `vpc_id` output exported by the remote 240 state data source might have looked like this: 241 242 ```hcl 243 data.terraform_remote_state.vpc.vpc_id 244 ``` 245 246 This value must now be accessed via the new `outputs` attribute: 247 248 ```hcl 249 data.terraform_remote_state.vpc.outputs.vpc_id 250 ``` 251 252 The upgrade tool will rewrite remote state references automatically to include 253 the additional `outputs` attribute. 254 255 Where appropriate, you can also access the outputs attribute directly to 256 work with the whole map as a single value: 257 258 ```hcl 259 data.terraform_remote_state.vpc.outputs 260 ``` 261 262 Another consideration for `terraform_remote_state` is that this data source must 263 be able to parse the latest state snapshot for a separate Terraform 264 configuration that may have been updated by a newer version of Terraform. 265 To provide flexibility when upgrading decomposed environments that use 266 `terraform_remote_state`, Terraform v0.11.14 introduced support for reading 267 outputs from the Terraform v0.12 state format, so if you upgrade all of your 268 configurations to Terraform v0.11.14 first you can then perform v0.12 upgrades 269 of individual configurations in any order, without breaking 270 `terraform_remote_state` usage. 271 272 Note that the `config` block should now be in the form of an assignment with the `=` sign: 273 274 ```hcl 275 data "terraform_remote_state" "default" { 276 backend = "gcs" 277 config = { 278 bucket = "..." 279 } 280 } 281 ``` 282 283 ### Attributes vs. blocks 284 285 Terraform resource configurations consist of both arguments that set 286 individual properties of the main object being described, and nested blocks 287 which declare zero or more other objects that are modeled as being part of 288 their parent. For example: 289 290 ```hcl 291 resource "aws_instance" "example" { 292 instance_type = "t2.micro" 293 ami = "ami-abcd1234" 294 295 tags = { 296 Name = "example instance" 297 } 298 299 ebs_block_device { 300 device_name = "sda2" 301 volume_type = "gp2" 302 volume_size = 24 303 } 304 } 305 ``` 306 307 In the above resource, `instance_type`, `ami`, and `tags` are both direct 308 arguments of the `aws_instance` resource, while `ebs_block_device` describes 309 a separate EBS block device object that is connected to the parent instance. 310 311 Due to the design of the configuration language decoder in Terraform v0.11 and 312 earlier, it was in many cases possible to interchange the argument syntax 313 (with `=`) and the block syntax (with just braces) when dealing with map 314 arguments vs. nested blocks. However, this led to some subtle bugs and 315 limitations, so Terraform v0.12 now requires consistent usage of argument 316 syntax for arguments and nested block syntax for nested blocks. 317 318 In return for this new strictness, Terraform v0.12 now allows map keys to be 319 set dynamically from expressions, which is a long-requested feature. The 320 main difference between a map attribute and a nested block is that a map 321 attribute will usually have user-defined keys, like we see in the `tags` 322 example above, while a nested block always has a fixed set of supported 323 arguments defined by the resource type schema, which Terraform will validate. 324 325 The configuration upgrade tool uses the provider's schema to recognize the 326 nature of each construct and will select the right syntax automatically. For 327 most simple usage, this will just involve adding or removing the equals sign 328 as appropriate. 329 330 A more complicated scenario is where users found that they could exploit this 331 flexibility to -- with some caveats -- dynamically generate nested blocks even 332 though this wasn't intentionally allowed: 333 334 ```hcl 335 # Example of no-longer-supported workaround from 0.11 and earlier 336 ebs_block_device = "${concat(map("device_name", "sda4"), var.extra_block_devices)}" 337 ``` 338 339 Terraform v0.12 now includes a first-class feature for dynamically generating 340 nested blocks using expressions, using the special `dynamic` block type. The 341 above can now be written like this, separating the static block device from 342 the dynamic ones: 343 344 ```hcl 345 ebs_block_device { 346 device_name = "sda4" 347 } 348 dynamic "ebs_block_device" { 349 for_each = var.extra_block_devices 350 content { 351 device_name = ebs_block_device.value.device_name 352 volume_type = ebs_block_device.value.volume_type 353 volume_size = ebs_block_device.value.volume_size 354 } 355 } 356 ``` 357 358 The configuration upgrade tool will detect use of the above workaround and 359 rewrite it as a `dynamic` block, but it may make non-ideal decisions for how to 360 flatten your expression down into static vs. dynamic blocks, so we recommend 361 reviewing the generated `dynamic` blocks to see if any simplifications are 362 possible. 363 364 Terraform v0.12 now also requires that each argument be set only once within 365 a particular block, whereas before Terraform would either take the last 366 definition or, in some cases, attempt to merge together multiple definitions 367 into a list. The upgrade tool does not remove or attempt to consolidate 368 any existing duplicate arguments, but other commands like `terraform validate` 369 will detect and report these after upgrading. 370 371 ### Integer vs. Float Number Types 372 373 From Terraform v0.12, the Terraform language no longer distinguishes between 374 integer and float types, instead just having a single "number" type that can 375 represent high-precision floating point numbers. This new type can represent 376 any value that could be represented before, plus many new values due to the 377 expanded precision. 378 379 In most cases this change should not cause any significant behavior change, but 380 please note that in particular the behavior of the division operator is now 381 different: it _always_ performs floating point division, whereas before it 382 would sometimes perform integer division by attempting to infer intent from 383 the argument types. 384 385 If you are relying on integer division behavior in your configuration, please 386 use the `floor` function to obtain the previous result. A common place this 387 would arise is in index operations, where the index is computed by division: 388 389 ```hcl 390 example = var.items[floor(count.index / var.any_number)] 391 ``` 392 393 Using a fractional number to index a list will produce an error telling you 394 that this is not allowed, serving as a prompt to add `floor`: 395 396 ``` 397 Error: Invalid index 398 399 The given key does not identify an element in this collection value: indexing a 400 sequence requires a whole number, but the given index (0.5) has a fractional 401 part. 402 ``` 403 404 Unfortunately the automatic upgrade tool cannot apply a fix for this case 405 because it does not have enough information to know if floating point or integer 406 division was intended by the configuration author, so this change must be made 407 manually where needed. 408 409 ### Referring to List Variables 410 411 In early versions of Terraform, before list support became first-class, we 412 required using seemingly-redundant list brackets around a single expression 413 in order to hint to the language interpreter that a list interpretation was 414 desired: 415 416 ```hcl 417 # Example for older versions of Terraform; not valid for v0.12 418 example = ["${var.any_list}"] 419 ``` 420 421 This strange requirement was subsequently lifted after the introduction of 422 first-class list support, but we retained compatibility with this older usage 423 for a transitional period by including some fixup logic that would detect when 424 list brackets contain list expressions and automatically flatten to a single 425 list. 426 427 As part of implementing the first-class expressions support for v0.12, we needed 428 to finally remove that backward-compatibility mechanism to avoid ambiguity 429 in the language, so an expression like the above will now produce a list of 430 lists and thus produce a type checking error for any argument that was expecting 431 a list of some other type. 432 433 The upgrade tool is able to recognize most simple usage of this pattern and 434 rewrite automatically to just refer to the list directly: 435 436 ```hcl 437 example = var.any_list 438 ``` 439 440 However, an unintended side-effect of this compatibility mechanism was to 441 also flatten mixed lists of single-value and list expressions into a single 442 list automatically. We didn't intend for this to be a part of the language, but 443 in retrospect it was an obvious consequence of how the compatibility mechanism 444 was implemented. If you have expressions in your modules that produce a list 445 of strings by using list brackets with a mixture of string and list-of-string 446 sub-expressions, you will need to rewrite this to explicitly use 447 [the `flatten` function](/language/functions/flatten) 448 to make the special treatment more obvious to the reader: 449 450 ```hcl 451 example = flatten([ 452 "single string", 453 var.any_list, 454 ]) 455 ``` 456 457 The configuration upgrade tool unfortunately cannot make this change 458 automatically, because it doesn't have enough information to know for certain 459 which interpretation was intended for a given list. 460 461 For complex examples that the upgrade tool is not able to adjust automatically, 462 subsequent Terraform operations may produce an error message like the following: 463 464 ``` 465 Error: Incorrect attribute value type 466 467 on redundant-list-brackets.tf line 9, in resource "aws_security_group" "foo": 468 9: cidr_blocks = ["${var.cidr_blocks}"] 469 470 Inappropriate value for attribute "cidr_blocks": element 0: string required. 471 ``` 472 473 This message is reporting that Terraform has understood this expression as a 474 list of lists, and therefore element zero is a list rather than a string. To 475 fix the error, remove the redundant list brackets and possibly add a 476 `flatten` function call as described above, for more complex cases. 477 478 ### Reserved Variable Names 479 480 In preparation for new features planned for future releases, Terraform 0.12 481 reserves some additional names that can no longer be used as input variable 482 names for modules. These reserved names are: 483 484 * `count` 485 * `depends_on` 486 * `for_each` 487 * `lifecycle` 488 * `providers` 489 * `source` 490 491 When any of these names is used as the label of a `variable` block, Terraform 492 will now generate the following error: 493 494 ``` 495 Error: Invalid variable name 496 497 on reserved-variable-names.tf line 2, in variable "count": 498 2: variable "count" { 499 500 The variable name "count" is reserved due to its special meaning inside module 501 blocks. 502 ``` 503 504 The upgrade tool cannot automatically adjust for these reserved names, because 505 it does not know what new name would be more appropriate. To proceed, you must 506 unfortunately rename these input variables and make a new major release of 507 the module in question, since renaming input variables is a breaking change. 508 509 ### Type Constraints on Variables 510 511 In Terraform v0.11, variables were documented as accepting only strings, lists 512 of strings, and maps of strings. However, in practice Terraform permitted 513 lists of lists and lists of maps and other nested structures in some cases, 514 even though it was then generally inconvenient to work with those values 515 elsewhere in the module due to limitations of the index syntax, `element` 516 function, and `lookup` function. 517 518 Terraform now allows various [type constraints](/language/expressions/type-constraints) 519 to be specified, as part of the language's new type system and generalized 520 functions and operators. However, because lists and maps of non-string values 521 were not officially supported in 0.11, existing configurations do not have 522 enough information for the upgrade tool to know what element type was intended. 523 It will therefore assume that lists and maps are of strings as documented, 524 which will be incorrect for configurations using more complex structures. The 525 result will be one of the following error messages: 526 527 ``` 528 Error: Invalid default value for variable 529 530 on child_module/example.tf line 4, in variable "example": 531 4: default = [ 532 5: { 533 6: "foo" = "bar" 534 7: }, 535 8: ] 536 537 This default value is not compatible with the variable's type constraint: 538 element 0: string required. 539 ``` 540 541 ``` 542 Error: Invalid value for module argument 543 544 on variables-incorrect-elem-type.tf line 4, in module "child": 545 4: example = [ 546 5: { 547 6: "foo" = "bar" 548 7: }, 549 8: ] 550 551 The given value is not suitable for child module variable "example" defined at 552 child/child.tf:1,1-19: element 0: string required. 553 ``` 554 555 To fix this, change the `type` argument from `list(string)` or `map(string)` 556 to a more appropriate [type constraint](/language/expressions/type-constraints). 557 558 If you're not sure what type constraint to use yet, another option is to 559 use the type constraint `any`, which will effectively disable validation and 560 allow any value. We recommend using specific types where possible, but selecting 561 `any` during upgrade may be preferable, so that the work to select and define 562 a more precise type can be saved for a later change at your leisure, once 563 upgrading is complete. 564 565 ### Working with `count` on resources 566 567 The `count` feature allows declaration of multiple instances of a particular 568 resource constructed from the same configuration. In Terraform v0.11, any 569 use of `count` would generally lead to referring to the resource in question 570 using the "splat expression" syntax elsewhere in the configuration: 571 572 ``` 573 aws_instance.example.*.id[0] 574 ``` 575 576 Because `aws_instance.example` itself was not directly referencable in 577 Terraform v0.11, the expression system allowed some flexibility in how such 578 expressions were resolved. For example, Terraform would treat 579 `aws_instance.example.id` as an alias for `aws_instance.example.*.id[0]`. 580 581 Terraform v0.12 allows referring to an entire resource as an object value, 582 but that required making a decision on what type of value is returned by 583 `aws_instance.example`. The new rules are as follows: 584 585 * For resources where `count` is _not_ set, a reference like 586 `aws_instance.example` returns a single object, whose attributes can be 587 accessed in the usual way, like `aws_instance.example.id`. 588 589 * For resources where `count` _is_ set -- even if the expression evaluates to 590 `1` -- `aws_instance.example` returns a list of objects whose length is 591 decided by the count. In this case `aws_instance.example.id` is an error, 592 and must instead be written as `aws_instance.example[0].id` to access 593 one of the objects before retrieving its `id` attribute value. 594 595 The splat syntax is still available and will still be useful in situations 596 where a list result is needed, but we recommend updating expressions like 597 `aws_instance.example.*.id[count.index]` to instead be 598 `aws_instance.example[count.index].id`, which should be easier to read and 599 understand for those who are familiar with other languages. 600 601 Another consequence of the new handling of `count` is that you can use the 602 `length` function directly with references to resources that have `count` set: 603 604 ``` 605 length(aws_instance.example) 606 ``` 607 608 This replaces the v0.11 special case of `aws_instance.example.count`, which 609 can no longer be supported due to `aws_instance.example` being a list. 610 611 The upgrade tool will automatically detect references that are inconsistent 612 with the `count` setting on the target resource and rewrite them to use the 613 new syntax. The upgrade tool will _not_ rewrite usage of splat syntax to 614 direct index syntax, because the old splat syntax form is still compatible. 615 616 Another `count`-related change is that Terraform now requires `count` to be 617 assigned a numeric value, and will not automatically convert a boolean value 618 to a number in the interests of clarity. If you wish to use a boolean value 619 to activate or deactivate a particular resource, use the conditional operator 620 to show clearly how the boolean value maps to a number value: 621 622 ```hcl 623 count = var.enabled ? 1 : 0 624 ``` 625 626 ### First-class expressions 627 628 Terraform v0.11 and earlier allowed expressions only within interpolation 629 sequences, like `"${var.example}"`. Because expressions are such an important 630 part of Terraform -- they are the means by which we connect the attributes of 631 one resource to the configuration of another -- Terraform v0.12 now allows 632 you to use expressions directly when defining most attributes. 633 634 ``` 635 ami = var.ami 636 ``` 637 638 The generalization of expression handling also has some other benefits. For 639 example, it's now possible to directly construct lists and maps within 640 expressions using the normal syntax, whereas in Terraform v0.11 we required 641 using the `list` and `map` functions: 642 643 ``` 644 # Old 0.11 example 645 tags = "${merge(map("Name", "example"), var.common_tags)}" 646 647 # Updated 0.12 example 648 tags = merge({ Name = "example" }, var.common_tags) 649 ``` 650 651 The automatic upgrade tool will perform rewrites like these automatically, 652 making expressions easier to read and understand. 653 654 ### Default settings in `connection` blocks 655 656 Terraform v0.11 and earlier allowed providers to pre-populate certain arguments 657 in a `connection` block for use with remote provisioners. Several resource 658 type implementations use this to pre-populate `type` as `"ssh"` and `host` 659 as one of the IP addresses of the compute instance being created. 660 661 While that feature was convenient in some cases, we found that in practice it 662 was hard for users to predict how it would behave, since each provider had its 663 own rules for whether to prefer public vs. private IP addresses, which network 664 interface to use, whether to use IPv4 or IPv6, etc. 665 666 It also violated our design principle of "explicit is better than implicit": we 667 think it's important that someone who is unfamiliar with a particular Terraform 668 configuration (or with Terraform itself) to be able to read the configuration 669 and make a good guess as to what it will achieve, and the default connection 670 settings feature left an important detail unstated: how do the provisioners 671 access the host? 672 673 With this in mind, Terraform v0.12 no longer performs any automatic population 674 of `connection` blocks. Instead, if you are using any remote provisioners you 675 should explicitly set the connection type and the hostname to connect to: 676 677 ```hcl 678 connection { 679 type = "ssh" 680 host = self.public_ip 681 # ... 682 } 683 ``` 684 685 The automatic upgrade tool will detect existing `connection` blocks that are 686 lacking these settings within resource types that are known to have previously 687 set defaults, and it will write out an expression that approximates whatever 688 selection logic the provider was previously doing in its own implementation. 689 690 Unfortunately in some cases the provider did not export the result of the 691 possibly-rather-complex host selection expression as a single attribute, and so 692 for some resource types the generated `host` expression will be quite 693 complicated. We recommend reviewing these and replacing them with a simpler 694 expression where possible, since you will often know better than Terraform does 695 which of the instance IP addresses are likely to be accessible from the host 696 where Terraform is running. 697 698 ### Equality operations must be valid on value and type 699 700 In 0.11, `"1"` would compare truthfully against `1`, however, in 0.12, 701 values must be equal on both value and type in order to be true. That is, in 0.11 702 you would see: 703 704 ``` 705 > "1" == 1 706 true 707 ``` 708 709 and in 0.12: 710 711 ``` 712 > "1" == 1 713 false 714 ``` 715 716 This means special care should be taken if you have any conditionals comparing to say, 717 `count.index` where you were previously expecting it to be a string, when it is now a number. 718 719 This is a scenario where you would need to update existing 0.11 code to work as you expect in 0.12: 720 721 ``` 722 resource "server_instance" "app" { 723 server_status = "${count.index == local.prod_index ? "production" : "standby"}" 724 } 725 } 726 727 locals { 728 # when migrating to 0.12, be sure to change this value to a number 729 # to ensure expected behavior 730 prod_index = "0" 731 } 732 ``` 733 734 Also take care that if you have a variable that is a number, but defined as a string, 735 the upgrade tool will not change it to a number, so take care to inspect your code: 736 737 ``` 738 locals { 739 some_count = "3" # will not be changed to a number after config upgrade 740 } 741 ``` 742 743 ## Upgrades for reusable modules 744 745 If you are making upgrades to a reusable module that is consumed by many 746 different configurations, you may need to take care with the timing of your 747 upgrade and of how you publish it. 748 749 We strongly recommend using module versioning, either via a Terraform registry 750 or via version control arguments in your module source addresses, to pin 751 existing references to the old version of the module and then publish the 752 upgraded version under a new version number. If you are using semantic 753 versioning, such as in a Terraform registry, the updates made by the upgrade 754 tool should be considered a breaking change and published as a new major 755 version. 756 757 The migration tool will automatically add a `>= 0.12.0` Terraform version 758 constraint to indicate that the module has been upgraded to use v0.12-only 759 features. By using version constraints, users can gradually update their callers 760 to use the newly-upgraded version as they begin to use Terraform v0.12 with 761 those modules. 762 763 For simpler modules it may be possible to carefully adapt them to be both 764 0.11 and 0.12 compatible at the same time, by following the upgrade notes in 765 earlier sections and avoiding any v0.12-only features. However, for any module 766 using a undocumented workarounds for v0.11 limitations it is unlikely to be 767 possible to both update it for Terraform v0.12 and retain v0.11 compatibility 768 at the same time, because those undocumented workarounds have been replaced 769 with new features in Terraform v0.12. 770 771 ## Map variables no longer merge when overridden 772 773 In prior versions of Terraform, a variable of type `"map"` had a special 774 behavior where any value provided via mechanisms such as the `-var` command 775 line option would be keywise-merged with any default value associated with 776 the variable. This was useful in early versions of Terraform that lacked 777 mechanisms for doing such merging explicitly, but since Terraform v0.10 778 introduced the concept of local values we consider it preferable to perform 779 such merges manually so that they are explicit in configuration: 780 781 ``` 782 variable "example_map" { 783 type = map(string) 784 default = {} 785 } 786 787 locals { 788 default_map_keys = { 789 "a" = "b" 790 } 791 merged_map_keys = merge(local.default_map_keys, var.example_map) 792 } 793 ``` 794 795 In order to improve the consistency of variable handling across types, the 796 map variable merging behavior is removed in Terraform v0.12. Because this 797 mechanism was driven by command line options rather than configuration, the 798 automatic upgrade tool cannot automatically handle it. If you are relying on 799 the merging feature, you must reorganize your configuration to use explicit 800 merging like in the above example, or else your default map value will be 801 entirely overridden by any explicitly-set value. 802 803 ## Upgrading `remote` Backend Configuration 804 805 Terraform Cloud and Terraform Enterprise users will need 806 to run `terraform init -reconfigure` to upgrade to Terraform 0.12. 807 808 Terraform provides a message stating that `terraform init` is required; while 809 there is no harm in running this command, the next error message will clarify 810 that `terraform init -reconfigure` is required. 811 812 ## Upgrading Sentinel policies 813 814 The Terraform Sentinel imports have been updated to work with Terraform 0.12. 815 Care has been taken to ensure that the API is as backwards compatible as 816 possible and most policies will continue to work without modification. However, 817 there are some important changes and certain policies will need to modified. 818 819 More information on the changes can be found in our page on [using Sentinel with 820 Terraform 0.12](/cloud-docs/sentinel/sentinel-tf-012). 821 822 It's strongly advised that you test your Sentinel policies after upgrading to 823 Terraform 0.12 to ensure they continue to work as expected. [Mock 824 generation](/cloud-docs/sentinel/mock) has also been updated to 825 produce mock data for the Sentinel imports as they appear in Terraform 0.12. 826 827 For more information on testing a policy with 0.11 and 0.12 at the same time, 828 see the section on [testing a policy with 0.11 and 0.12 829 simultaneously](/cloud-docs/sentinel/sentinel-tf-012#testing-a-policy-with-0-11-and-0-12-simultaneously).