github.com/kcburge/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.