374 lines
17 KiB
Markdown
374 lines
17 KiB
Markdown
---
|
|
layout: "language"
|
|
page_title: "Upgrading to Terraform v0.15"
|
|
sidebar_current: "upgrade-guides-0-15"
|
|
description: |-
|
|
Upgrading to Terraform v0.15
|
|
---
|
|
|
|
# Upgrading to Terraform v0.15
|
|
|
|
Terraform v0.15 is a major release and so it includes some small changes in
|
|
behavior that you may need to consider when upgrading. This guide is intended
|
|
to help with that process.
|
|
|
|
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/v0.15/CHANGELOG.md).
|
|
After reviewing this guide, we recommend reviewing the Changelog to check for
|
|
specific notes about less-commonly-used features.
|
|
|
|
This guide is also not intended as an overview of the new features in
|
|
Terraform v0.15. This release includes other enhancements that don't need any
|
|
special attention during upgrade, but those are described in the changelog and
|
|
elsewhere in the Terraform documentation.
|
|
|
|
This guide focuses on changes from v0.14 to v0.15. Terraform supports upgrade
|
|
tools and features only for one major release upgrade at a time, so if you are
|
|
currently using a version of Terraform prior to v0.14 please upgrade through
|
|
the latest minor releases of all of the intermediate versions first, reviewing
|
|
the previous upgrade guides for any considerations that may be relevant to you.
|
|
|
|
Unlike the previous few Terraform major releases, v0.15's upgrade concerns are
|
|
largely conclusions of deprecation cycles left over from previous releases,
|
|
many of which already had deprecation warnings in v0.14. If you previously
|
|
responded to those while using Terraform v0.14 then you hopefully won't need
|
|
to many any special changes to upgrade, although we still recommend reviewing
|
|
the content below to confirm, particularly if you see new errors or unexpected
|
|
behavior after upgrading from Terraform v0.14.
|
|
|
|
-> If you run into any problems during upgrading that are not addressed by the
|
|
information in this guide, please feel free to start a topic in
|
|
[The Terraform community forum](https://discuss.hashicorp.com/c/terraform-core),
|
|
describing the problem you've encountered in enough detail that other readers
|
|
may be able to reproduce it and offer advice.
|
|
|
|
Upgrade guide sections:
|
|
|
|
* [Legacy Configuration Language Features](#legacy-configuration-language-features)
|
|
* [Alternative (Aliased) Provider Configurations Within Modules](#alternative-provider-configurations-within-modules)
|
|
* [Commands Accepting a Configuration Directory Argument](#commands-accepting-a-configuration-directory-argument)
|
|
* [Microsoft Windows Terminal Support](#microsoft-windows-terminal-support)
|
|
* [Other Minor Command Line Behavior Changes](#other-minor-command-line-behavior-changes)
|
|
|
|
## Legacy Configuration Language Features
|
|
|
|
Terraform v0.12 introduced new syntax for a variety of existing Terraform
|
|
language features that were intended to make the language easier to read and
|
|
write and, in some cases, to better allow for future changes to the language.
|
|
|
|
Many of the old forms remained available but deprecated from v0.12 through to
|
|
v0.14, with these deprecations finally concluding in the v0.15 release. Those
|
|
who used the `terraform 0.12upgrade` command when upgrading from Terraform v0.11
|
|
to v0.12 will have had these updated automatically, but we've summarized the
|
|
changes below to help with any remaining legacy forms you might encounter while
|
|
upgrading to Terraform v0.15:
|
|
|
|
* The built-in functions `list` and `map` were replaced with first-class syntax
|
|
`[ ... ]` and `{ ... }` in Terraform v0.12, and we've now removed the
|
|
deprecated functions in order to resolve the ambiguity with the syntax used
|
|
to declare list and map type constraints inside `variable` blocks.
|
|
|
|
If you need to update a module which was using the `list` function, you
|
|
can get the same result by replacing `list(...)` with `tolist([...])`.
|
|
For example:
|
|
|
|
```diff
|
|
- list("a", "b", "c")
|
|
+ tolist(["a", "b", "c"])
|
|
```
|
|
|
|
If you need to update a module which was using the `map` function, you
|
|
can get the same result by replacing `map(...)` with `tomap([...])`.
|
|
For example:
|
|
|
|
```diff
|
|
- map("a", 1, "b", 2)
|
|
+ tomap({ a = 1, b = 2 })
|
|
```
|
|
|
|
The above examples include the type conversion functions `tolist` and
|
|
`tomap` to ensure that the result will always be of the same type as
|
|
before. However, in most situations those explicit type conversions won't
|
|
be necessary because Terraform can infer the necessary type conversions
|
|
automatically from context. In those cases, you can just use the
|
|
`[ ... ]` or `{ ... }` syntax directly, without a conversion function.
|
|
|
|
* In `variable` declaration blocks, the `type` argument previously accepted
|
|
v0.11-style type constraints given as quoted strings. This legacy syntax
|
|
is removed in Terraform v0.15.
|
|
|
|
To update an old-style type constraint to the modern syntax, start by
|
|
removing the quotes so that the argument is a bare keyword rather than
|
|
a string:
|
|
|
|
```hcl
|
|
variable "example" {
|
|
type = string
|
|
}
|
|
```
|
|
|
|
Additionally, if the previous type constraint was either `"list"` or
|
|
`"map`", add a type argument to specify the element type of the collection.
|
|
Terraform v0.11 typically supported only collections of strings, so in
|
|
most cases you can set the element type to `string`:
|
|
|
|
```hcl
|
|
variable "example" {
|
|
type = list(string)
|
|
}
|
|
|
|
variable "example" {
|
|
type = map(string)
|
|
}
|
|
```
|
|
|
|
* In `lifecycle` blocks nested inside `resource` blocks, Terraform previously
|
|
supported a legacy value `["*"]` for the `ignore_changes` argument, which
|
|
is removed in Terraform v0.15.
|
|
|
|
Instead, use the `all` keyword to indicate that you wish to ignore changes
|
|
to all of the resource arguments:
|
|
|
|
```hcl
|
|
lifecycle {
|
|
ignore_changes = all
|
|
}
|
|
```
|
|
|
|
* Finally, Terraform v0.11 and earlier required all non-constant expressions
|
|
to be written using string interpolation syntax, even if the result was
|
|
not a string. Terraform v0.12 introduced a less confusing syntax where
|
|
arguments can accept any sort of expression without any special wrapping,
|
|
and so the interpolation-style syntax has been redundant and deprecated
|
|
in recent Terraform versions.
|
|
|
|
For this particular change we have not made the older syntax invalid, but
|
|
we do still recommend updating interpolation-only expressions to bare
|
|
expressions to improve readability:
|
|
|
|
```diff
|
|
- example = "${var.foo}"
|
|
+ example = var.foo
|
|
```
|
|
|
|
This only applies to arguments where the value is a single expression without
|
|
any string concatenation. You must continue to use the `${ ... }` syntax for
|
|
situations where you are combining string values together into a larger
|
|
string.
|
|
|
|
The `terraform fmt` command can detect and repair simple examples of the
|
|
legacy interpolation-only syntax, and so we'd recommend running
|
|
`terraform fmt` on your modules once you've addressed any of the other
|
|
situations above that could block configuration parsing in order to update
|
|
your configurations to the typical Terraform language style conventions.
|
|
|
|
## Alternative Provider Configurations Within Modules
|
|
|
|
Terraform's provider configuration scheme includes the idea of a "default"
|
|
(unaliased) provider configuration along with zero or more alternative
|
|
(aliased) provider configurations.
|
|
|
|
The `required_providers` block now has a new field for providers to indicate
|
|
aliased configuration names, replacing the need for an empty "proxy
|
|
configuration block" as a placeholder. In order to declare
|
|
[configuration aliases](/docs/language/modules/develop/providers.html#provider-aliases-within-modules),
|
|
add the desired names to the `configuration_aliases` argument for the provider
|
|
requirements.
|
|
|
|
```hcl
|
|
terraform {
|
|
required_providers {
|
|
aws = {
|
|
source = "hashicorp/aws"
|
|
version = ">= 2.7.0"
|
|
configuration_aliases = [ aws.alternate ]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Warnings will be emitted now where empty configuration blocks are present but
|
|
no longer required, though they continue to work unchanged in the 0.15 release.
|
|
There are a few cases where existing configurations may return new errors:
|
|
|
|
* The `providers` map in a module call cannot override a provider configured
|
|
within the module. This is not a supported configuration, but was previously
|
|
missed in validation and now returns an error.
|
|
|
|
* A provider alias within a module that has no configuration _requires_ a
|
|
provider configuration be supplied in the module `providers` map.
|
|
|
|
* All entries in the `providers` map in a module call must correspond to a
|
|
provider name within the module. Passing in a configuration to an undeclared
|
|
provider is now an error.
|
|
|
|
## Commands Accepting a Configuration Directory Argument
|
|
|
|
A subset of Terraform's CLI commands have historically accepted a final
|
|
positional argument to specify which directory contains the root module of
|
|
the configuration, overriding the default behavior of expecting to find it
|
|
in the current working directory.
|
|
|
|
However, the design of that argument was flawed in a number of ways due to
|
|
it being handled at the wrong level of abstraction: it only changed where
|
|
Terraform looks for configuration and not any of the other files that Terraform
|
|
might search for, and that could therefore violate assumptions that Terraform
|
|
configurations might make about the locations of different files, leading
|
|
to confusing error messages. It was also not possible to support this usage
|
|
pattern across all commands due to those commands using positional arguments
|
|
in other ways.
|
|
|
|
To address these design flaws, Terraform v0.14 introduced a new global option
|
|
`-chdir` which you can use before the subcommand name, causing Terraform to
|
|
run the subcommand as if the given directory had been the current working
|
|
directory:
|
|
|
|
```shellsession
|
|
$ terraform -chdir=example init
|
|
```
|
|
|
|
This command causes the Terraform process to actually change its current
|
|
working directory to the given directory before launching the subcommand, and
|
|
so now any relative paths accessed by the subcommand will be treated as
|
|
relative to that directory, including (but not limited to) the following key
|
|
directory conventions:
|
|
|
|
* As with the positional arguments that `-chdir` replaces, Terraform will look
|
|
for the root module's `.tf` and `.tf.json` files in the given directory.
|
|
|
|
* The `.tfvars` and `.tfvars.json` files that Terraform automatically searches
|
|
for, and any relative paths given in `-var-file` options, will be searched
|
|
in the given directory.
|
|
|
|
* The `.terraform` directory which Terraform creates to retain the working
|
|
directory internal state will appear in the given directory, rather than
|
|
the current working directory.
|
|
|
|
After treating the v0.14 releases as a migration period for this new behavior,
|
|
Terraform CLI v0.15 no longer accepts configuration directories on any
|
|
command except `terraform fmt`. (`terraform fmt` is special compared to the
|
|
others because it primarily deals with configuration files in isolation,
|
|
rather than modules or configurations as a whole.)
|
|
|
|
If you built automation which previously relied on overriding the configuration
|
|
directory alone, you will need to transition to using the `-chdir` command line
|
|
option before upgrading to Terraform v0.15.
|
|
|
|
Since the `-chdir` argument behavior is more comprehensive than the positional
|
|
arguments it has replaced, you may need to make some further changes in the
|
|
event that your automation was relying on the limitations of the old mechanism:
|
|
|
|
* If your system depends on the `.terraform` directory being created in the
|
|
_real_ current working directory while using a root module defined elsewhere,
|
|
you can use the `TF_DATA_DIR` environment variable to specify the absolute
|
|
path where Terraform should store its working directory internal state:
|
|
|
|
```bash
|
|
TF_DATA_DIR="$PWD/.terraform"
|
|
```
|
|
|
|
* If your system uses `.tfvars` or `.tfvars.json` files either implicitly found
|
|
or explicitly selected in the current working directory, you must either
|
|
move those variables files into the root module directory or specify your
|
|
files from elsewhere explicitly using the `-var-file` command line option:
|
|
|
|
```bash
|
|
terraform plan -var-file="$PWD/example.tfvars"
|
|
```
|
|
|
|
As a special case for backward compatibility, Terraform ensures that the
|
|
language expression `path.cwd` will return the _original_ working directory,
|
|
before overriding with `-chdir`, so that existing configurations referring to
|
|
files in that directory can still work. If you want to refer to files in the
|
|
directory given in `-chdir` then you can use `path.root`, which returns the
|
|
directory containing the configuration's root module.
|
|
|
|
## Microsoft Windows Terminal Support
|
|
|
|
Until the first Windows 10 update, Microsoft Windows had a console window
|
|
implementation with an API incompatible with the virtual terminal approach
|
|
taken on all other platforms that Terraform supports.
|
|
|
|
Previous versions of Terraform accommodated this by using an API translation
|
|
layer which could convert a subset of typical virtual terminal sequences into
|
|
corresponding Windows Console API function calls, but as a result this has
|
|
prevented Terraform from using more complex terminal features such as progress
|
|
indicators that update in place, menu prompts, etc.
|
|
|
|
Over the course of several updates to Windows 10, Microsoft has introduced
|
|
virtual terminal support similar to other platforms and
|
|
[now recommends the virtual terminal approach for console application developers](https://docs.microsoft.com/en-us/windows/console/classic-vs-vt).
|
|
In response to that recommendation, Terraform v0.15 no longer includes the
|
|
terminal API translation layer and consequently it will, by default, produce
|
|
incorrectly-formatted output on Windows 8 and earlier, and on non-updated
|
|
original retail Windows 10 systems.
|
|
|
|
If you need to keep using Terraform on an older version of Windows, there are
|
|
two possible workarounds available in the v0.15.0 release:
|
|
|
|
* Run Terraform commands using the `-no-color` command line option to disable
|
|
the terminal formatting sequences.
|
|
|
|
This will cause the output to be unformatted plain text, but as a result
|
|
will avoid the output being interspersed with uninterpreted terminal
|
|
control sequences.
|
|
|
|
* Alternatively, you can use Terraform v0.15.0 in various third-party
|
|
virtual terminal implementations for older Windows versions, including
|
|
[ConEmu](https://conemu.github.io/), [Cmder](https://cmder.net/),
|
|
and [mintty](https://mintty.github.io/).
|
|
|
|
Although we have no immediate plans to actively block running Terraform on
|
|
older versions of Windows, we will not be able to test future versions of
|
|
Terraform on those older versions and so later releases may contain
|
|
unintended regressions. We recommend planning an upgrade to a modern Windows
|
|
release on any system where you expect to continue using Terraform CLI.
|
|
|
|
## Other Minor Command Line Behavior Changes
|
|
|
|
Finally, Terraform v0.15 includes a small number of minor changes to the
|
|
details of some commands and command line arguments, as part of a general
|
|
cleanup of obsolete features and improved consistency:
|
|
|
|
* Interrupting Terraform commands with your operating system's interrupt
|
|
signal (`SIGINT` on Unix systems) will now cause Terraform to exit with
|
|
a non-successful exit code. Previously it would, in some cases, exit with
|
|
a success code.
|
|
|
|
This signal is typically sent to Terraform when you press
|
|
Ctrl+C or similar interrupt keyboard shortcuts in an interactive terminal,
|
|
but might also be used by automation in order to gracefully cancel a
|
|
long-running Terraform operation.
|
|
|
|
* The `-lock` and `-lock-timeout` options are no longer available for the
|
|
`terraform init` command. Locking applies to operations that can potentially
|
|
change remote objects, to help ensure that two concurrent Terraform processes
|
|
don't try to run conflicting operations, but `terraform init` does not
|
|
interact with any providers in order to possibly effect such changes.
|
|
|
|
These options didn't do anything in the `terraform init` command before,
|
|
and so you can remove them from any automated calls with no change
|
|
in behavior.
|
|
|
|
* The `-verify-plugins` and `-get-plugins` options to `terraform init` are
|
|
no longer available. These have been non-functional since Terraform v0.13,
|
|
with the introduction of the new Terraform Registry-based provider installer,
|
|
because in practice there are very few operations Terraform can perform which
|
|
both require a `terraform init` but can also run without valid provider
|
|
plugins installed.
|
|
|
|
If you were using these options in automated calls to `terraform init`,
|
|
remove them from the command line for compatibility with Terraform v0.15.
|
|
There is no longer an option to initialize without installing the
|
|
required provider plugins.
|
|
|
|
* The `terraform destroy` command no longer accepts the option `-force`. This
|
|
was a previous name for the option in earlier Terraform versions, but we've
|
|
since adopted `-auto-approve` for consistency with the `terraform apply`
|
|
command.
|
|
|
|
If you are using `-force` in an automated call to `terraform destroy`,
|
|
change to using `-auto-approve` instead.
|