github.com/hugorut/terraform@v1.1.3/website/docs/language/upgrade-guides/0-11.mdx (about)

     1  ---
     2  page_title: Upgrading to Terraform 0.11
     3  description: Upgrading to Terraform v0.11
     4  ---
     5  
     6  # Upgrading to Terraform v0.11
     7  
     8  Terraform v0.11 is a major release and thus includes some changes that
     9  you'll need to consider when upgrading. This guide is intended to help with
    10  that process.
    11  
    12  The goal of this guide is to cover the most common upgrade concerns and
    13  issues that would benefit from more explanation and background. The exhaustive
    14  list of changes will always be the
    15  [Terraform Changelog](https://github.com/hugorut/terraform/blob/main/CHANGELOG.md).
    16  After reviewing this guide, we recommend reviewing the Changelog to check on
    17  specific notes about the resources and providers you use.
    18  
    19  This guide focuses on changes from v0.10 to v0.11. Each previous major release
    20  has its own upgrade guide, so please consult the other guides (available
    21  in the navigation) if you are upgrading directly from an earlier version.
    22  
    23  ## Interactive Approval in `terraform apply`
    24  
    25  Terraform 0.10 introduced a new mode for `terraform apply` (when run without
    26  an explicit plan file) where it would show a plan and prompt for approval
    27  before proceeding, similar to `terraform destroy`.
    28  
    29  Terraform 0.11 adopts this as the default behavior for this command, which
    30  means that for interactive use in a terminal it is not necessary to separately
    31  run `terraform plan -out=...` to safely review and apply a plan.
    32  
    33  The new behavior also has the additional advantage that, when using a backend
    34  that supports locking, the state lock will be held throughout the refresh,
    35  plan, confirmation and apply steps, ensuring that a concurrent execution
    36  of `terraform apply` will not invalidate the execution plan.
    37  
    38  A consequence of this change is that `terraform apply` is now interactive by
    39  default unless a plan file is provided on the command line. When
    40  [running Terraform in automation](https://learn.hashicorp.com/tutorials/terraform/automate-terraform?in=terraform/automation&utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS)
    41  it is always recommended to separate plan from apply, but if existing automation
    42  was running `terraform apply` with no arguments it may now be necessary to
    43  update it to either generate an explicit plan using `terraform plan -out=...`
    44  or to run `terraform apply -auto-approve` to bypass the interactive confirmation
    45  step. The latter should be done only in unimportant environments.
    46  
    47  **Action:** For interactive use in a terminal, prefer to use `terraform apply`
    48  with out an explicit plan argument rather than `terraform plan -out=tfplan`
    49  followed by `terraform apply tfplan`.
    50  
    51  **Action:** Update any automation scripts that run Terraform non-interactively
    52  so that they either use separated plan and apply or override the confirmation
    53  behavior using the `-auto-approve` option.
    54  
    55  ## Relative Paths in Module `source`
    56  
    57  Terraform 0.11 introduces full support for module installation from
    58  [Terraform Registry](https://registry.terraform.io/) as well as other
    59  private, in-house registries using concise module source strings like
    60  `hashicorp/consul/aws`.
    61  
    62  As a consequence, module source strings like `"child"` are no longer
    63  interpreted as relative paths. Instead, relative paths must be expressed
    64  explicitly by beginning the string with either `./` (for a module in a child
    65  directory) or `../` (for a module in the parent directory).
    66  
    67  **Action:** Update existing module `source` values containing relative paths
    68  to start with either `./` or `../` to prevent misinterpretation of the source
    69  as a Terraform Registry module.
    70  
    71  ## Interactions Between Providers and Modules
    72  
    73  Prior to Terraform 0.11 there were several limitations in deficiencies in
    74  how providers interact with child modules, such as:
    75  
    76  * Ancestor module provider configurations always overrode the associated
    77    settings in descendent modules.
    78  
    79  * There was no well-defined mechanism for passing "aliased" providers from
    80    an ancestor module to a descendent, where the descendent needs access to
    81    multiple provider instances.
    82  
    83  Terraform 0.11 changes some of the details of how each resource block is
    84  associated with a provider configuration, which may change how Terraform
    85  interprets existing configurations. This is notably true in the following
    86  situations:
    87  
    88  * If the same provider is configured in both an ancestor and a descendent
    89    module, the ancestor configuration no longer overrides attributes from
    90    the descendent and the descendent no longer inherits attributes from
    91    its ancestor. Instead, each configuration is entirely distinct.
    92  
    93  * If a `provider` block is present in a child module, it must either contain a
    94    complete configuration for its associated provider or a configuration must be
    95    passed from the parent module using
    96    [the new `providers` attribute](/language/configuration-0-11/modules#providers-within-modules).
    97    In the latter case, an empty provider block is a placeholder that declares
    98    that the child module requires a configuration to be passed from its parent.
    99  
   100  * When a module containing its own `provider` blocks is removed from its
   101    parent module, Terraform will no longer attempt to associate it with
   102    another provider of the same name in a parent module, since that would
   103    often cause undesirable effects such as attempting to refresh resources
   104    in the wrong region. Instead, the resources in the module resources must be
   105    explicitly destroyed _before_ removing the module, so that the provider
   106    configuration is still available: `terraform destroy -target=module.example`.
   107  
   108  The recommended design pattern moving forward is to place all explicit
   109  `provider` blocks in the root module of the configuration, and to pass
   110  providers explicitly to child modules so that the associations are obvious
   111  from configuration:
   112  
   113  ```hcl
   114  provider "aws" {
   115    region = "us-east-1"
   116    alias  = "use1"
   117  }
   118  
   119  provider "aws" {
   120    region = "us-west-1"
   121    alias  = "usw1"
   122  }
   123  
   124  module "example-use1" {
   125    source = "./example"
   126  
   127    providers = {
   128      "aws" = "aws.use1"
   129    }
   130  }
   131  
   132  module "example-usw1" {
   133    source = "./example"
   134  
   135    providers = {
   136      "aws" = "aws.usw1"
   137    }
   138  }
   139  ```
   140  
   141  With the above configuration, any `aws` provider resources in the module
   142  `./example` will use the us-east-1 provider configuration for
   143  `module.example-use1` and the us-west-1 provider configuration for
   144  `module.example-usw1`.
   145  
   146  When a default (non-aliased) provider is used, and not explicitly
   147  declared in a child module, automatic inheritance of that provider is still
   148  supported.
   149  
   150  **Action**: In existing configurations where both a descendent module and
   151  one of its ancestor modules both configure the same provider, copy any
   152  settings from the ancestor into the descendent because provider configurations
   153  now inherit only as a whole, rather than on a per-argument basis.
   154  
   155  **Action**: In existing configurations where a descendent module inherits
   156  _aliased_ providers from an ancestor module, use
   157  [the new `providers` attribute](/language/configuration-0-11/modules#providers-within-modules)
   158  to explicitly pass those aliased providers.
   159  
   160  **Action**: Consider refactoring existing configurations so that all provider
   161  configurations are set in the root module and passed explicitly to child
   162  modules, as described in the following section.
   163  
   164  ### Moving Provider Configurations to the Root Module
   165  
   166  With the new provider inheritance model, it is strongly recommended to refactor
   167  any configuration where child modules define their own `provider` blocks so
   168  that all explicit configuration is defined in the _root_ module. This approach
   169  will ensure that removing a module from the configuration will not cause
   170  any provider configurations to be removed along with it, and thus ensure that
   171  all of the module's resources can be successfully refreshed and destroyed.
   172  
   173  A common configuration is where two child modules have different configurations
   174  for the same provider, like this:
   175  
   176  ```hcl
   177  # root.tf
   178  
   179  module "network-use1" {
   180    source = "./network"
   181    region = "us-east-1"
   182  }
   183  
   184  module "network-usw2" {
   185    source = "./network"
   186    region = "us-west-2"
   187  }
   188  ```
   189  
   190  ```hcl
   191  # network/network.tf
   192  
   193  variable "region" {
   194  }
   195  
   196  provider "aws" {
   197    region = "${var.region}"
   198  }
   199  
   200  resource "aws_vpc" "example" {
   201    # ...
   202  }
   203  ```
   204  
   205  The above example is problematic because removing either `module.network-use1`
   206  or `module.network-usw2` from the root module will make the corresponding
   207  provider configuration no longer available, as described in
   208  [issue #15762](https://github.com/hugorut/terraform/issues/15762), which
   209  prevents Terraform from refreshing or destroying that module's `aws_vpc.example`
   210  resource.
   211  
   212  This can be addressed by moving the `provider` blocks into the root module
   213  as _additional configurations_, and then passing them down to the child
   214  modules as _default configurations_ via the explicit `providers` map:
   215  
   216  ```hcl
   217  # root.tf
   218  
   219  provider "aws" {
   220    region = "us-east-1"
   221    alias  = "use1"
   222  }
   223  
   224  provider "aws" {
   225    region = "us-west-2"
   226    alias  = "usw2"
   227  }
   228  
   229  module "network-use1" {
   230    source = "./network"
   231  
   232    providers = {
   233      "aws" = "aws.use1"
   234    }
   235  }
   236  
   237  module "network-usw2" {
   238    source = "./network"
   239  
   240    providers = {
   241      "aws" = "aws.usw2"
   242    }
   243  }
   244  ```
   245  
   246  ```hcl
   247  # network/network.tf
   248  
   249  # Empty provider block signals that we expect a default (unaliased) "aws"
   250  # provider to be passed in from the caller.
   251  provider "aws" {
   252  }
   253  
   254  resource "aws_vpc" "example" {
   255    # ...
   256  }
   257  ```
   258  
   259  After the above refactoring, run `terraform apply` to re-synchoronize
   260  Terraform's record (in [the Terraform state](/language/state)) of the
   261  location of each resource's provider configuration. This should make no changes
   262  to actual infrastructure, since no resource configurations were changed.
   263  
   264  For more details on the explicit `providers` map, and discussion of more
   265  complex possibilities such as child modules with additional (aliased) provider
   266  configurations, see [_Providers Within Modules_](/language/configuration-0-11/modules#providers-within-modules).
   267  
   268  ## Error Checking for Output Values
   269  
   270  Prior to Terraform 0.11, if an error occurred when evaluating the `value`
   271  expression within an `output` block then it would be silently ignored and
   272  the empty string used as the result. This was inconvenient because it made it
   273  very hard to debug errors within output expressions.
   274  
   275  To give better feedback, Terraform now halts and displays an error message
   276  when such errors occur, similar to the behavior for expressions elsewhere
   277  in the configuration.
   278  
   279  Unfortunately, this means that existing configurations may have erroneous
   280  outputs lurking that will become fatal errors after upgrading to Terraform 0.11.
   281  The prior behavior is no longer available; to apply such a configuration with
   282  Terraform 0.11 will require adjusting the configuration to avoid the error.
   283  
   284  **Action:** If any existing output value expressions contain errors, change these
   285  expressions to fix the error.
   286  
   287  ### Referencing Attributes from Resources with `count = 0`
   288  
   289  A common pattern for conditional resources is to conditionally set count
   290  to either `0` or `1` depending on the result of a boolean expression:
   291  
   292  ```hcl
   293  resource "aws_instance" "example" {
   294    count = "${var.create_instance ? 1 : 0}"
   295  
   296    # ...
   297  }
   298  ```
   299  
   300  When using this pattern, it's required to use a special idiom to access
   301  attributes of this resource to account for the case where no resource is
   302  created at all:
   303  
   304  ```hcl
   305  output "instance_id" {
   306    value = "${element(concat(aws_instance.example.*.id, list("")), 0)}"
   307  }
   308  ```
   309  
   310  Accessing `aws_instance.example.id` directly is an error when `count = 0`.
   311  This is true for all situations where interpolation expressions are allowed,
   312  but previously _appeared_ to work for outputs due to the suppression of the
   313  error. Existing outputs that access non-existent resources must be updated to
   314  use the idiom above after upgrading to 0.11.0.