github.com/ns1/terraform@v0.7.10-0.20161109153551-8949419bef40/website/source/upgrade-guides/0-7.html.markdown (about)

     1  ---
     2  layout: "downloads"
     3  page_title: "Upgrading to Terraform 0.7"
     4  sidebar_current: "upgrade-guides-0-7"
     5  description: |-
     6    Upgrading to Terraform v0.7
     7  ---
     8  
     9  # Upgrading to Terraform v0.7
    10  
    11  Terraform v0.7 is a major release, and thus includes some backwards incompatibilities that you'll need to consider when upgrading. This guide is meant to help with that process.
    12  
    13  The goal of this guide is to cover the most common upgrade concerns and issues that would benefit from more explanation and background. The exhaustive list of changes will always be the [Terraform Changelog](https://github.com/hashicorp/terraform/blob/master/CHANGELOG.md). After reviewing this guide, review the Changelog to check on specific notes about the resources and providers you use.
    14  
    15  ## Plugin Binaries
    16  
    17  Before v0.7, Terraform's built-in plugins for providers and provisioners were each distributed as separate binaries.
    18  
    19  ```
    20  terraform               # core binary
    21  terraform-provider-*    # provider plugins
    22  terraform-provisioner-* # provisioner plugins
    23  ```
    24  
    25  These binaries needed to all be extracted to somewhere in your `$PATH` or in the `~/.terraform.d` directory for Terraform to work.
    26  
    27  As of v0.7, all built-in plugins ship embedded in a single binary. This means that if you just extract the v0.7 archive into a path, you may still have the old separate binaries in your `$PATH`. You'll need to remove them manually.
    28  
    29  For example, if you keep Terraform binaries in `/usr/local/bin` you can clear out the old external binaries like this:
    30  
    31  ```
    32  rm /usr/local/bin/terraform-*
    33  ```
    34  
    35  External plugin binaries continue to work using the same pattern, but due to updates to the RPC protocol, they will need to be recompiled to be compatible with Terraform v0.7.x.
    36  
    37  ## Maps in Displayed Plans
    38  
    39  When displaying a plan, Terraform now distinguishes attributes of type map by using a `%` character for the "length field".
    40  
    41  Here is an example showing a diff that includes both a list and a map:
    42  
    43  ```
    44  somelist.#:  "0" => "1"
    45  somelist.0:  "" => "someitem"
    46  somemap.%:   "0" => "1"
    47  somemap.foo: "" => "bar"
    48  ```
    49  
    50  ## Interpolation Changes
    51  
    52  There are a few changes to Terraform's interpolation language that may require updates to your configs.
    53  
    54  ### String Concatenation
    55  
    56  The `concat()` interpolation function used to work for both lists and strings. It now only works for lists.
    57  
    58  ```
    59  "${concat(var.foo, "-suffix")}"     # => Error! No longer supported.
    60  ```
    61  
    62  Instead, you can use variable interpolation for string concatenation.
    63  
    64  ```
    65  "${var.foo}-suffix"
    66  ```
    67  
    68  ### Nested Quotes and Escaping
    69  
    70  Escaped quotes inside of interpolations were supported to retain backwards compatibility with older versions of Terraform that allowed them.
    71  
    72  Now, escaped quotes will no longer work in the interpolation context:
    73  
    74  ```
    75  "${lookup(var.somemap, \"somekey\")}"      # => Syntax Error!
    76  ```
    77  
    78  Instead, treat each set of interpolation braces (`${}`) as a new quoting context:
    79  
    80  ```
    81  "${lookup(var.somemap, "somekey")}"
    82  ```
    83  
    84  This allows double quote characters to be expressed properly within strings inside of interpolation expressions:
    85  
    86  ```
    87  "${upper("\"quoted\"")}"    # => "QUOTED"
    88  ```
    89  
    90  ## Safer `terraform plan` Behavior
    91  
    92  Prior to v0.7, the `terraform plan` command had the potential to write updates to the state if changes were detected during the Refresh step (which happens by default during `plan`). Some configurations have metadata that changes with every read, so Refresh would always result in changes to the state, and therefore a write.
    93  
    94  In collaborative environments with shared remote state, this potential side effect of `plan` would cause unnecessary contention over the state, and potentially even interfere with active `apply` operations if they were happening simultaneously elsewhere.
    95  
    96  Terraform v0.7 addresses this by changing the Refresh process that is run during `terraform plan` to always be an in-memory only refresh. New state information detected during this step will not be persisted to permanent state storage.
    97  
    98  If the `-out` flag is used to produce a Plan File, the updated state information _will_ be encoded into that file, so that the resulting `terraform apply` operation can detect if any changes occurred that might invalidate the plan.
    99  
   100  For most users, this change will not affect your day-to-day usage of Terraform. For users with automation that relies on the old side effect of `plan`, you can use the `terraform refresh` command, which will still persist any changes it discovers.
   101  
   102  ## Migrating to Data Sources
   103  
   104  With the addition of [Data Sources](/docs/configuration/data-sources.html), there are several resources that were acting as Data Sources that are now deprecated. Existing configurations will continue to work, but will print a deprecation warning when a data source is used as a resource.
   105  
   106   * `atlas_artifact`
   107   * `template_file`
   108   * `template_cloudinit_config`
   109   * `tls_cert_request`
   110  
   111  Migrating to the equivalent Data Source is as simple as changing the `resource` keyword to `data` in your declaration and prepending `data.` to attribute references elsewhere in your config.
   112  
   113  For example, given a config like:
   114  
   115  ```
   116  resource "template_file" "example" {
   117    template = "someconfig"
   118  }
   119  resource "aws_instance" "example" {
   120    user_data = "${template_file.example.rendered}"
   121    # ...
   122  }
   123  ```
   124  
   125  A config using the equivalent Data Source would look like this:
   126  
   127  ```
   128  data "template_file" "example" {
   129    template = "someconfig"
   130  }
   131  resource "aws_instance" "example" {
   132    user_data = "${data.template_file.example.rendered}"
   133    # ...
   134  }
   135  ```
   136  
   137  Referencing remote state outputs has also changed. The `.output` keyword is no longer required.
   138  
   139  For example, a config like this:
   140  
   141  ```
   142  resource "terraform_remote_state" "example" {
   143    # ...
   144  }
   145  
   146  resource "aws_instance" "example" {
   147    ami = "${terraform_remote_state.example.output.ami_id}"
   148    # ...
   149  }
   150  ```
   151  
   152  Would now look like this:
   153  
   154  ```
   155  data "terraform_remote_state" "example" {
   156    # ...
   157  }
   158  
   159  resource "aws_instance" "example" {
   160    ami = "${data.terraform_remote_state.example.ami_id}"
   161    # ...
   162  }
   163  ```
   164  
   165  <a id="listmap"></a>
   166  
   167  ## Migrating to native lists and maps
   168  
   169  Terraform 0.7 now supports lists and maps as first-class constructs. Although the patterns commonly used in previous versions still work (excepting any compatibility notes), there are now patterns with cleaner syntax available.
   170  
   171  For example, a common pattern for exporting a list of values from a module was to use an output with a `join()` interpolation, like this:
   172  
   173  ```
   174  output "private_subnets" {
   175    value = "${join(",", aws_subnet.private.*.id)}"
   176  }
   177  ```
   178  
   179  When using the value produced by this output in another module, a corresponding `split()` would be used to retrieve individual elements, often parameterized by `count.index`, for example:
   180  
   181  ```
   182  subnet_id = "${element(split(",", var.private_subnets), count.index)}"
   183  ```
   184  
   185  Using Terraform 0.7, list values can now be passed between modules directly. The above example can read like this for the output:
   186  
   187  ```
   188  output "private_subnets" {
   189    value = ["${aws_subnet.private.*.id}"]
   190  }
   191  ```
   192  
   193  And then when passed to another module as a `list` type variable, we can index directly using `[]` syntax:
   194  
   195  ```
   196  subnet_id = "${var.private_subnets[count.index]}"
   197  ```
   198  
   199  Note that indexing syntax does not wrap around if the extent of a list is reached - for example if you are trying to distribute 10 instances across three private subnets. For this behaviour, `element` can still be used:
   200  
   201  ```
   202  subnet_id = "${element(var.private_subnets, count.index)}"
   203  ```
   204  
   205  ## Map value overrides
   206  
   207  Previously, individual elements in a map could be overridden by using a dot notation. For example, if the following variable was declared:
   208  
   209  ```
   210  variable "amis" {
   211    type = "map"
   212    default = {
   213      us-east-1 = "ami-123456"
   214      us-west-2 = "ami-456789"
   215      eu-west-1 = "ami-789123"
   216    }
   217  }
   218  ```
   219  
   220  The key "us-west-2" could be overridden using `-var "amis.us-west-2=overridden_value"` (or equivalent in an environment variable or `tfvars` file). The syntax for this has now changed - instead maps from the command line will be merged with the default value, with maps from flags taking precedence. The syntax for overriding individual values is now:
   221  
   222  ```
   223  -var 'amis = { us-west-2 = "overridden_value" }'
   224  ```
   225  
   226  This will give the map the effective value:
   227  
   228  ```
   229  {
   230    us-east-1 = "ami-123456"
   231    us-west-2 = "overridden_value"
   232    eu-west-1 = "ami-789123"
   233  }
   234  ```
   235  
   236  It's also possible to override the values in a variables file, either in `terraform.tfvars` or specified using the `-var-file` flag.