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