github.com/hs0210/hashicorp-terraform@v0.11.12-beta1/website/upgrade-guides/0-11.html.markdown (about)

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