github.com/iaas-resource-provision/iaas-rpc@v1.0.7-0.20211021023331-ed21f798c408/website/upgrade-guides/0-12.html.markdown (about)

     1  ---
     2  layout: "language"
     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/cli/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/language/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/language/expressions/type-constraints.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/language/expressions/type-constraints.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).