github.com/hooklift/terraform@v0.11.0-beta1.0.20171117000744-6786c1361ffe/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  * Only unaliased provider configurations can be automatically inherited from
    97    ancestor modules. Aliased providers must be passed explicitly using
    98    [the new `providers` attribute](/docs/modules/usage.html#providers-within-modules).
    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 only default (non-aliased) providers are in use, automatic inheritance
   147  to child modules is still supported.
   148  
   149  **Action**: In existing configurations where both a descendent module and
   150  one of its ancestor modules both configure the same provider, copy any
   151  settings from the ancestor into the descendent because provider configurations
   152  now inherit only as a whole, rather than on a per-argument basis.
   153  
   154  **Action**: In existing configurations where a descendent module inherits
   155  _aliased_ providers from an ancestor module, use
   156  [the new `providers` attribute](/docs/modules/usage.html#providers-within-modules)
   157  to explicitly pass those aliased providers.
   158  
   159  **Action**: Consider refactoring existing configurations so that all provider
   160  configurations are set in the root module and passed explicitly to child
   161  modules, as described in the following section.
   162  
   163  ### Moving Provider Configurations to the Root Module
   164  
   165  With the new provider inheritance model, it is strongly recommended to refactor
   166  any configuration where child modules define their own `provider` blocks so
   167  that all explicit configuration is defined in the _root_ module. This approach
   168  will ensure that removing a module from the configuration will not cause
   169  any provider configurations to be removed along with it, and thus ensure that
   170  all of the module's resources can be successfully refreshed and destroyed.
   171  
   172  A common configuration is where two child modules have different configurations
   173  for the same provider, like this:
   174  
   175  ```hcl
   176  # root.tf
   177  
   178  module "network-use1" {
   179    source = "./network"
   180    region = "us-east-1"
   181  }
   182  
   183  module "network-usw2" {
   184    source = "./network"
   185    region = "us-west-2"
   186  }
   187  ```
   188  
   189  ```hcl
   190  # network/network.tf
   191  
   192  variable "region" {
   193  }
   194  
   195  provider "aws" {
   196    region = "${var.region}"
   197  }
   198  
   199  resource "aws_vpc" "example" {
   200    # ...
   201  }
   202  ```
   203  
   204  The above example is problematic because removing either `module.network-use1`
   205  or `module.network-usw2` from the root module will make the corresponding
   206  provider configuration no longer available, as described in
   207  [issue #15762](https://github.com/hashicorp/terraform/issues/15762), which
   208  prevents Terraform from refreshing or destroying that module's `aws_vpc.example`
   209  resource.
   210  
   211  This can be addressed by moving the `provider` blocks into the root module
   212  as _additional configurations_, and then passing them down to the child
   213  modules as _default configurations_ via the explicit `providers` map:
   214  
   215  ```hcl
   216  # root.tf
   217  
   218  provider "aws" {
   219    region = "us-east-1"
   220    alias  = "use1"
   221  }
   222  
   223  provider "aws" {
   224    region = "us-west-2"
   225    alias  = "usw2"
   226  }
   227  
   228  module "network-use1" {
   229    source = "./network"
   230  
   231    providers = {
   232      "aws" = "aws.use1"
   233    }
   234  }
   235  
   236  module "network-usw2" {
   237    source = "./network"
   238  
   239    providers = {
   240      "aws" = "aws.usw2"
   241    }
   242  }
   243  ```
   244  
   245  ```hcl
   246  # network/network.tf
   247  
   248  # Empty provider block signals that we expect a default (unaliased) "aws"
   249  # provider to be passed in from the caller.
   250  provider "aws" {
   251  }
   252  
   253  resource "aws_vpc" "example" {
   254    # ...
   255  }
   256  ```
   257  
   258  After the above refactoring, run `terraform apply` to re-synchoronize
   259  Terraform's record (in [the Terraform state](/docs/state/index.html)) of the
   260  location of each resource's provider configuration. This should make no changes
   261  to actual infrastructure, since no resource configurations were changed.
   262  
   263  For more details on the explicit `providers` map, and discussion of more
   264  complex possibilities such as child modules with additional (aliased) provider
   265  configurations, see [_Providers Within Modules_](/docs/modules/usage.html#providers-within-modules).
   266  
   267  ## Error Checking for Output Values
   268  
   269  Prior to Terraform 0.11, if an error occured when evaluating the `value`
   270  expression within an `output` block then it would be silently ignored and
   271  the empty string used as the result. This was inconvenient because it made it
   272  very hard to debug errors within output expressions.
   273  
   274  To give better feedback, Terraform now halts and displays an error message
   275  when such errors occur, similar to the behavior for expressions elsewhere
   276  in the configuration.
   277  
   278  Unfortunately, this means that existing configurations may have erroneous
   279  outputs lurking that will become fatal errors after upgrading to Terraform 0.11.
   280  The prior behavior is no longer available; to apply such a configuration with
   281  Terraform 0.11 will require adjusting the configuration to avoid the error.
   282  
   283  **Action:** If any existing output value expressions contain errors, change these
   284  expressions to fix the error.
   285  
   286  ### Referencing Attributes from Resources with `count = 0`
   287  
   288  A common pattern for conditional resources is to conditionally set count
   289  to either `0` or `1` depending on the result of a boolean expression:
   290  
   291  ```hcl
   292  resource "aws_instance" "example" {
   293    count = "${var.create_instance ? 1 : 0}"
   294  
   295    # ...
   296  }
   297  ```
   298  
   299  When using this pattern, it's required to use a special idiom to access
   300  attributes of this resource to account for the case where no resource is
   301  created at all:
   302  
   303  ```hcl
   304  output "instance_id" {
   305    value = "${element(concat(aws_instance.example.*.id, list("")), 0)}"
   306  }
   307  ```
   308  
   309  Accessing `aws_instance.example.id` directly is an error when `count = 0`.
   310  This is true for all situations where interpolation expressions are allowed,
   311  but previously _appeared_ to work for outputs due to the suppression of the
   312  error. Existing outputs that access non-existent resources must be updated to
   313  use the idiom above after upgrading to 0.11.0.