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.