website: Version-specific upgrade guides (v1.4 branch)

Before our website allowed selecting from older versions of Terraform to
see older documentation we needed to preserve all of the historical
upgrade guides in the latest release branch so that they'd stay available
on the website.

However, our new strategy is for each release to have its own separate
set of documentation selectable using a global version selector. We should
therefore now have only the upgrade guide for the each minor release
on its release branch, with the upgrade guides for earlier releases
instead maintained on their own branches.

However, our v1.1 branch is, as a matter of pragmatism, serving as the home
for the "v1.1 and earlier" documentation, and so there will continue to
be multiple upgrade guides on that branch. For that reason, we're
preserving the URL scheme "upgrade-guides" (plural) even though the URL
now points to only a single version upgrade guide because that causes
readers to land in the correct place if they are on a modern version's
upgrade guide page and they use the version selector to choose the
"v1.1 and earlier" option.
This commit is contained in:
Martin Atkins 2022-09-13 15:22:32 -07:00
parent 3062d43b39
commit a30294372f
15 changed files with 17 additions and 3566 deletions

View File

@ -6,11 +6,6 @@
"path": "attr-as-blocks",
"hidden": true
},
{
"title": "Terraform v1.0 Compatibility Promises",
"path": "v1-compatibility-promises",
"hidden": true
},
{
"title": "Files and Directories",
"routes": [
@ -1057,62 +1052,12 @@
]
},
{
"title": "Upgrade Guides",
"routes": [
{ "title": "Overview", "path": "upgrade-guides" },
{
"title": "Upgrading to Terraform v1.2",
"path": "upgrade-guides/1-2"
},
{
"title": "Upgrading to Terraform v1.1",
"path": "upgrade-guides/1-1"
},
{
"title": "Upgrading to Terraform v1.0",
"path": "upgrade-guides/1-0"
},
{
"title": "v1.0 Compatibility Promises",
"href": "/language/v1-compatibility-promises"
},
{
"title": "Upgrading to Terraform v0.15",
"path": "upgrade-guides/0-15"
},
{
"title": "Upgrading to Terraform v0.14",
"path": "upgrade-guides/0-14"
},
{
"title": "Upgrading to Terraform v0.13",
"path": "upgrade-guides/0-13"
},
{
"title": "Upgrading to Terraform v0.12",
"path": "upgrade-guides/0-12"
},
{
"title": "Upgrading to Terraform v0.11",
"path": "upgrade-guides/0-11"
},
{
"title": "Upgrading to Terraform v0.10",
"path": "upgrade-guides/0-10"
},
{
"title": "Upgrading to Terraform v0.9",
"path": "upgrade-guides/0-9"
},
{
"title": "Upgrading to Terraform v0.8",
"path": "upgrade-guides/0-8"
},
{
"title": "Upgrading to Terraform v0.7",
"path": "upgrade-guides/0-7"
}
]
"title": "Upgrading to Terraform v1.4",
"path": "upgrade-guides"
},
{
"title": "v1.x Compatibility Promises",
"path": "v1-compatibility-promises"
},
{ "divider": true },
{ "title": "Terraform Internals", "href": "/internals" },

View File

@ -1,152 +0,0 @@
---
page_title: Upgrading to Terraform 0.10
description: Upgrading to Terraform v0.10
---
# Upgrading to Terraform v0.10
Terraform v0.10 is a major release and thus includes some changes that
you'll 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/main/CHANGELOG.md).
After reviewing this guide, we recommend reviewing the Changelog to check on
specific notes about the resources and providers you use.
This guide focuses on changes from v0.9 to v0.10. Each previous major release
has its own upgrade guide, so please consult the other guides (available
in the navigation) if you are upgrading directly from an earlier version.
## Separated Provider Plugins
As of v0.10, provider plugins are no longer included in the main Terraform
distribution. Instead, they are distributed separately and installed
automatically by
[the `terraform init` command](/cli/commands/init).
In the long run, this new approach should be beneficial to anyone who wishes
to upgrade a specific provider to get new functionality without also
upgrading another provider that may have introduced incompatible changes.
In the short term, it just means a smaller distribution package and thus
avoiding the need to download tens of providers that may never be used.
Provider plugins are now also versioned separately from Terraform itself.
[Version constraints](/language/providers/configuration#provider-versions)
can be specified in configuration to ensure that new major releases
(which may have breaking changes) are not automatically installed.
**Action:** After upgrading, run `terraform init` in each Terraform
configuration working directory to install the necessary provider plugins.
If running Terraform in automation, this command should be run as the first
step after a Terraform configuration is cloned from version control, and
will also install any necessary modules and configure any remote backend.
**Action:** For "production" configurations, consider adding
[provider version constraints](/language/providers/configuration#provider-versions),
as suggested by the `terraform init` output, to prevent new major versions
of plugins from being automatically installed in future.
### Third-party Provider Plugins
This initial release of separated provider plugins applies only to the
providers that are packaged and released by Hashicorp. The goal is to
eventually support a similar approach for third-party plugins, but we wish
to ensure the robustness of the installation and versioning mechanisms before
generalizing this feature.
-> **Note:** As of Terraform 0.13, Terraform can automatically install
third-party providers released on the Terraform Registry.
In the mean time, third-party providers can be installed by placing them in the
user plugins directory:
| Operating system | User plugins directory |
| ----------------- | ------------------------------- |
| Windows | `%APPDATA%\terraform.d\plugins` |
| All other systems | `~/.terraform.d/plugins` |
Maintainers of third-party providers may optionally
make use of the new versioning mechanism by naming provider binaries
using the scheme `terraform-provider-NAME_v0.0.1`, where "0.0.1" is an
example version. Terraform expects providers to follow the
[semantic versioning](http://semver.org/) methodology.
Although third-party providers with versions cannot currently be automatically
installed, Terraform 0.10 _will_ verify that the installed version matches the
constraints in configuration and produce an error if an acceptable version
is unavailable.
**Action:** No immediate action required, but third-party plugin maintainers
may optionally begin using version numbers in their binary distributions to
help users deal with changes over time.
## Recursive Module Targeting with `-target`
It is possible to target all of the resources in a particular module by passing
a module address to the `-target` argument:
```
$ terraform plan -out=tfplan -target=module.example
```
Prior to 0.10, this command would target only the resources _directly_ in
the given module. As of 0.10, this behavior has changed such that the above
command also targets resources in _descendent_ modules.
For example, if `module.example` contains a module itself, called
`module.examplechild`, the above command will target resources in both
`module.example` _and_ `module.example.module.examplechild`.
This also applies to other Terraform features that use
[resource addressing](/cli/state/resource-addressing) syntax.
This includes some of the subcommands of
[`terraform state`](/cli/commands/state).
**Action:** If running Terraform with `-target` in automation, review usage
to ensure that selecting additional resources in child modules will not have
ill effects. Be sure to review plan output when `-target` is used to verify
that only the desired resources have been targeted for operations. Please
note that it is not recommended to routinely use `-target`; it is provided for
exceptional uses and manual intervention.
## Interactive Approval in `terraform apply`
Starting with Terraform 0.10 `terraform apply` has a new mode where it will
present the plan, pause for interactive confirmation, and then apply the
plan only if confirmed. This is intended to get similar benefits to separately
running `terraform plan`, but to streamline the workflow for interactive
command-line use.
For 0.10 this feature is disabled by default, to avoid breaking any wrapper
scripts that are expecting the old behavior. To opt-in to this behavior,
pass `-auto-approve=false` when running `terraform apply` without an explicit
plan file.
It is planned that a future version of Terraform will make this behavior the
default. Although no immediate action is required, we strongly recommend
adjusting any Terraform automation or wrapper scripts to prepare for this
upcoming change in behavior, in the following ways:
* Non-interative automation around production systems should _always_
separately run `terraform plan -out=tfplan` and then (after approval)
`terraform apply tfplan`, to ensure operators have a chance to review
the plan before applying it.
* If running `terraform apply` _without_ a plan file in automation for
a _non-production_ system, add `-auto-approve=true` to the command line
soon, to preserve the current 0.10 behavior once auto-approval is no longer
enabled by default.
We are using a staged deprecation for this change because we are aware that
many teams use Terraform in wrapper scripts and automation, and we wish to
ensure that such teams have an opportunity to update those tools in preparation
for the future change in behavior.
**Action:** 0.10 preserves the previous behavior as the default, so no
immediate action is required. However, maintainers of tools that wrap
Terraform, either in automation or in alternative command-line UI, should
consider which behavior is appropriate for their use-case and explicitly
set the `-auto-approve=...` flag to ensure that behavior in future versions.

View File

@ -1,314 +0,0 @@
---
page_title: Upgrading to Terraform 0.11
description: Upgrading to Terraform v0.11
---
# Upgrading to Terraform v0.11
Terraform v0.11 is a major release and thus includes some changes that
you'll 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/main/CHANGELOG.md).
After reviewing this guide, we recommend reviewing the Changelog to check on
specific notes about the resources and providers you use.
This guide focuses on changes from v0.10 to v0.11. Each previous major release
has its own upgrade guide, so please consult the other guides (available
in the navigation) if you are upgrading directly from an earlier version.
## Interactive Approval in `terraform apply`
Terraform 0.10 introduced a new mode for `terraform apply` (when run without
an explicit plan file) where it would show a plan and prompt for approval
before proceeding, similar to `terraform destroy`.
Terraform 0.11 adopts this as the default behavior for this command, which
means that for interactive use in a terminal it is not necessary to separately
run `terraform plan -out=...` to safely review and apply a plan.
The new behavior also has the additional advantage that, when using a backend
that supports locking, the state lock will be held throughout the refresh,
plan, confirmation and apply steps, ensuring that a concurrent execution
of `terraform apply` will not invalidate the execution plan.
A consequence of this change is that `terraform apply` is now interactive by
default unless a plan file is provided on the command line. When
[running Terraform in automation](https://learn.hashicorp.com/tutorials/terraform/automate-terraform?in=terraform/automation&utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS)
it is always recommended to separate plan from apply, but if existing automation
was running `terraform apply` with no arguments it may now be necessary to
update it to either generate an explicit plan using `terraform plan -out=...`
or to run `terraform apply -auto-approve` to bypass the interactive confirmation
step. The latter should be done only in unimportant environments.
**Action:** For interactive use in a terminal, prefer to use `terraform apply`
with out an explicit plan argument rather than `terraform plan -out=tfplan`
followed by `terraform apply tfplan`.
**Action:** Update any automation scripts that run Terraform non-interactively
so that they either use separated plan and apply or override the confirmation
behavior using the `-auto-approve` option.
## Relative Paths in Module `source`
Terraform 0.11 introduces full support for module installation from
[Terraform Registry](https://registry.terraform.io/) as well as other
private, in-house registries using concise module source strings like
`hashicorp/consul/aws`.
As a consequence, module source strings like `"child"` are no longer
interpreted as relative paths. Instead, relative paths must be expressed
explicitly by beginning the string with either `./` (for a module in a child
directory) or `../` (for a module in the parent directory).
**Action:** Update existing module `source` values containing relative paths
to start with either `./` or `../` to prevent misinterpretation of the source
as a Terraform Registry module.
## Interactions Between Providers and Modules
Prior to Terraform 0.11 there were several limitations in deficiencies in
how providers interact with child modules, such as:
* Ancestor module provider configurations always overrode the associated
settings in descendent modules.
* There was no well-defined mechanism for passing "aliased" providers from
an ancestor module to a descendent, where the descendent needs access to
multiple provider instances.
Terraform 0.11 changes some of the details of how each resource block is
associated with a provider configuration, which may change how Terraform
interprets existing configurations. This is notably true in the following
situations:
* If the same provider is configured in both an ancestor and a descendent
module, the ancestor configuration no longer overrides attributes from
the descendent and the descendent no longer inherits attributes from
its ancestor. Instead, each configuration is entirely distinct.
* If a `provider` block is present in a child module, it must either contain a
complete configuration for its associated provider or a configuration must be
passed from the parent module using
[the new `providers` attribute](/language/configuration-0-11/modules#providers-within-modules).
In the latter case, an empty provider block is a placeholder that declares
that the child module requires a configuration to be passed from its parent.
* When a module containing its own `provider` blocks is removed from its
parent module, Terraform will no longer attempt to associate it with
another provider of the same name in a parent module, since that would
often cause undesirable effects such as attempting to refresh resources
in the wrong region. Instead, the resources in the module resources must be
explicitly destroyed _before_ removing the module, so that the provider
configuration is still available: `terraform destroy -target=module.example`.
The recommended design pattern moving forward is to place all explicit
`provider` blocks in the root module of the configuration, and to pass
providers explicitly to child modules so that the associations are obvious
from configuration:
```hcl
provider "aws" {
region = "us-east-1"
alias = "use1"
}
provider "aws" {
region = "us-west-1"
alias = "usw1"
}
module "example-use1" {
source = "./example"
providers = {
"aws" = "aws.use1"
}
}
module "example-usw1" {
source = "./example"
providers = {
"aws" = "aws.usw1"
}
}
```
With the above configuration, any `aws` provider resources in the module
`./example` will use the us-east-1 provider configuration for
`module.example-use1` and the us-west-1 provider configuration for
`module.example-usw1`.
When a default (non-aliased) provider is used, and not explicitly
declared in a child module, automatic inheritance of that provider is still
supported.
**Action**: In existing configurations where both a descendent module and
one of its ancestor modules both configure the same provider, copy any
settings from the ancestor into the descendent because provider configurations
now inherit only as a whole, rather than on a per-argument basis.
**Action**: In existing configurations where a descendent module inherits
_aliased_ providers from an ancestor module, use
[the new `providers` attribute](/language/configuration-0-11/modules#providers-within-modules)
to explicitly pass those aliased providers.
**Action**: Consider refactoring existing configurations so that all provider
configurations are set in the root module and passed explicitly to child
modules, as described in the following section.
### Moving Provider Configurations to the Root Module
With the new provider inheritance model, it is strongly recommended to refactor
any configuration where child modules define their own `provider` blocks so
that all explicit configuration is defined in the _root_ module. This approach
will ensure that removing a module from the configuration will not cause
any provider configurations to be removed along with it, and thus ensure that
all of the module's resources can be successfully refreshed and destroyed.
A common configuration is where two child modules have different configurations
for the same provider, like this:
```hcl
# root.tf
module "network-use1" {
source = "./network"
region = "us-east-1"
}
module "network-usw2" {
source = "./network"
region = "us-west-2"
}
```
```hcl
# network/network.tf
variable "region" {
}
provider "aws" {
region = "${var.region}"
}
resource "aws_vpc" "example" {
# ...
}
```
The above example is problematic because removing either `module.network-use1`
or `module.network-usw2` from the root module will make the corresponding
provider configuration no longer available, as described in
[issue #15762](https://github.com/hashicorp/terraform/issues/15762), which
prevents Terraform from refreshing or destroying that module's `aws_vpc.example`
resource.
This can be addressed by moving the `provider` blocks into the root module
as _additional configurations_, and then passing them down to the child
modules as _default configurations_ via the explicit `providers` map:
```hcl
# root.tf
provider "aws" {
region = "us-east-1"
alias = "use1"
}
provider "aws" {
region = "us-west-2"
alias = "usw2"
}
module "network-use1" {
source = "./network"
providers = {
"aws" = "aws.use1"
}
}
module "network-usw2" {
source = "./network"
providers = {
"aws" = "aws.usw2"
}
}
```
```hcl
# network/network.tf
# Empty provider block signals that we expect a default (unaliased) "aws"
# provider to be passed in from the caller.
provider "aws" {
}
resource "aws_vpc" "example" {
# ...
}
```
After the above refactoring, run `terraform apply` to re-synchoronize
Terraform's record (in [the Terraform state](/language/state)) of the
location of each resource's provider configuration. This should make no changes
to actual infrastructure, since no resource configurations were changed.
For more details on the explicit `providers` map, and discussion of more
complex possibilities such as child modules with additional (aliased) provider
configurations, see [_Providers Within Modules_](/language/configuration-0-11/modules#providers-within-modules).
## Error Checking for Output Values
Prior to Terraform 0.11, if an error occurred when evaluating the `value`
expression within an `output` block then it would be silently ignored and
the empty string used as the result. This was inconvenient because it made it
very hard to debug errors within output expressions.
To give better feedback, Terraform now halts and displays an error message
when such errors occur, similar to the behavior for expressions elsewhere
in the configuration.
Unfortunately, this means that existing configurations may have erroneous
outputs lurking that will become fatal errors after upgrading to Terraform 0.11.
The prior behavior is no longer available; to apply such a configuration with
Terraform 0.11 will require adjusting the configuration to avoid the error.
**Action:** If any existing output value expressions contain errors, change these
expressions to fix the error.
### Referencing Attributes from Resources with `count = 0`
A common pattern for conditional resources is to conditionally set count
to either `0` or `1` depending on the result of a boolean expression:
```hcl
resource "aws_instance" "example" {
count = "${var.create_instance ? 1 : 0}"
# ...
}
```
When using this pattern, it's required to use a special idiom to access
attributes of this resource to account for the case where no resource is
created at all:
```hcl
output "instance_id" {
value = "${element(concat(aws_instance.example.*.id, list("")), 0)}"
}
```
Accessing `aws_instance.example.id` directly is an error when `count = 0`.
This is true for all situations where interpolation expressions are allowed,
but previously _appeared_ to work for outputs due to the suppression of the
error. Existing outputs that access non-existent resources must be updated to
use the idiom above after upgrading to 0.11.0.

View File

@ -1,829 +0,0 @@
---
page_title: Upgrading to Terraform 0.12
description: Upgrading to Terraform v0.12
---
# Upgrading to Terraform v0.12
[Terraform v0.12 is a major release](https://hashicorp.com/blog/terraform-0-1-2-preview)
focused on configuration language improvements and thus includes some
changes that you'll need to consider when upgrading. The goal of this guide is
to cover the most common upgrade concerns and issues.
For most users, upgrading configuration should be completely automatic. Some
simple configurations will require no changes at all, and most other
configurations can be prepared by running
[the automatic upgrade tool](/cli/commands/0.12upgrade). Please read on
for more information and recommendations on the upgrade process.
-> If you are a developer maintaining a provider plugin, please see
[the documentation on 0.12 compatibility for providers](/plugin/sdkv2/guides/terraform-0.12-compatibility)
to learn more about the changes that are required.
## Upgrade to Terraform 0.11 first
We strongly recommend completing an upgrade to the latest Terraform v0.11
release first. This will give you an opportunity to address any changes
required for the previous major version upgrades separately, rather than
making multiple changes at once.
In particular, if you are upgrading from a Terraform version prior to v0.9,
you _must_ first [upgrade to Terraform v0.9](/language/upgrade-guides/0-9) and
switch to initializing with `terraform init`, because v0.12 no longer includes
the functionality for automatically migrating from the legacy remote state
mechanism.
This guide focuses on changes from v0.11 to v0.12. Each previous major release
has its own upgrade guide, so please consult the other guides (available in the
navigation) to upgrade step-by-step to v0.11 first.
Terraform v0.11.14 (and any subsequent v0.11 releases) also include some
additional functionality to help smooth the upgrade, which we will use later
in this guide.
Prior versions of Terraform are available from
[the releases server](https://releases.hashicorp.com/terraform/).
## Pre-upgrade Checklist
Terraform v0.11.14 introduced a temporary helper command
`terraform 0.12checklist`, which analyzes your configuration to detect any
required steps that will be easier to perform before upgrading.
To use it, first upgrade to [Terraform v0.11.14](https://releases.hashicorp.com/terraform/0.11.14/).
Then, perform the following steps:
* `terraform init` to ensure your working directory is fully initialized and
all required plugins are installed and selected.
* `terraform apply` to ensure that your real infrastructure and Terraform
state are consistent with the current configuration. The instructions
produced by the checklist command assume that configuration and state are
synchronized.
* `terraform 0.12checklist` to see if there are any pre-upgrade steps in the
checklist.
If all is well, the final command will produce a message like this:
```
Looks good! We did not detect any problems that ought to be
addressed before upgrading to Terraform v0.12
This tool is not perfect though, so please check the v0.12 upgrade
guide for additional guidance, and for next steps:
https://www.terraform.io/upgrade-guides/0-12.html
```
As the message suggests, the next step in that case is to read the remainder
of this page to prepare for and carry out the upgrade.
However, the checklist command may instead produce a list of one or more tasks
that we recommend you perform before upgrading to Terraform 0.12, because they
are easier to perform with a fully-functional Terraform 0.11 than with a
Terraform 0.12 that has encountered compatibility problems.
The tasks it may suggest you perform could include:
* Upgrading any provider versions that are not compatible with Terraform v0.12.
We recommend upgrading to the latest version of each provider before upgrading
because that will avoid changing many things in one step.
* Renaming any resources or provider aliases that have names that start with
digits, because that is no longer valid in Terraform 0.12.
* Upgrading any external modules the configuration uses which themselves have
the above problems.
In each case, the tool will give some direction on how to perform the task it
is suggesting.
The output from `terraform 0.12checklist` is in Markdown format so that it can
easily be pasted into a Markdown-compatible issue tracker, should you want
to track the necessary tasks or share the work with other team members.
After all of the tasks are complete, run `terraform 0.12checklist` one more time
to verify that everything is complete. If so, continue reading the following
sections to complete the upgrade!
### Addendum: Invalid module names
There is one additional pre-upgrade checklist item that the Terraform team did
not become aware of until after the release of Terraform v0.11.14, and thus
cannot be detected automatically by the checklist tool: renaming modules which
have names that start with digits.
Terraform 0.11 inadvertently tolerated leading-digit names for modules as a
result of a validation bug, but Terraform 0.12 has corrected that bug and will
reject such module names. Unfortunately, module names are also recorded in
state snapshots and so a state snapshot created for a configuration with an
invalid module name will itself be invalid as far as Terraform 0.12 is
concerned.
You can address this in a similar way to what the checklist tool suggests for
invalid resource names and provider aliases:
* Rename the module in your configuration.
* Use `terraform state mv module.old module.new` _in Terraform 0.11.14_ to
update the state to use the new name instead of the old name.
As with all of the pre-upgrade checklist items, be sure to run `terraform apply`
once more before upgrading in order to ensure that the latest state snapshot is
synchronized with the latest configuration.
## Upgrading to Terraform 0.12
Before switching to Terraform 0.12, we recommend using Terraform v0.11.14 (or
any later v0.11 release) to perform one last `terraform init` and
`terraform apply` to ensure that everything is initialized and synchronized.
Once `terraform apply` shows no changes pending, switch over to a Terraform
v0.12 release and run `terraform init` again to upgrade the working directory
metadata to v0.12 format. (Once you've done this, you'll need to delete the
`.terraform` directory if you wish to return to Terraform v0.11, but no
real infrastructure or persisted state will be upgraded yet.)
It is possible that your configuration may be using configuration constructs
that are not Terraform v0.12 compatible and thus require upgrade. In that case,
`terraform init` will produce the following message:
```
Terraform has initialized, but configuration upgrades may be needed.
Terraform found syntax errors in the configuration that prevented full
initialization. If you've recently upgraded to Terraform v0.12, this may be
because your configuration uses syntax constructs that are no longer valid,
and so must be updated before full initialization is possible.
Terraform has installed the required providers to support the configuration
upgrade process. To begin upgrading your configuration, run the following:
terraform 0.12upgrade
To see the full set of errors that led to this message, run:
terraform validate
```
As mentioned in the message, Terraform has partially initialized the directory
just enough to perform the configuration upgrade process, which is described
in the following section.
We recommend running the configuration upgrade tool even if you do not see
the above message, because it may detect and fix constructs that are
syntactically correct but still need some changes to work as expected with
Terraform v0.12.
## Upgrading Terraform configuration
Terraform v0.12 includes a new command `terraform 0.12upgrade` that will
read the configuration files for a module written for Terraform 0.11 and
update them in-place to use the cleaner Terraform 0.12 syntax and also
adjust for use of features that have changed behavior in the 0.12 Terraform
language.
Simple configuration files are likely to be understood by Terraform 0.12 as-is,
because the language is still broadly compatible, but we recommend that everyone
run the upgrade tool nonetheless. Even if your configuration is already
compatible, the tool will update your configuration to use the cleaner syntax
available in Terraform 0.12, which should improve readability.
To run the command, first make sure that your local working directory is synced
with your version control system so that there are no changes outstanding. This
will make it easier to review the changes that the upgrade tool is proposing,
using the diff feature of your version control system.
With a fully-initialized working directory (all necessary providers and child
modules installed), run `terraform 0.12upgrade` to begin the process. By default
it will print some information about what it is about to do and prompt for
confirmation:
```
This command will rewrite the configuration files in the given directory so
that they use the new syntax features from Terraform v0.12, and will identify
any constructs that may need to be adjusted for correct operation with
Terraform v0.12.
We recommend using this command in a clean version control work tree, so that
you can easily see the proposed changes as a diff against the latest commit.
If you have uncommitted changes already present, we recommend aborting this
command and dealing with them before running this command again.
Would you like to upgrade the module in the current directory?
```
If you answer yes, the `.tf` and `.tfvars` files in your current working
directory will be rewritten in-place.
The upgrade tool may also print out warnings about constructs it wasn't able to
migrate fully automatically; in that case, it will also emit comments into the
rewritten source files containing the special marker `TF-UPGRADE-TODO`, as
a prompt for a decision you'll need to make to complete the upgrade.
Once the upgrade tool has successfully completed and you've resolved any
`TF-UPGRADE-TODO` prompts, use your version control tool to review the proposed
changes and then run `terraform plan` to see the effect of those changes.
In most cases, `terraform plan` should report that no changes are required,
because the updated configuration is equivalent to before.
The remaining sections below describe both some common changes that the upgrade
tool is able to make automatically, and some other upgrade situations that
the configuration tool may not be able to fully resolve. If you encounter
any errors during the upgrade or during the subsequent `terraform plan`, the
sections below may give some additional context for how to proceed.
Once you're happy with the updated configuration, commit it to version control
in the usual way and apply it with Terraform 0.12.
### Remote state references
The `terraform_remote_state` data source has changed slightly for the v0.12
release to make all of the remote state outputs available as a single map
value, rather than as top-level attributes as in previous releases.
In previous releases, a reference to a `vpc_id` output exported by the remote
state data source might have looked like this:
```hcl
data.terraform_remote_state.vpc.vpc_id
```
This value must now be accessed via the new `outputs` attribute:
```hcl
data.terraform_remote_state.vpc.outputs.vpc_id
```
The upgrade tool will rewrite remote state references automatically to include
the additional `outputs` attribute.
Where appropriate, you can also access the outputs attribute directly to
work with the whole map as a single value:
```hcl
data.terraform_remote_state.vpc.outputs
```
Another consideration for `terraform_remote_state` is that this data source must
be able to parse the latest state snapshot for a separate Terraform
configuration that may have been updated by a newer version of Terraform.
To provide flexibility when upgrading decomposed environments that use
`terraform_remote_state`, Terraform v0.11.14 introduced support for reading
outputs from the Terraform v0.12 state format, so if you upgrade all of your
configurations to Terraform v0.11.14 first you can then perform v0.12 upgrades
of individual configurations in any order, without breaking
`terraform_remote_state` usage.
Note that the `config` block should now be in the form of an assignment with the `=` sign:
```hcl
data "terraform_remote_state" "default" {
backend = "gcs"
config = {
bucket = "..."
}
}
```
### Attributes vs. blocks
Terraform resource configurations consist of both arguments that set
individual properties of the main object being described, and nested blocks
which declare zero or more other objects that are modeled as being part of
their parent. For example:
```hcl
resource "aws_instance" "example" {
instance_type = "t2.micro"
ami = "ami-abcd1234"
tags = {
Name = "example instance"
}
ebs_block_device {
device_name = "sda2"
volume_type = "gp2"
volume_size = 24
}
}
```
In the above resource, `instance_type`, `ami`, and `tags` are both direct
arguments of the `aws_instance` resource, while `ebs_block_device` describes
a separate EBS block device object that is connected to the parent instance.
Due to the design of the configuration language decoder in Terraform v0.11 and
earlier, it was in many cases possible to interchange the argument syntax
(with `=`) and the block syntax (with just braces) when dealing with map
arguments vs. nested blocks. However, this led to some subtle bugs and
limitations, so Terraform v0.12 now requires consistent usage of argument
syntax for arguments and nested block syntax for nested blocks.
In return for this new strictness, Terraform v0.12 now allows map keys to be
set dynamically from expressions, which is a long-requested feature. The
main difference between a map attribute and a nested block is that a map
attribute will usually have user-defined keys, like we see in the `tags`
example above, while a nested block always has a fixed set of supported
arguments defined by the resource type schema, which Terraform will validate.
The configuration upgrade tool uses the provider's schema to recognize the
nature of each construct and will select the right syntax automatically. For
most simple usage, this will just involve adding or removing the equals sign
as appropriate.
A more complicated scenario is where users found that they could exploit this
flexibility to -- with some caveats -- dynamically generate nested blocks even
though this wasn't intentionally allowed:
```hcl
# Example of no-longer-supported workaround from 0.11 and earlier
ebs_block_device = "${concat(map("device_name", "sda4"), var.extra_block_devices)}"
```
Terraform v0.12 now includes a first-class feature for dynamically generating
nested blocks using expressions, using the special `dynamic` block type. The
above can now be written like this, separating the static block device from
the dynamic ones:
```hcl
ebs_block_device {
device_name = "sda4"
}
dynamic "ebs_block_device" {
for_each = var.extra_block_devices
content {
device_name = ebs_block_device.value.device_name
volume_type = ebs_block_device.value.volume_type
volume_size = ebs_block_device.value.volume_size
}
}
```
The configuration upgrade tool will detect use of the above workaround and
rewrite it as a `dynamic` block, but it may make non-ideal decisions for how to
flatten your expression down into static vs. dynamic blocks, so we recommend
reviewing the generated `dynamic` blocks to see if any simplifications are
possible.
Terraform v0.12 now also requires that each argument be set only once within
a particular block, whereas before Terraform would either take the last
definition or, in some cases, attempt to merge together multiple definitions
into a list. The upgrade tool does not remove or attempt to consolidate
any existing duplicate arguments, but other commands like `terraform validate`
will detect and report these after upgrading.
### Integer vs. Float Number Types
From Terraform v0.12, the Terraform language no longer distinguishes between
integer and float types, instead just having a single "number" type that can
represent high-precision floating point numbers. This new type can represent
any value that could be represented before, plus many new values due to the
expanded precision.
In most cases this change should not cause any significant behavior change, but
please note that in particular the behavior of the division operator is now
different: it _always_ performs floating point division, whereas before it
would sometimes perform integer division by attempting to infer intent from
the argument types.
If you are relying on integer division behavior in your configuration, please
use the `floor` function to obtain the previous result. A common place this
would arise is in index operations, where the index is computed by division:
```hcl
example = var.items[floor(count.index / var.any_number)]
```
Using a fractional number to index a list will produce an error telling you
that this is not allowed, serving as a prompt to add `floor`:
```
Error: Invalid index
The given key does not identify an element in this collection value: indexing a
sequence requires a whole number, but the given index (0.5) has a fractional
part.
```
Unfortunately the automatic upgrade tool cannot apply a fix for this case
because it does not have enough information to know if floating point or integer
division was intended by the configuration author, so this change must be made
manually where needed.
### Referring to List Variables
In early versions of Terraform, before list support became first-class, we
required using seemingly-redundant list brackets around a single expression
in order to hint to the language interpreter that a list interpretation was
desired:
```hcl
# Example for older versions of Terraform; not valid for v0.12
example = ["${var.any_list}"]
```
This strange requirement was subsequently lifted after the introduction of
first-class list support, but we retained compatibility with this older usage
for a transitional period by including some fixup logic that would detect when
list brackets contain list expressions and automatically flatten to a single
list.
As part of implementing the first-class expressions support for v0.12, we needed
to finally remove that backward-compatibility mechanism to avoid ambiguity
in the language, so an expression like the above will now produce a list of
lists and thus produce a type checking error for any argument that was expecting
a list of some other type.
The upgrade tool is able to recognize most simple usage of this pattern and
rewrite automatically to just refer to the list directly:
```hcl
example = var.any_list
```
However, an unintended side-effect of this compatibility mechanism was to
also flatten mixed lists of single-value and list expressions into a single
list automatically. We didn't intend for this to be a part of the language, but
in retrospect it was an obvious consequence of how the compatibility mechanism
was implemented. If you have expressions in your modules that produce a list
of strings by using list brackets with a mixture of string and list-of-string
sub-expressions, you will need to rewrite this to explicitly use
[the `flatten` function](/language/functions/flatten)
to make the special treatment more obvious to the reader:
```hcl
example = flatten([
"single string",
var.any_list,
])
```
The configuration upgrade tool unfortunately cannot make this change
automatically, because it doesn't have enough information to know for certain
which interpretation was intended for a given list.
For complex examples that the upgrade tool is not able to adjust automatically,
subsequent Terraform operations may produce an error message like the following:
```
Error: Incorrect attribute value type
on redundant-list-brackets.tf line 9, in resource "aws_security_group" "foo":
9: cidr_blocks = ["${var.cidr_blocks}"]
Inappropriate value for attribute "cidr_blocks": element 0: string required.
```
This message is reporting that Terraform has understood this expression as a
list of lists, and therefore element zero is a list rather than a string. To
fix the error, remove the redundant list brackets and possibly add a
`flatten` function call as described above, for more complex cases.
### Reserved Variable Names
In preparation for new features planned for future releases, Terraform 0.12
reserves some additional names that can no longer be used as input variable
names for modules. These reserved names are:
* `count`
* `depends_on`
* `for_each`
* `lifecycle`
* `providers`
* `source`
When any of these names is used as the label of a `variable` block, Terraform
will now generate the following error:
```
Error: Invalid variable name
on reserved-variable-names.tf line 2, in variable "count":
2: variable "count" {
The variable name "count" is reserved due to its special meaning inside module
blocks.
```
The upgrade tool cannot automatically adjust for these reserved names, because
it does not know what new name would be more appropriate. To proceed, you must
unfortunately rename these input variables and make a new major release of
the module in question, since renaming input variables is a breaking change.
### Type Constraints on Variables
In Terraform v0.11, variables were documented as accepting only strings, lists
of strings, and maps of strings. However, in practice Terraform permitted
lists of lists and lists of maps and other nested structures in some cases,
even though it was then generally inconvenient to work with those values
elsewhere in the module due to limitations of the index syntax, `element`
function, and `lookup` function.
Terraform now allows various [type constraints](/language/expressions/type-constraints)
to be specified, as part of the language's new type system and generalized
functions and operators. However, because lists and maps of non-string values
were not officially supported in 0.11, existing configurations do not have
enough information for the upgrade tool to know what element type was intended.
It will therefore assume that lists and maps are of strings as documented,
which will be incorrect for configurations using more complex structures. The
result will be one of the following error messages:
```
Error: Invalid default value for variable
on child_module/example.tf line 4, in variable "example":
4: default = [
5: {
6: "foo" = "bar"
7: },
8: ]
This default value is not compatible with the variable's type constraint:
element 0: string required.
```
```
Error: Invalid value for module argument
on variables-incorrect-elem-type.tf line 4, in module "child":
4: example = [
5: {
6: "foo" = "bar"
7: },
8: ]
The given value is not suitable for child module variable "example" defined at
child/child.tf:1,1-19: element 0: string required.
```
To fix this, change the `type` argument from `list(string)` or `map(string)`
to a more appropriate [type constraint](/language/expressions/type-constraints).
If you're not sure what type constraint to use yet, another option is to
use the type constraint `any`, which will effectively disable validation and
allow any value. We recommend using specific types where possible, but selecting
`any` during upgrade may be preferable, so that the work to select and define
a more precise type can be saved for a later change at your leisure, once
upgrading is complete.
### Working with `count` on resources
The `count` feature allows declaration of multiple instances of a particular
resource constructed from the same configuration. In Terraform v0.11, any
use of `count` would generally lead to referring to the resource in question
using the "splat expression" syntax elsewhere in the configuration:
```
aws_instance.example.*.id[0]
```
Because `aws_instance.example` itself was not directly referencable in
Terraform v0.11, the expression system allowed some flexibility in how such
expressions were resolved. For example, Terraform would treat
`aws_instance.example.id` as an alias for `aws_instance.example.*.id[0]`.
Terraform v0.12 allows referring to an entire resource as an object value,
but that required making a decision on what type of value is returned by
`aws_instance.example`. The new rules are as follows:
* For resources where `count` is _not_ set, a reference like
`aws_instance.example` returns a single object, whose attributes can be
accessed in the usual way, like `aws_instance.example.id`.
* For resources where `count` _is_ set -- even if the expression evaluates to
`1` -- `aws_instance.example` returns a list of objects whose length is
decided by the count. In this case `aws_instance.example.id` is an error,
and must instead be written as `aws_instance.example[0].id` to access
one of the objects before retrieving its `id` attribute value.
The splat syntax is still available and will still be useful in situations
where a list result is needed, but we recommend updating expressions like
`aws_instance.example.*.id[count.index]` to instead be
`aws_instance.example[count.index].id`, which should be easier to read and
understand for those who are familiar with other languages.
Another consequence of the new handling of `count` is that you can use the
`length` function directly with references to resources that have `count` set:
```
length(aws_instance.example)
```
This replaces the v0.11 special case of `aws_instance.example.count`, which
can no longer be supported due to `aws_instance.example` being a list.
The upgrade tool will automatically detect references that are inconsistent
with the `count` setting on the target resource and rewrite them to use the
new syntax. The upgrade tool will _not_ rewrite usage of splat syntax to
direct index syntax, because the old splat syntax form is still compatible.
Another `count`-related change is that Terraform now requires `count` to be
assigned a numeric value, and will not automatically convert a boolean value
to a number in the interests of clarity. If you wish to use a boolean value
to activate or deactivate a particular resource, use the conditional operator
to show clearly how the boolean value maps to a number value:
```hcl
count = var.enabled ? 1 : 0
```
### First-class expressions
Terraform v0.11 and earlier allowed expressions only within interpolation
sequences, like `"${var.example}"`. Because expressions are such an important
part of Terraform -- they are the means by which we connect the attributes of
one resource to the configuration of another -- Terraform v0.12 now allows
you to use expressions directly when defining most attributes.
```
ami = var.ami
```
The generalization of expression handling also has some other benefits. For
example, it's now possible to directly construct lists and maps within
expressions using the normal syntax, whereas in Terraform v0.11 we required
using the `list` and `map` functions:
```
# Old 0.11 example
tags = "${merge(map("Name", "example"), var.common_tags)}"
# Updated 0.12 example
tags = merge({ Name = "example" }, var.common_tags)
```
The automatic upgrade tool will perform rewrites like these automatically,
making expressions easier to read and understand.
### Default settings in `connection` blocks
Terraform v0.11 and earlier allowed providers to pre-populate certain arguments
in a `connection` block for use with remote provisioners. Several resource
type implementations use this to pre-populate `type` as `"ssh"` and `host`
as one of the IP addresses of the compute instance being created.
While that feature was convenient in some cases, we found that in practice it
was hard for users to predict how it would behave, since each provider had its
own rules for whether to prefer public vs. private IP addresses, which network
interface to use, whether to use IPv4 or IPv6, etc.
It also violated our design principle of "explicit is better than implicit": we
think it's important that someone who is unfamiliar with a particular Terraform
configuration (or with Terraform itself) to be able to read the configuration
and make a good guess as to what it will achieve, and the default connection
settings feature left an important detail unstated: how do the provisioners
access the host?
With this in mind, Terraform v0.12 no longer performs any automatic population
of `connection` blocks. Instead, if you are using any remote provisioners you
should explicitly set the connection type and the hostname to connect to:
```hcl
connection {
type = "ssh"
host = self.public_ip
# ...
}
```
The automatic upgrade tool will detect existing `connection` blocks that are
lacking these settings within resource types that are known to have previously
set defaults, and it will write out an expression that approximates whatever
selection logic the provider was previously doing in its own implementation.
Unfortunately in some cases the provider did not export the result of the
possibly-rather-complex host selection expression as a single attribute, and so
for some resource types the generated `host` expression will be quite
complicated. We recommend reviewing these and replacing them with a simpler
expression where possible, since you will often know better than Terraform does
which of the instance IP addresses are likely to be accessible from the host
where Terraform is running.
### Equality operations must be valid on value and type
In 0.11, `"1"` would compare truthfully against `1`, however, in 0.12,
values must be equal on both value and type in order to be true. That is, in 0.11
you would see:
```
> "1" == 1
true
```
and in 0.12:
```
> "1" == 1
false
```
This means special care should be taken if you have any conditionals comparing to say,
`count.index` where you were previously expecting it to be a string, when it is now a number.
This is a scenario where you would need to update existing 0.11 code to work as you expect in 0.12:
```
resource "server_instance" "app" {
server_status = "${count.index == local.prod_index ? "production" : "standby"}"
}
}
locals {
# when migrating to 0.12, be sure to change this value to a number
# to ensure expected behavior
prod_index = "0"
}
```
Also take care that if you have a variable that is a number, but defined as a string,
the upgrade tool will not change it to a number, so take care to inspect your code:
```
locals {
some_count = "3" # will not be changed to a number after config upgrade
}
```
## Upgrades for reusable modules
If you are making upgrades to a reusable module that is consumed by many
different configurations, you may need to take care with the timing of your
upgrade and of how you publish it.
We strongly recommend using module versioning, either via a Terraform registry
or via version control arguments in your module source addresses, to pin
existing references to the old version of the module and then publish the
upgraded version under a new version number. If you are using semantic
versioning, such as in a Terraform registry, the updates made by the upgrade
tool should be considered a breaking change and published as a new major
version.
The migration tool will automatically add a `>= 0.12.0` Terraform version
constraint to indicate that the module has been upgraded to use v0.12-only
features. By using version constraints, users can gradually update their callers
to use the newly-upgraded version as they begin to use Terraform v0.12 with
those modules.
For simpler modules it may be possible to carefully adapt them to be both
0.11 and 0.12 compatible at the same time, by following the upgrade notes in
earlier sections and avoiding any v0.12-only features. However, for any module
using a undocumented workarounds for v0.11 limitations it is unlikely to be
possible to both update it for Terraform v0.12 and retain v0.11 compatibility
at the same time, because those undocumented workarounds have been replaced
with new features in Terraform v0.12.
## Map variables no longer merge when overridden
In prior versions of Terraform, a variable of type `"map"` had a special
behavior where any value provided via mechanisms such as the `-var` command
line option would be keywise-merged with any default value associated with
the variable. This was useful in early versions of Terraform that lacked
mechanisms for doing such merging explicitly, but since Terraform v0.10
introduced the concept of local values we consider it preferable to perform
such merges manually so that they are explicit in configuration:
```
variable "example_map" {
type = map(string)
default = {}
}
locals {
default_map_keys = {
"a" = "b"
}
merged_map_keys = merge(local.default_map_keys, var.example_map)
}
```
In order to improve the consistency of variable handling across types, the
map variable merging behavior is removed in Terraform v0.12. Because this
mechanism was driven by command line options rather than configuration, the
automatic upgrade tool cannot automatically handle it. If you are relying on
the merging feature, you must reorganize your configuration to use explicit
merging like in the above example, or else your default map value will be
entirely overridden by any explicitly-set value.
## Upgrading `remote` Backend Configuration
Terraform Cloud and Terraform Enterprise users will need
to run `terraform init -reconfigure` to upgrade to Terraform 0.12.
Terraform provides a message stating that `terraform init` is required; while
there is no harm in running this command, the next error message will clarify
that `terraform init -reconfigure` is required.
## Upgrading Sentinel policies
The Terraform Sentinel imports have been updated to work with Terraform 0.12.
Care has been taken to ensure that the API is as backwards compatible as
possible and most policies will continue to work without modification. However,
there are some important changes and certain policies will need to modified.
More information on the changes can be found in our page on [using Sentinel with
Terraform 0.12](/cloud-docs/sentinel/sentinel-tf-012).
It's strongly advised that you test your Sentinel policies after upgrading to
Terraform 0.12 to ensure they continue to work as expected. [Mock
generation](/cloud-docs/sentinel/mock) has also been updated to
produce mock data for the Sentinel imports as they appear in Terraform 0.12.
For more information on testing a policy with 0.11 and 0.12 at the same time,
see the section on [testing a policy with 0.11 and 0.12
simultaneously](/cloud-docs/sentinel/sentinel-tf-012#testing-a-policy-with-0-11-and-0-12-simultaneously).

View File

@ -1,482 +0,0 @@
---
page_title: Upgrading to Terraform v0.13
description: Upgrading to Terraform v0.13
---
# Upgrading to Terraform v0.13
Terraform v0.13 is a major release and thus includes some changes that
you'll 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/main/CHANGELOG.md).
After reviewing this guide, we recommend reviewing the Changelog to check for
specific notes about less-commonly-used features.
This guide focuses on changes from v0.12 to v0.13. 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.12 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.
In particular, Terraform v0.13 no longer includes the `terraform 0.12upgrade`
command for automatically migrating module source code from v0.11 to v0.12
syntax. If your modules are written for v0.11 and earlier you may need to
upgrade their syntax using the latest minor release of Terraform v0.12 before
using Terraform v0.13.
-> 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:
* [Before You Upgrade](#before-you-upgrade)
* [Explicit Provider Source Locations](#explicit-provider-source-locations)
* [New Filesystem Layout for Local Copies of Providers](#new-filesystem-layout-for-local-copies-of-providers)
* [Special considerations for in-house providers](#in-house-providers)
* [Destroy-time provisioners may not refer to other resources](#destroy-time-provisioners-may-not-refer-to-other-resources)
* [Data resource reads can no longer be disabled by `-refresh=false`](#data-resource-reads-can-no-longer-be-disabled-by-refresh-false)
* [Frequently Asked Questions](#frequently-asked-questions)
## Before You Upgrade
When upgrading between major releases, we always recommend ensuring that you
can run `terraform plan` and see no proposed changes on the previous version
first, because otherwise pending changes can add additional unknowns into the
upgrade process.
For this upgrade in particular, completing the upgrade will require running
`terraform apply` with Terraform 0.13 after upgrading in order to apply some
upgrades to the Terraform state, and we recommend doing that with no other
changes pending.
## Explicit Provider Source Locations
Prior versions of Terraform have supported automatic provider installation only
for providers packaged and distributed by HashiCorp. Providers built by the
community have previously required manual installation by extracting their
distribution packages into specific local filesystem locations.
Terraform v0.13 introduces a new hierarchical namespace for providers that
allows specifying both HashiCorp-maintained and community-maintained providers
as dependencies of a module, with community providers distributed from other
namespaces on [Terraform Registry](https://registry.terraform.io/) or from a
third-party provider registry.
In order to establish the hierarchical namespace, Terraform now requires
explicit source information for any providers that are not HashiCorp-maintained,
using a new syntax in the `required_providers` nested block inside the
`terraform` configuration block:
```hcl
terraform {
required_providers {
azurerm = {
# The "hashicorp" namespace is the new home for the HashiCorp-maintained
# provider plugins.
#
# source is not required for the hashicorp/* namespace as a measure of
# backward compatibility for commonly-used providers, but recommended for
# explicitness.
source = "hashicorp/azurerm"
version = "~> 2.12"
}
newrelic = {
# source is required for providers in other namespaces, to avoid ambiguity.
source = "newrelic/newrelic"
version = "~> 2.1.1"
}
}
}
```
If you are using providers that now require an explicit source location to be
specified, `terraform init` will produce an error like the following:
```
Error: Failed to install providers
Could not find required providers, but found possible alternatives:
hashicorp/datadog -> terraform-providers/datadog
hashicorp/fastly -> terraform-providers/fastly
If these suggestions look correct, upgrade your configuration with the
following command:
terraform 0.13upgrade
```
As mentioned in the error message, Terraform v0.13 includes an automatic
upgrade command
[`terraform 0.13upgrade`](/cli/commands/0.13upgrade)
that is able to automatically generate source addresses for unlabelled
providers by consulting the same lookup table that was previously used for
Terraform v0.12 provider installation. This command will automatically modify
the configuration of your current module, so you can use the features of your
version control system to inspect the proposed changes before committing them.
We recommend running `terraform 0.13upgrade` even if you don't see the message,
because it will generate the recommended explicit source addresses for
providers in the "hashicorp" namespace.
For more information on declaring provider dependencies, see
[Provider Requirements](/language/providers/requirements).
That page also includes some guidance on how to write provider dependencies
for a module that must remain compatible with both Terraform v0.12 and
Terraform v0.13; the `terraform 0.13upgrade` result includes a conservative
version constraint for Terraform v0.13 or later, which you can weaken to
`>= 0.12.26` if you follow the guidelines in
[v0.12-Compatible Provider Requirements](/language/providers/requirements#v0-12-compatible-provider-requirements).
Each module must declare its own set of provider requirements, so if you have
a configuration which calls other modules then you'll need to run this upgrade
command for each module separately.
[The `terraform 0.13upgrade documentation`](/cli/commands/0.13upgrade)
includes an example of running the upgrade process across all directories under
a particular prefix that contain `.tf` files using some common Unix command line
tools, which may be useful if you want to upgrade all modules in a single
repository at once.
After you've added explicit provider source addresses to your configuration,
run `terraform init` again to re-run the provider installer.
-> **Action:** Either run [`terraform 0.13upgrade`](/cli/commands/0.13upgrade) for each of your modules, or manually update the provider declarations to use explicit source addresses.
The upgrade tool described above only updates references in your configuration.
The Terraform state also includes references to provider configurations which
need to be updated to refer to the correct providers.
Terraform will automatically update provider configuration references in the
state the first time you run `terraform apply` after upgrading, but it relies
on information in the configuration to understand which provider any
existing resource belongs to, and so you must run `terraform apply` at least
once (and accept any changes it proposes) before removing any `resource` blocks
from your configuration after upgrading.
If you are using Terraform Cloud or Terraform Enterprise with the VCS-driven
workflow (as opposed to CLI-driven runs), refer to
[The UI- and VCS-driven Run Workflow](/cloud-docs/run/ui) to learn how
to manually start a run after you select a Terraform v0.13 release for your
workspace.
If you remove a `resource` block (or a `module` block for a module that
contains `resource` blocks) before the first `terraform apply`, you may see
a message like this reflecting that Terraform cannot determine which provider
configuration the existing object ought to be managed by:
```
Error: Provider configuration not present
To work with null_resource.foo its original provider configuration at
provider["registry.terraform.io/-/aws"] is required, but it has been removed.
This occurs when a provider configuration is removed while objects created by
that provider still exist in the state. Re-add the provider configuration to
destroy aws_instance.example, after which you can remove the provider
configuration again.
```
In this specific upgrade situation the problem is actually the missing
`resource` block rather than the missing `provider` block: Terraform would
normally refer to the configuration to see if this resource has an explicit
`provider` argument that would override the default strategy for selecting
a provider. If you see the above after upgrading, re-add the resource mentioned
in the error message until you've completed the upgrade.
-> **Action:** After updating all modules in your configuration to use the new provider requirements syntax, run `terraform apply` to create a new state snapshot containing the new-style provider source addresses that are now specified in your configuration.
## New Filesystem Layout for Local Copies of Providers
As part of introducing the hierarchical provider namespace discussed in the
previous section, Terraform v0.13 also introduces a new hierarchical directory
structure for manually-installed providers in the local filesystem.
If you use local copies of official providers or if you use custom in-house
providers that you have installed manually, you will need to adjust your local
directories to use the new directory structure.
The previous layout was a single directory per target platform containing
various executable files named with the prefix `terraform-provider`, like
`linux_amd64/terraform-provider-google_v2.0.0`. The new expected location for the
Google Cloud Platform provider for that target platform within one of the local
search directories would be the following:
```
registry.terraform.io/hashicorp/google/2.0.0/linux_amd64/terraform-provider-google_v2.0.0
```
The `registry.terraform.io` above is the hostname of the registry considered
to be the origin for this provider. The provider source address
`hashicorp/google` is a shorthand for `registry.terraform.io/hashicorp/google`,
and the full, explicit form is required for a local directory.
Note that the version number given as a directory name must be written _without_
the "v" prefix that tends to be included when a version number is used as part
of a git branch name. If you include that prefix, Terraform will not recognize
the directory as containing provider packages.
As before, the recommended default location for locally-installed providers
is one of the following, depending on which operating system you are running
Terraform under:
* Windows: `%APPDATA%\terraform.d\plugins`
* All other systems: `~/.terraform.d/plugins`
Terraform v0.13 introduces some additional options for customizing where
Terraform looks for providers in the local filesystem. For more information on
those new options, see [Provider Installation](/cli/config/config-file#provider-installation).
If you use only providers that are automatically installable from Terraform
provider registries but still want to avoid Terraform re-downloading them from
registries each time, Terraform v0.13 includes
[the `terraform providers mirror` command](/cli/commands/providers/mirror)
which you can use to automatically populate a local directory based on the
requirements of the current configuration file:
```
terraform providers mirror ~/.terraform.d/plugins
```
-> **Action:** If you use local copies of official providers rather than installing them automatically from Terraform Registry, adopt the new expected directory structure for your local directory either by running `terraform providers mirror` or by manually reorganizing the existing files.
### In-house Providers
If you use an in-house provider that is not available from an upstream registry
at all, after upgrading you will see an error similar to the following:
```
- Finding latest version of hashicorp/happycloud...
Error: Failed to install provider
Error while installing hashicorp/happycloud: provider registry
registry.terraform.io does not have a provider named
registry.terraform.io/hashicorp/happycloud
```
Terraform assumes that a provider without an explicit source address belongs
to the "hashicorp" namespace on `registry.terraform.io`, which is not true
for your in-house provider. Instead, you can use any domain name under your
control to establish a _virtual_ source registry to serve as a separate
namespace for your local use. For example:
```
terraform.example.com/awesomecorp/happycloud/1.0.0/linux_amd64/terraform-provider-happycloud_v1.0.0
```
You can then specify explicitly the requirement for that in-house provider
in your modules, using the requirement syntax discussed in the previous section:
```hcl
terraform {
required_providers {
happycloud = {
source = "terraform.example.com/awesomecorp/happycloud"
version = "1.0.0"
}
}
}
```
If you wish, you can later run your own Terraform provider registry at the
specified hostname as an alternative to local installation, without any further
modifications to the above configuration. However, we recommend tackling that
only after your initial upgrade using the new local filesystem layout.
-> **Action:** If you use in-house providers that are not installable from a provider registry, assign them a new source address under a domain name you control and update your modules to specify that new source address.
If your configuration using one or more in-house providers has existing state
snapshots that include resources belonging to those providers, you'll also need
to perform a one-time migration of the provider references in the state, so
Terraform can understand them as belonging to your in-house providers rather
than to providers in the public Terraform Registry. If you are in this
situation, `terraform init` will produce the following error message after
you complete the configuration changes described above:
```
Error: Failed to install legacy providers required by state
Found unresolvable legacy provider references in state. It looks like these
refer to in-house providers. You can update the resources in state with the
following command:
terraform state replace-provider registry.terraform.io/-/happycloud terraform.example.com/awesomecorp/happycloud
```
Provider source addresses starting with `registry.terraform.io/-/` are a special
way Terraform marks legacy addresses where the true namespace is unknown.
For providers that were automatically-installable in Terraform 0.12, Terraform
0.13 can automatically determine the new addresses for these using a lookup
table in the public Terraform Registry, but for in-house providers you will
need to provide the appropriate mapping manually.
The `terraform state replace-provider` subcommand allows re-assigning provider
source addresses recorded in the Terraform state, and so we can use this
command to tell Terraform how to reinterpret the "legacy" provider addresses
as properly-namespaced providers that match with the provider source addresses
in the configuration.
~> **Warning:** The `terraform state replace-provider` subcommand, like all of the `terraform state` subcommands, will create a new state snapshot and write it to the configured backend. After the command succeeds the latest state snapshot will use syntax that Terraform v0.12 cannot understand, so you should perform this step only when you are ready to permanently upgrade to Terraform v0.13.
```
terraform state replace-provider 'registry.terraform.io/-/happycloud' 'terraform.example.com/awesomecorp/happycloud'
```
The command above asks Terraform to update any resource instance in the state
that belongs to a legacy (non-namespaced) provider called "happycloud" to
instead belong to the fully-qualified source address
`terraform.example.com/awesomecorp/happycloud`.
Whereas the configuration changes for provider requirements are made on a
per-module basis, the Terraform state captures data from throughout the
configuration (all of the existing module instances) and so you only need to
run `terraform state replace-provider` once per configuration.
Running `terraform init` again after completing this step should cause
Terraform to attempt to install `terraform.example.com/awesomecorp/happycloud`
and to find it in the local filesystem directory you populated in an earlier
step.
-> **Action:** If you use in-house providers that are not installable from a provider registry and your existing state contains resource instances that were created with any of those providers, use the `terraform state replace-provider` command to update the state to use the new source addressing scheme only once you are ready to commit to your v0.13 upgrade. (Terraform v0.12 cannot parse a state snapshot that was created by this command.)
## Destroy-time provisioners may not refer to other resources
Destroy-time provisioners allow introducing arbitrary additional actions into
the destroy phase of the resource lifecycle, but in practice the design of this
feature was flawed because it created the possibility for a destroy action
of one resource to depend on a create or update action of another resource,
which often leads either to dependency cycles or to incorrect behavior due to
unsuitable operation ordering.
In order to retain as many destroy-time provisioner capabilities as possible
while addressing those design flaws, Terraform v0.12.18 began reporting
deprecation warnings for any `provisioner` block setting `when = destroy` whose
configuration refers to any objects other than `self`, `count`, and `each`.
Addressing the flaws in the destroy-time provisioner design was a pre-requisite
for new features in v0.13 such as module `depends_on`, so Terraform v0.13
concludes the deprecation cycle by making such references now be fatal errors:
```
Error: Invalid reference from destroy provisioner
Destroy-time provisioners and their connection configurations may only
reference attributes of the related resource, via 'self', 'count.index',
or 'each.key'.
References to other resources during the destroy phase can cause dependency
cycles and interact poorly with create_before_destroy.
```
Some existing modules using resource or other references inside destroy-time
provisioners can be updated by placing the destroy-time provisioner inside a
`null_resource` resource and copying any data needed at destroy time into
the `triggers` map to be accessed via `self`:
```hcl
resource "null_resource" "example" {
triggers = {
instance_ip_addr = aws_instance.example.private_ip
}
provisioner "remote-exec" {
when = destroy
connection {
host = self.triggers.instance_ip_addr
# ...
}
# ...
}
}
```
In the above example, the `null_resource.example.triggers` map is effectively
acting as a temporary "cache" for the instance's private IP address to
guarantee that a value will be available when the provisioner runs, even if
the `aws_instance.example` object itself isn't currently available.
The provisioner's `connection` configuration can refer to that value via
`self`, whereas referring directly to `aws_instance.example.private_ip` in that
context is forbidden.
[Provisioners are a last resort](/language/resources/provisioners/syntax#provisioners-are-a-last-resort),
so we recommend avoiding both create-time and destroy-time provisioners wherever
possible. Other options for destroy-time actions include using `systemd` to
run commands within your virtual machines during shutdown or using virtual
machine lifecycle hooks provided by your chosen cloud computing platform,
both of which can help ensure that the shutdown actions are taken even if the
virtual machine is terminated in an unusual way.
-> **Action:** If you encounter the "Invalid reference from destroy provisioner" error message after upgrading, reorganize your destroy-time provisioners to depend only on self-references, and consider other approaches if possible to avoid using destroy-time provisioners at all.
## Data resource reads can no longer be disabled by `-refresh=false`
In Terraform v0.12 and earlier, Terraform would read the data for data
resources during the "refresh" phase of `terraform plan`, which is the same
phase where Terraform synchronizes its state with any changes made to
remote objects.
An important prerequisite for properly supporting `depends_on` for both
data resources and modules containing data resources was to change the data
resource lifecycle to now read data during the _plan_ phase, so that
dependencies on managed resources could be properly respected.
If you were previously using `terraform plan -refresh=false` or
`terraform apply -refresh=false` to disable the refresh phase, you will find
that under Terraform 0.13 this will continue to disable synchronization of
managed resources (declared with `resource` blocks) but will no longer
disable the reading of data resources (declared with `data` blocks).
~> Updating the data associated with data resources is crucial to producing an
accurate plan, and so there is no replacement mechanism in Terraform v0.13
to restore the previous behavior.
## Frequently Asked Questions
### Why do I see `-/provider` during init?
Provider source addresses starting with `registry.terraform.io/-/` are a special
way Terraform marks legacy addresses where the true namespace is unknown. For
providers that were automatically-installable in Terraform 0.12, Terraform 0.13
can automatically determine the new addresses for these using a lookup table in
the public Terraform Registry. That lookup table is accessed by using the
special namespace `-`.
When you run `init`, terraform generates a list of required providers based on
both the configuration and state. Legacy-style providers - such as providers in
a statefile written with Terraform v0.12 - don't have a namespace, so terraform
uses the placeholder namespace `-` to query the registry. That is why you may
see output like this during your first `init`:
```
- Finding latest version of -/null...
- Finding latest version of -/random...
- Finding latest version of hashicorp/null...
- Finding latest version of hashicorp/random...
```
Terraform found providers `null` and `random` in the statefile without a
namespace. Terraform _also_ found `hashicorp/null` and `hashicorp/random` in the
configuration files. Providers in configuration are automatically assumed to be
default (HashiCorp) providers, while providers found in state are first looked
up in the registry.
While this does not cause any problems for Terraform, it has been confusing. You
may circumvent this by using the `terraform state replace-provider` subcommand
to tell Terraform exactly what provider addresses are required in state.
Continuing from the example above, the following commands tell Terraform the
source address for the `null` and `random` providers:
```
terraform state replace-provider -- -/random registry.terraform.io/hashicorp/random
terraform state replace-provider -- -/null registry.terraform.io/hashicorp/null
```
If you are seeing these messages with errors, and are using in-house or
locally-installed providers, please see the section on [in-house providers](#in-house-providers).

View File

@ -1,414 +0,0 @@
---
page_title: Upgrading to Terraform v0.14
description: Upgrading to Terraform v0.14
---
# Upgrading to Terraform v0.14
Terraform v0.14 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.14/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.14. 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.13 to v0.14. 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.13 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.
In particular, Terraform v0.14 no longer includes the `terraform 0.13upgrade`
command for automatically inserting
[provider requirements](/language/providers/requirements)
into existing modules, and the automatic mechanisms to upgrade legacy provider
references in the Terraform state. You will need to successfully complete a
`terraform apply` at least once under Terraform v0.13 before upgrading an
existing configuration to 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:
* [Before You Upgrade](#before-you-upgrade)
* [Provider Dependency Lock File](#provider-dependency-lock-file)
* [Concise Terraform Plan Output](#concise-terraform-plan-output)
* [Sensitive Values in Plan Output](#sensitive-values-in-plan-output)
* [Other important workflow changes](#other-important-workflow-changes)
## Before You Upgrade
Terraform v0.14 does not support legacy Terraform state snapshot formats from
prior to Terraform v0.13, so before upgrading to Terraform v0.14 you _must_
have successfully run `terraform apply` at least once with Terraform v0.13
so that it can complete its state format upgrades.
When upgrading between major releases, we always recommend ensuring that you
can run `terraform plan` and see no proposed changes on the previous version
first, because otherwise pending changes can add additional unknowns into the
upgrade process. Terraform v0.14 has the additional requirement of running
`terraform apply`, as described above, because that allows Terraform v0.13 to
commit the result of its automatic state format upgrades.
## Provider Dependency Lock File
In Terraform v0.13 and earlier, the `terraform init` command would always
install the newest version of any provider in the configuration that would
meet the configured version constraints.
That meant that unless the configuration author manually entered _exact_
version constraints (for a particular version alone), a later provider release
could potentially cause a change in behavior for an existing configuration even
though the configuration itself had not changed.
We believe that, as far as possible, the behavior of a configuration that has
already been written and tested should remain consistent unless it is
intentionally changed by its author, and that intentional changes should be
represented in files that can be included in a version control system and
code review process.
To better meet that goal, Terraform v0.14 introduces a new
[dependency lock file](/language/files/dependency-lock),
which Terraform will generate automatically after running `terraform init`
in the same directory as your configuration's root module. This file includes
the specific version numbers selected for each provider, and also includes
the package checksums for the selected version to help ensure that the
provider packages you depend on are not changed in-place upstream,
whether accidentally or maliciously.
This new behavior is designed so that for most users it will not require
a significant change in workflow. After running `terraform init` for the
first time after upgrading you will find a new file `.terraform.lock.hcl`
in your root module directory, and `terraform init` will automatically read
and respect the entries in that file on future runs with no additional action
on your part. We strongly recommend that you commit this file to your version
control system, but if you do not then Terraform's behavior will be very similar to
the old v0.13 behavior.
There are some situations that require some further consideration though,
and those are discussed in the following sections.
### Opting out of dependency locking
We understand that not all teams share our belief that upgrades should always
be represented as changes to the code in a version control repository. Those
teams may have previously intentionally used a non-exact version constraint
for one or more providers in order to automatically adopt any future provider
releases and then make any necessary configuration changes in retrospect.
You can continue with a model similar to the v0.13 behavior after upgrading
to v0.14 by placing `.terraform.lock.hcl` in your version control system's
"ignore" file, such as `.gitignore` for Git. In that case, Terraform will
see the lock file in the same way as the internal index that Terraform v0.13
would generate under the `.terraform` directory, preserving the selections
only with in a particular working directory until you delete the file.
With that said, we do recommend that teams consider carefully the benefits
of a persistent lock file, and make a considered decision about which path
to take. We believe that a lock file under version control will be the best
choice for most teams, because we've seen this pattern used successfully in
many other programming language ecosystems.
### In-house providers and internal mirrors
Terraform v0.13 introduced a new hierarchical namespace for providers, which
was an important pre-requisite for introducing a dependency lock file in
v0.14 which can support a mixture of official, partner, community and in-house
providers in a single configuration.
If you followed the advice from the Terraform v0.13 upgrade guide about
[assigning your in-house providers their own unique source addresses](/language/upgrade-guides/0-13#in-house-providers),
and you're distributing your in-house providers to Terraform through one of
the documented mechanisms, Terraform should handle selecting a version and
recording its checksums in the same way for all of the providers you use.
However, the full functionality of the lock file does depend on some
information only available from a real provider registry, so there are some
special considerations for providers installed from either filesystem or
network mirrors:
* Mirror sources don't provide package checksums that are signed by the original
provider distributor, so by default `terraform init` will record only the
checksum for the provider package on the platform you are currently using.
For example, if you run `terraform init` on a macOS system and then commit
the lock file, a collegue running `terraform init` on a Linux system may
encounter a checksum error, because the mirror-based installation was only
able to safely record the checksum for the package it actually installed.
This problem doesn't arise for installation from a provider registry because
the registry can provide signed checksums for all packages for a particular
provider version, across all supported platforms.
If you use mirrors exclusively in your environment and you use Terraform
across a mixture of platforms then, in addition to making sure that your
mirrors include packages for all of the necessary platforms, you may choose
to use
[the new `terraform providers lock` command](/cli/commands/providers/lock)
to pre-enter the required lock file entries for all of the platforms you
intend to use.
* Terraform expects a particular version of a provider to have identical
package checksums across all installation methods you work with in your
team.
For example, if you use direct installation from Terraform registries in
your development environment but you use a mirror in your production
automation, you must ensure that the packages available for a particular
provider version in your mirror are identical to the official packages
in the origin registry.
If your internal mirrors intentionally have different packages than are
available upstream, you must either use your internal mirrors consistently
(so Terraform never uses or verifies an official package) or you must
publish your own builds so that Terraform can understand your intent for
them to be distinct.
If you are only making minor or temporary changes to a provider, such as
building for a platform that Terraform doesn't official support or including
a bugfix patch that isn't yet in an upstream release, the simplest answer
is to number your local build with semantic versioning _build metadata_,
such as `v2.1.0+companyname.1` where `v2.1.0` is the upstream release you
derived yours from, `companyname` is a short mnemonic for your organization,
and `.1` is an internal build id that you can potentially increment if
you need to make ongoing new builds from the same upstream version.
If you are making more substantial changes to a provider, such as adding
entirely new features that your modules depend on, it may be better to
instead publish the provider under a separate namespace you control, such
as publishing a fork of `hashicorp/aws` as `companyname/aws` in the public
registry or `tf.example.com/companyname/aws` for in-house distribution only.
This is a more drastic approach in that Terraform will understand your
release as an entirely separate provider, but it also allows your modules
to clearly indicate that they depend on the features of your fork rather
than the features of the upstream release.
In both cases the dependency lock file will see your releases as distinct
from the upstream ones and thus expect the two to have a different set of
checksums each.
### External module dependencies are not locked
Although we do hope to eventually include a means to lock version selections
for external modules in addition to providers, this new capability is limited
only to providers in Terraform v0.14.
Terraform modules have a different approach to distribution and versioning than
Terraform providers, with many different supported installation methods that
each require careful consideration in designing a dependency locking mechanism.
If you wish to lock your module dependencies then for now you must continue
to use the same strategy as for v0.13 and earlier: specify exact version
constraints for modules distributed via a module registry, or use the
source-type-specific mechanisms to lock to a particular version of module
packages retrieved directly using other protocols.
Note that Terraform also does not currently track checksums for external
module dependencies. If you are concerned about the possibility of external
modules being altered in-place without your knowledge, we recommend using
modules only from sources directly under your control, such as a private
Terraform module registry.
### The local provider cache directory
As an implementation detail of automatic provider installation, Terraform
has historically unpacked auto-installed plugins under the local cache
directory in `.terraform/plugins`. That directory was only intended for
Terraform's internal use, but unfortunately due to a miscommunication within
our team it was inadvertently documented as if it were a "filesystem mirror"
directory that you could place local providers in to upload them to
Terraform Cloud.
Unfortunately the implementation details have changed in Terraform v0.14 in
order to move the authority for provider version selection to the new dependency
lock file, and so manually placing extra plugins into that local cache directory
is no longer effective in Terraform v0.14.
We've included a heuristic in `terraform init` for Terraform v0.14 which should
detect situations where you're relying on an unofficial provider manually
installed into the cache directory and generate a warning like the following:
```
Warning: Missing provider is in legacy cache directory
Terraform supports a number of local directories that can serve as automatic
local filesystem mirrors, but .terraform/plugins is not one of them because
Terraform v0.13 and earlier used this directory to cache copies of provider
plugins retrieved from elsewhere.
If you intended to use this directory as a filesystem mirror for
tf.example.com/awesomecorp/happycloud, place it instead in the following
directory:
terraform.d/plugins/tf.example.com/awesomecorp/happycloud/1.1.0/linux_amd64
```
The error message suggests using the `terraform.d` directory, which is a
local search directory originally introduced in Terraform v0.10 in order to
allow sending bundled providers along with your configuration up to Terraform
Cloud. The error message assumes that use-case because it was for Terraform
Cloud in particular that this approach was previously mis-documented.
If you aren't intending to upload the provider plugin to Terraform Cloud as
part of your configuration, we recommend instead installing to one of
[the other implied mirror directories](/cli/config/config-file#implied-local-mirror-directories),
or you can explicitly configure some
[custom provider installation methods](/cli/config/config-file#provider-installation)
if your needs are more complicated.
## Concise Terraform Plan Output
In Terraform v0.11 and earlier, the output from `terraform plan` was designed
to show only the subset of resource instance attributes that had actually
changed compared to the prior state.
Although that made the output very concise, we heard from several users that
the lack of context in the output had led to some misunderstandings that in
turn caused production outages. We know that reviewing a Terraform plan can
be a point of anxiety for those working on production infrastructure, so we
responded to that feedback in Terraform v0.12 by having the plan output
instead show the full context of each resource instance that has a planned
action, and then use extra annotations (`+`, `-`, `~`) to mark the specific
attributes that will change.
Based on further feedback since the v0.12 release, we understand that the
new detailed output has been very overwhelming for resource types that have
a large number of attributes or deeply nested block structures. Terraform v0.14
introduces a new compromise that aims to still address the concern about
context while allowing better focus on the parts of each object that are
changing.
For this initial release, Terraform will omit from the plan output any
attribute that has not changed, with the exception of a number of attribute
names whose values often contain human-recognizable identifying information.
When attributes or blocks are omitted, Terraform will always include a summary
of what isn't included, to avoid ambiguity with an argument merely being unset.
This is intended as an incremental step to improve the worst cases of verbose
output in Terraform v0.12 and v0.13, but the compromises we made here may not
be suitable for all situations. If you'd like to retain the fully-verbose
output from Terraform v0.13, you can temporarily re-enable it by setting the
environment variable `TF_X_CONCISE_DIFF=0` when you run Terraform.
If you choose to opt out of the new concise mode, please
[open a feature request issue](https://github.com/hashicorp/terraform/issues/new?labels=enhancement%2C+new&template=feature_request.md)
to let us know what you found lacking in the new output. We intend to continue
iterating on the design tradeoffs here to find the best compromise to suit
the needs of most users. We expect to remove the opt-out environment variable
in Terraform v0.15.
## Sensitive Values in Plan Output
In Terraform v0.13 and earlier, Terraform allowed provider authors to mark
certain resource type attributes as being "sensitive", and similarly allowed
module authors to mark certain output values as "sensitive". Terraform would
then show the placeholder string `(sensitive value)` in the plan output,
instead of the actual value.
Terraform v0.14 introduces a more extensive version of that behavior where
Terraform will track when you write an expression whose result is derived
from a
[sensitive input variable](/language/values/outputs#sensitive-suppressing-values-in-cli-output) or
[sensitive output value](/language/values/variables#suppressing-values-in-cli-output),
and so after upgrading to Terraform v0.14 you may find that more values are
obscured in the Terraform plan output than would have been in Terraform v0.13.
If a sensitive value (either derived from a sensitive input variable or a sensitive output variable) is used in another module output, that output must be marked `sensitive` as well to be explicit about this data being passed through Terraform:
```terraform
variable "foo" {
sensitive = true
}
output "bar" {
value = var.foo
# sensitive must be true when referencing a sensitive input variable
sensitive = true
}
```
There is also experimental behavior that will extend this sensitivity-awareness to attributes providers define as sensitive. You can enable this feature by activating the experiment in the `terraform` block:
```
terraform {
experiments = [provider_sensitive_attrs]
}
```
If you enable this experiment, attributes that are defined by a given _provider_ as sensitive will have the same sensitivity-tracking behavior as sensitive input values and outputs. For example, the [`vault_generic_secret`](https://registry.terraform.io/providers/hashicorp/vault/latest/docs/data-sources/generic_secret) data source has an attribute `data` that is sensitive according to this provider's schema.
```
# mod/main.tf
terraform {
experiments = [provider_sensitive_attrs]
}
data "vault_generic_secret" "foobar" {
path = "secret/foobar"
}
output "token" {
value = vault_generic_secret.foobar.data["token"]
# a error will display if sensitive = true is not here
}
```
If you do not add `sensitive = true` to the output referencing that sensitive attribute, you will get an error:
```
Error: Output refers to sensitive values
on mod/main.tf line 6:
6: output "token" {
Expressions used in outputs can only refer to sensitive values if the
sensitive attribute is true.
```
For this feature we've taken the approach that it's better to be conservative
and obscure _potentially-sensitive_ values at the expense of potentially also
obscuring some values that aren't sensitive. Unfortunately this means that
if you've written a module in a generic or dynamic way then Terraform may
over-generalize which values are sensitive, leading to less helpful plan output.
Due to the security implications of this feature, Terraform offers no direct
way to opt out of this change. However, the obscuring of these values is done
at the UI layer only and so you can still access the raw values, if needed,
by saving your plan to an plan file and then asking Terraform to present it
in machine-readable JSON format:
```
terraform plan -out=tfplan
terraform show -json tfplan
```
Please note that the binary file `tfplan` and the JSON output produced from it
can both include cleartext representations of sensitive values, so writing
these to disk on a multi-user system or viewing the JSON output on-screen
may cause those values to become visible to others.
Sensitive values are also still saved in state snapshots stored in your
configured backend. Use the access control and audit mechanisms offered by
the remote system to control who can access that data.
## Other Important Workflow Changes
### Terraform Output Formatting
We've modified the formatting of `terraform output` to match the formatting of `terraform show`.
We consider the console output of Terraform human readable; specifically designed and optimized for operators and practitioners to review themselves. As a result we occasionally (maybe even regularly) intend to tweak that output to help improve consistency, clarity, actionability and more.
If you rely on `terraform output` in automation, please use `terraform output -json`.

View File

@ -1,534 +0,0 @@
---
page_title: Upgrading to Terraform v0.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 make 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:
* [Sensitive Output Values](#sensitive-output-values)
* [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)
* [Azure Backend `arm_`-prefixed Arguments](#azure-backend-removed-arguments)
## Sensitive Output Values
Terraform v0.14 previously introduced the ability for Terraform to track and
propagate the "sensitivity" of values through expressions that include
references to sensitive input variables and output values. For example:
```hcl
variable "example" {
type = string
sensitive = true
}
resource "example" "example" {
# The following value is also treated as sensitive, because it's derived
# from var.example.
name = "foo-${var.example}"
}
```
As part of that feature, Terraform also began requiring you to mark an output
value as sensitive if its definition includes any sensitive values itself:
```hcl
output "example" {
value = "foo-${var.example}"
# Must mark this output value as sensitive, because it's derived from
# var.example that is declared as sensitive.
sensitive = true
}
```
Terraform v0.15 extends this mechanism to also work for values derived from
resource attributes that the provider has declared as being sensitive.
Provider developers will typically mark an attribute as sensitive if the
remote system has documented the corresponding field as being sensitive, such
as if the attribute always contains a password or a private key.
As a result of that, after upgrading to Terraform v0.15 you may find that
Terraform now reports some of your output values as invalid, if they were
derived from sensitive attributes without also being marked as sensitive:
```
│ Error: Output refers to sensitive values
│ on sensitive-resource-attr.tf line 5:
│ 5: output "private_key" {
│ Expressions used in outputs can only refer to sensitive values if the
│ sensitive attribute is true.
```
If you were intentionally exporting a sensitive value, you can address the
error by adding an explicit declaration `sensitive = true` to the output
value declaration:
```hcl
output "private_key" {
value = tls_private_key.example.private_key_pem
sensitive = true
}
```
With that addition, if this output value was a root module output value then
Terraform will hide its value in the `terraform plan` and `terraform apply`
output:
```
Changes to Outputs:
+ private_key = (sensitive value)
```
-> **Note:** The declaration of an output value as sensitive must be made
within the module that declares the output, so if you depend on a third-party
module that has a sensitive output value that is lacking this declaration then
you will need to wait for a new version of that module before you can upgrade
to Terraform v0.15.
The value is only hidden in the main UI, and so the sensitive value
will still be recorded in the state. If you declared this output value in order
to use it as part of integration with other software, you can still retrieve
the cleartext value using commands intended for machine rather than human
consumption, such as `terraform output -json` or `terraform output -raw`:
```shellsession
$ terraform output -raw private_key
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAoahsvJ1rIxTIOOmJZ7yErs5eOq/Kv9+5l3h0LbxW78K8//Kb
OMU3v8F3h8jp+AB/1zGr5UBYfnYp5ncJm/OTCXLFAHxGibEbRnf1m2A3o0hEaWsw
# (etc...)
```
If you consider Terraform's treatment of a sensitive value to be too
conservative and you'd like to force Terraform to treat a sensitive value as
non-sensitive, you can use
[the `nonsensitive` function](/language/functions/nonsensitive) to
override Terraform's automatic detection:
```hcl
output "private_key" {
# WARNING: Terraform will display this result as cleartext
value = nonsensitive(tls_private_key.example.private_key_pem)
}
```
For more information on the various situations where sensitive values can
originate in Terraform, refer to the following sections:
* [Sensitive Input Variables](/language/values/variables#suppressing-values-in-cli-output)
* [Sensitive Resource Attributes](/language/expressions/references#sensitive-resource-attributes)
* [Sensitive Output Values](/language/values/outputs#sensitive)
-> **Note:** The new behavior described in this section was previously
available in Terraform v0.14 as the
[language experiment](/language/settings/#experimental-language-features)
`provider_sensitive_attrs`. That experiment has now concluded, so if you were
participating in that experiment then you'll now need to remove the experiment
opt-in from your module as part of upgrading to Terraform v0.15.
## 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](/language/modules/develop/providers#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.
## Azure Backend Removed Arguments
In an earlier release the `azure` backend changed to remove the `arm_` prefix
from a number of the configuration arguments:
| Old Name | New Name |
| --------------------- | ----------------- |
| `arm_client_id` | `client_id` |
| `arm_client_secret` | `client_secret` |
| `arm_subscription_id` | `subscription_id` |
| `arm_tenant_id` | `tenant_id` |
The old names were previously deprecated, but we've removed them altogether
in Terraform v0.15 in order to conclude that deprecation cycle.
If you have a backend configuration using the old names then you may see
errors like the following when upgrading to Terraform v0.15:
```
│ Error: Invalid backend configuration argument
│ The backend configuration argument "arm_client_id" given on
│ the command line is not expected for the selected backend type.
```
If you see errors like this, rename the arguments in your backend configuration
as shown in the table above and then run the following to re-initialize your
backend configuration:
```
terraform init -reconfigure
```
The `-reconfigure` argument instructs Terraform to just replace the old
configuration with the new configuration directly, rather than offering to
migrate the latest state snapshots from the old to the new configuration.
Migration would not be appropriate in this case because the old and new
configurations are equivalent and refer to the same remote objects.

View File

@ -1,233 +0,0 @@
---
page_title: Upgrading to Terraform 0.7
description: Upgrading to Terraform v0.7
---
# Upgrading to Terraform v0.7
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.
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/main/CHANGELOG.md). After reviewing this guide, review the Changelog to check on specific notes about the resources and providers you use.
## Plugin Binaries
Before v0.7, Terraform's built-in plugins for providers and provisioners were each distributed as separate binaries.
```
terraform # core binary
terraform-provider-* # provider plugins
terraform-provisioner-* # provisioner plugins
```
These binaries needed to all be extracted to somewhere in your `$PATH` or in the `~/.terraform.d` directory for Terraform to work.
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.
For example, if you keep Terraform binaries in `/usr/local/bin` you can clear out the old external binaries like this:
```
rm /usr/local/bin/terraform-*
```
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.
## Maps in Displayed Plans
When displaying a plan, Terraform now distinguishes attributes of type map by using a `%` character for the "length field".
Here is an example showing a diff that includes both a list and a map:
```
somelist.#: "0" => "1"
somelist.0: "" => "someitem"
somemap.%: "0" => "1"
somemap.foo: "" => "bar"
```
## Interpolation Changes
There are a few changes to Terraform's interpolation language that may require updates to your configs.
### String Concatenation
The `concat()` interpolation function used to work for both lists and strings. It now only works for lists.
```
"${concat(var.foo, "-suffix")}" # => Error! No longer supported.
```
Instead, you can use variable interpolation for string concatenation.
```
"${var.foo}-suffix"
```
### Nested Quotes and Escaping
Escaped quotes inside of interpolations were supported to retain backwards compatibility with older versions of Terraform that allowed them.
Now, escaped quotes will no longer work in the interpolation context:
```
"${lookup(var.somemap, \"somekey\")}" # => Syntax Error!
```
Instead, treat each set of interpolation braces (`${}`) as a new quoting context:
```
"${lookup(var.somemap, "somekey")}"
```
This allows double quote characters to be expressed properly within strings inside of interpolation expressions:
```
"${upper("\"quoted\"")}" # => "QUOTED"
```
## Safer `terraform plan` Behavior
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.
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.
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.
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.
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.
## Migrating to Data Sources
With the addition of [Data Sources](/language/data-sources), 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.
- `atlas_artifact`
- `template_file`
- `template_cloudinit_config`
- `tls_cert_request`
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.
For example, given a config like:
```
resource "template_file" "example" {
template = "someconfig"
}
resource "aws_instance" "example" {
user_data = "${template_file.example.rendered}"
# ...
}
```
A config using the equivalent Data Source would look like this:
```
data "template_file" "example" {
template = "someconfig"
}
resource "aws_instance" "example" {
user_data = "${data.template_file.example.rendered}"
# ...
}
```
Referencing remote state outputs has also changed. The `.output` keyword is no longer required.
For example, a config like this:
```
resource "terraform_remote_state" "example" {
# ...
}
resource "aws_instance" "example" {
ami = "${terraform_remote_state.example.output.ami_id}"
# ...
}
```
Would now look like this:
```
data "terraform_remote_state" "example" {
# ...
}
resource "aws_instance" "example" {
ami = "${data.terraform_remote_state.example.ami_id}"
# ...
}
```
<a id="listmap"></a>
## Migrating to native lists and maps
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.
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:
```
output "private_subnets" {
value = "${join(",", aws_subnet.private.*.id)}"
}
```
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:
```
subnet_id = "${element(split(",", var.private_subnets), count.index)}"
```
Using Terraform 0.7, list values can now be passed between modules directly. The above example can read like this for the output:
```
output "private_subnets" {
value = ["${aws_subnet.private.*.id}"]
}
```
And then when passed to another module as a `list` type variable, we can index directly using `[]` syntax:
```
subnet_id = "${var.private_subnets[count.index]}"
```
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:
```
subnet_id = "${element(var.private_subnets, count.index)}"
```
## Map value overrides
Previously, individual elements in a map could be overridden by using a dot notation. For example, if the following variable was declared:
```
variable "amis" {
type = "map"
default = {
us-east-1 = "ami-123456"
us-west-2 = "ami-456789"
eu-west-1 = "ami-789123"
}
}
```
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:
```
-var 'amis = { us-west-2 = "overridden_value" }'
```
This will give the map the effective value:
```
{
us-east-1 = "ami-123456"
us-west-2 = "overridden_value"
eu-west-1 = "ami-789123"
}
```
It's also possible to override the values in a variables file, either in any `terraform.tfvars` file, an `.auto.tfvars` file, or specified using the `-var-file` flag.

View File

@ -1,159 +0,0 @@
---
page_title: Upgrading to Terraform 0.8
description: Upgrading to Terraform v0.8
---
# Upgrading to Terraform v0.8
Terraform v0.8 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.
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/main/CHANGELOG.md).
After reviewing this guide, we recommend reviewing the Changelog to check on
specific notes about the resources and providers you use.
## Newlines in Strings
Newlines are no longer allowed in strings unless it is a heredoc or an
interpolation. This improves the performance of IDE syntax highlighting
of Terraform configurations and simplifies parsing.
**Behavior that no longer works in Terraform 0.8:**
```
resource "null_resource" "foo" {
value = "foo
bar"
}
```
**Valid Terraform 0.8 configuration:**
```
resource "null_resource" "foo" {
value = "foo\nbar"
value2 = <<EOF
foo
bar
EOF
# You can still have newlines within interpolations.
value3 = "${lookup(
var.foo, var.bar)}"
}
```
**Action:** Use heredocs or escape sequences when you have a string with newlines.
## Math Order of Operations
Math operations now follow standard mathematical order of operations.
Prior to 0.8, math ordering was simply left-to-right. With 0.8, `*`, `/`, and
`%` are done before `+`, `-`.
Some examples are shown below:
```
${1+5*2} => 11 (was 12 in 0.7)
${4/2*5} => 10 (was 10 in 0.7)
${(1+5)*2} => 12 (was 12 in 0.7)
```
**Action:** Use parantheses where necessary to be explicit about ordering.
## Escaped Variables in Templates
The `template_file` resource now requires that any variables specified
in an inline `template` attribute are now escaped. This _does not affect_
templates read from files either via `file()` or the `filename` attribute.
Inline variables must be escaped using two dollar signs. `${foo}` turns into
`$${foo}`.
This is necessary so that Terraform doesn't try to interpolate the values
before executing the template (for example using standard Terraform
interpolations). In Terraform 0.7, we had special case handling to ignore
templates, but this would cause confusion and poor error messages. Terraform
0.8 requires explicitly escaping variables.
**Behavior that no longer works in Terraform 0.8:**
```
data "template_file" "foo" {
template = "${foo}"
vars { foo = "value" }
}
```
**Valid Terraform 0.8 template:**
```
data "template_file" "foo" {
template = "$${foo}"
vars { foo = "value" }
}
```
**Action:** Escape variables in inline templates in `template_file` resources.
## Escape Sequences Within Interpolations
Values within interpolations now only need to be escaped once.
The exact behavior prior to 0.8 was inconsistent. In many cases, users
just added `\` until it happened to work. The behavior is now consistent:
single escape any values that need to be escaped.
For example:
```
${replace(var.foo, "\\", "\\\\")}
```
This will now replace `\` with `\\` throughout `var.foo`. Note that `\` and
`\\` are escaped exactly once. Prior to 0.8, this required double the escape
sequences to function properly.
A less complicated example:
```
${replace(var.foo, "\n", "")}
```
This does what you expect by replacing newlines with empty strings. Prior
to 0.8, you'd have to specify `\\n`, which could be confusing.
**Action:** Escape sequences within interpolations only need to be escaped
once.
## New Internal Graphs
The core graphs used to execute Terraform operations have been changed to
support new features. These require no configuration changes and should work
as normal.
They were tested extensively during 0.7.x behind experimental
flags and using the shadow graph. However, it is possible that there
are still edge cases that aren't properly handled.
While we believe it will be unlikely, if you find that something is not
working properly, you may use the `-Xlegacy-graph` flag on any Terraform
operation to use the old code path.
This flag will be removed prior to 0.9 (the next major release after 0.8),
so please report any issues that require this flag so we can make sure
they become fixed.
~> **Warning:** Some features (such as `depends_on` referencing modules)
do not work on the legacy graph code path. Specifically, any features
introduced in Terraform 0.8 won't work with the legacy code path. These
features will only work with the new, default graphs introduced with
Terraform 0.8.

View File

@ -1,72 +0,0 @@
---
page_title: Upgrading to Terraform 0.9
description: Upgrading to Terraform v0.9
---
# Upgrading to Terraform v0.9
Terraform v0.9 is a major release and thus includes some changes that
you'll need to consider when upgrading. This guide is meant 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/main/CHANGELOG.md).
After reviewing this guide, we recommend reviewing the Changelog to check on
specific notes about the resources and providers you use.
## Remote State
Remote state has been overhauled to be easier and safer to configure and use.
**The new changes are backwards compatible** with existing remote state and
you'll be prompted to migrate to the new remote backend system.
An in-depth guide for migrating to the new backend system
[is available here](https://github.com/hashicorp/terraform/blob/v0.9.11/website/source/docs/backends/legacy-0-8.html.md).
This includes
backing up your existing remote state and also rolling back if necessary.
The only non-backwards compatible change is in the CLI: the existing
`terraform remote config` command is now gone. Remote state is now configured
via the "backend" section within the Terraform configuration itself.
**Example configuring a Consul remote backend:**
```
terraform {
backend "consul" {
address = "demo.consul.io"
datacenter = "nyc3"
path = "tfdemo"
scheme = "https"
}
}
```
**Action:** Nothing immediately, everything will continue working
except scripts using `terraform remote config`.
As soon as possible, [upgrade to backends](/language/settings/backends).
## State Locking
Terraform 0.9 now will acquire a lock for your state if your backend
supports it. **This change is backwards compatible**, but may require
enhanced permissions for the authentication used with your backend.
Backends that support locking as of the 0.9.0 release are: local files,
Amazon S3, HashiCorp Consul, and Terraform Enterprise (atlas). If you don't
use these backends, you can ignore this section.
Specific notes for each affected backend:
- **Amazon S3**: DynamoDB is used for locking. The AWS access keys
must have access to Dynamo. You may disable locking by omitting the
`lock_table` key in your backend configuration.
- **HashiCorp Consul**: Sessions are used for locking. If an auth token
is used it must have permissions to create and destroy sessions. You
may disable locking by specifying `lock = false` in your backend
configuration.
**Action:** Update your credentials or configuration if necessary.

View File

@ -1,70 +0,0 @@
---
page_title: Upgrading to Terraform v1.0
description: Upgrading to Terraform v1.0
---
# Upgrading to Terraform v1.0
Terraform v1.0 is an unusual release in that its primary focus is on stability,
and it represents the culmination of several years of work in previous major
releases to make sure that the Terraform language and internal architecture
will be a suitable foundation for forthcoming additions that will remain
backward-compatible.
Terraform v1.0.0 intentionally has no significant changes compared to Terraform
v0.15.5. You can consider the v1.0 series as a direct continuation of the v0.15
series.
There are no special steps to take if you are upgrading from the previous
major release, Terraform v0.15.
You can also upgrade directly from Terraform v0.14 if you wish, although please
still consider the notes from [the Terraform v0.15 upgrade guide](/language/upgrade-guides/0-15).
If you are affected by the notes in that upgrade guide, you will still need to
take the steps described there but you can do so as part of upgrading to v1.0,
without any need for an intermediate step of running Terraform v0.15.
If you are currently using Terraform v0.13 or earlier then we strongly
recommend upgrading one major version at a time until you reach Terraform v0.14,
following the upgrade guides of each of those versions, because those earlier
versions include mechanisms to automatically detect necessary changes to your
configuration, and in some cases also automatically edit your configuration
to include those changes. Once you reach Terraform v0.14 you can then skip
directly from there to Terraform v1.0.
The following table summarizes the above recommendations. In each case, we
recommend using the latest patch release from each major version in order to
complete your upgrade.
| Current Version | Recommendation |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| v0.10 or earlier | Refer to the upgrade guides for these historical versions until you have upgraded to the latest v0.11 release, then refer to the following item. |
| v0.11 | Use [the `terraform 0.12checklist` command](/language/upgrade-guides/0-12#pre-upgrade-checklist) to detect any situations that must be addressed before upgrading to v0.12, resolve them, and then upgrade to the latest v0.12 release and follow [the v0.12 Upgrade Guide](/language/upgrade-guides/0-12). |
| v0.12 | Upgrade to the latest Terraform v0.13 release and then follow [the v0.13 upgrade guide](/language/upgrade-guides/0-13) to upgrade your configuration and state for explicit provider requirements. |
| v0.13 | Upgrade to the latest Terraform v0.14 release and attempt a normal Terraform run. If you encounter any new errors, refer to [the v0.14 upgrade guide](/language/upgrade-guides/0-14) for resolution steps. |
| v0.14 | Upgrade directly to the latest Terraform v1.0 release and attempt a normal Terraform run. If you encounter any new errors, refer to [the v0.15 upgrade guide](/language/upgrade-guides/0-15) for resolution steps. |
| v0.15 | Upgrade directly to the latest Terraform v1.0 release and attempt a normal Terraform run. Terraform v1.0 is a continuation of the v0.15 series, and so v1.0.0 and later are directly backward-compatible with Terraform v0.15.5. |
-> If you run into any problems during upgrading, 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.
## Remote State Compatibility
In a more complex system you might have multiple separate Terraform
configurations that collaborate together using
[the `terraform_remote_state` data source](/language/state/remote-state-data).
In that case, it's typical for some configurations to be applied with a new
version before others do, causing differences in the state snapshot format
between your different configurations.
If you are upgrading from Terraform v0.14 or Terraform v0.15 to Terraform v1.0
then you can upgrade your configurations in any order, because all three of
these versions have intercompatible state snapshot formats.
Upgrading from v0.13 or earlier in a multi-configuration environment may
require more explicit planning to ensure state snapshot compatibility. Please
refer to the previous release upgrade guides for more information, and upgrade
only one major version at a time until you reach Terraform v0.14.

View File

@ -1,195 +0,0 @@
---
page_title: Upgrading to Terraform v1.1
description: Upgrading to Terraform v1.1
---
# Upgrading to Terraform v1.1
Terraform v1.1 is the first minor release after establishing a compatibility
baseline in Terraform v1.0, and so this release should not require any
unusual upgrade steps for most users.
However, if you are upgrading from a version earlier than v1.0 then please
refer to [the Terraform v1.0 upgrade guide](/language/upgrade-guides/1-0) for how to upgrade through
the v0 releases to reach the v1 release series. Because v1.1 is
backward-compatible with the v1.0 series, you can upgrade directly to the
latest v1.1 release, skipping the v1.0 series entirely, at any point where the
v1.0 upgrade guide calls for upgrading to Terraform v1.0.
Terraform v1.1 continues to honor
[the Terraform v1.0 Compatibility Promises](/language/v1-compatibility-promises),
but there are some behavior changes outside of those promises that may affect a
small number of users, described in the following sections.
* [Terraform requires macOS 10.13 High Sierra or later](#terraform-requires-macos-1013-high-sierra-or-later)
* [Preparation for removing Azure AD Graph support in the AzureRM Backend](#preparation-for-removing-azure-ad-graph-support-in-the-azurerm-backend)
* [Interpretation of remote file paths in the `remote-exec` and `file` provisioners](#interpretation-of-remote-file-paths-in-the-remote-exec-and-file-provisioners)
* [Changes to `terraform graph`](#changes-to-terraform-graph)
* [Changes to `terraform state mv`](#changes-to-terraform-state-mv)
* [Provider checksum verification in `terraform apply`](#provider-checksum-verification-in-terraform-apply)
## Terraform requires macOS 10.13 High Sierra or later
As operating system vendors phase out support for older versions of their
software, the Terraform team must also phase out support in order to focus
on supporting newer releases.
With that in mind, the official releases of Terraform v1.1 now require
macOS 10.13 High Sierra or later. Earlier versions of macOS are no longer
supported, and Terraform CLI behavior on those earlier versions is undefined.
## Preparation for removing Azure AD Graph support in the AzureRM Backend
[Microsoft has announced the deprecation of Azure AD Graph](https://docs.microsoft.com/en-us/graph/migrate-azure-ad-graph-faq),
and so Terraform v1.1 marks the first phase of a deprecation process for
that legacy system in [the AzureRM state storage backend](/language/settings/backends/azurerm).
During the Terraform v1.1 release the default behavior is unchanged, but you
can explicitly opt in to Microsoft Graph by setting
`use_microsoft_graph = true` inside your `backend "azurerm` block and then
reinitializing your working directory with `terraform init -reconfigure`.
In Terraform v1.2 we plan to change this argument to default to `true` when
not set, and so we strongly recommend planning to migrate to Microsoft Graph
in the near future to prepare for the final removal of Azure AD Graph support
in a later Terraform release. However, no immediate change is required before
upgrading to Terraform v1.1.
## Interpretation of remote file paths in the `remote-exec` and `file` provisioners
When using Terraform's built-in `remote-exec` and `file` provisioners, there
are two situations where Terraform internally uses
[Secure Copy Protocol](https://en.wikipedia.org/wiki/Secure_copy_protocol)
(SCP) to upload files to the remote system at a configuration-specified
location:
* For [the `file` provisioner](/language/resources/provisioners/file),
the primary functionality is to upload a file using SCP, and the
`destination` argument specifies the remote path where the file is to be
written.
* For [the `remote-exec` provisioner](/language/resources/provisioners/remote-exec),
internally the provisioner works by uploading the given scripts to files
on the remote system and then executing them. By default the provisioner
selects a temporary filename automatically, but a module author can
potentially override that location using the `script_path` argument in the
associated [`connection` block](https://www.terraform.io/language/resources/provisioners/connection).
If you are not using either of the specific arguments mentioned above, no
configuration changes will be required to upgrade to Terraform v1.1.
These provisioners both passing the specified remote paths to the `scp` service
program on the remote system. In Terraform v1.0 and earlier, the provisioners
were passing the paths to `scp` in a way that was inadvertently subject to
_shell expansion_. That inadvertently allowed for convenient shorthands
such as `~/example` and `$HOME/example` to write into the target user's
home directory, but also offered an undesirable opportunity for accidental
remote code execution, such as `$(arbitrary-program)`.
In Terraform v1.1 both of the above remote path arguments are passed _verbatim_
to the remote `scp` service, without any prior shell expansion. For that reason,
shell-defined expansion tokens such as `~` and environment variable references
will no longer be evaluated.
By default, the OpenSSH server and the program `scp` together already interpret
relative paths as relative to the target user's home directory, and so
module authors can specify relative paths without any special metacharacters
in order to request uploading into that default location:
```hcl
provisioner "file" {
source = "local.txt"
destination = "remote.txt"
}
```
If you maintain a module that was depending on expansion of `~/`, `$HOME/`,
`${HOME}`/ or similar, remove that prefix so that your module instead specifies
just a relative path.
This is an intentional compatibility regression which we accepted after due
consideration of
[the pragmatic exceptions to our compatibility promises](/language/v1-compatibility-promises#pragmatic-exceptions).
Specifically, this behavior offered an unintended and non-obvious avenue for
arbitrary code execution on the remote system if either of the above arguments
were populated from outside input, and an alternative approach is available
which doesn't have that drawback, and this is therefore justified on security
grounds.
## Changes to `terraform graph`
The `terraform graph` command exists to help with debugging and so it
inherently exposes some of Terraform Core's implementation details. For that
reason it isn't included in the v1.0 Compatibility Promises, but we still
aim to preserve its behavior in spirit even as Terraform Core's internal
design changes.
In previous releases, `terraform graph` exposed the implementation detail that
Terraform internally knows how to build graph types called "validate" and
"eval", but Terraform Core no longer exposes those graph types externally
and so consequently the graph command will no longer accept the options
`-type=validate` or `-type=eval`.
You can see a similar result to what those graph types would previously
produce by generating a _plan_ graph, which is the default graph type and
therefore requires no special `-type=...` option.
## Changes to `terraform state mv`
Terraform's local state storage backend supports a number of
[legacy command line options](/language/settings/backends/local#command-line-arguments)
for backward-compatibility with workflows from much older versions of Terraform,
prior to the introduction of Backends.
Those options are not supported when using any other backend, but for many
commands they are simply silently ignored rather than returning an error.
Because `terraform state mv` has some extra use-cases related to migrating
between states, it historically had some slightly different handling of those
legacy options, but was not fully consistent.
From Terraform v1.1, the behavior of these options has changed as follows:
* The `-state=...` argument is allowed even when a remote backend is specified
in the configuration. If present, it forces the command to work in local
mode.
* The `-backup=...` and `-backup-out=...` options are allowed only if either
the local backend is the configuration's selected backend _or_ if you
specify `-state=...` to force local state operation. These options will now
return an error if used against a remote backend, whereas previous Terraform
versions ignored them entirely in that case.
There are no breaking changes to `terraform state mv`'s normal usage pattern,
without any special options overriding the state storage strategy.
## Provider checksum verification in `terraform apply`
This section applies only to situations where you might generate a saved
plan file using `terraform plan -out=tfplan` and then separately apply it
using `terraform apply tfplan`.
You do not need to consider this section unless you are using a custom
Terraform provider which somehow modifies its own provider package contents
during execution. That is hypothetically possible, but not true in practice for
any publicly-available providers we are aware of at the time of writing this
guide.
Our design intent for this two-step run workflow is that the saved plan
records enough information for Terraform to guarantee that it's running
against an identical set of providers during the apply step as it was during
the plan step, because otherwise the different provider plugins may disagree
about the meaning of the planned actions.
However, prior versions of Terraform verified consistency only for the main
executable file representing a provider plugin, and didn't consider other
files that might appear alongside in the plugin package. Terraform v1.1 now
uses the same strategy for provider checking during apply as it does when
verifying provider consistency against
[the dependency lock file](/language/files/dependency-lock)
during `terraform init`, which means `terraform apply` will return an error
if it detects that _any_ of the files in a provider's plugin package have
changed compared to when the plan was created.
In the unlikely event that you _do_ use a self-modifying provider plugin,
please consider other solutions to achieve the goals which motivated that,
which do not involve the provider modifying itself at runtime. If you aren't
sure, please open a GitHub issue to discuss your use-case.

View File

@ -1,43 +0,0 @@
---
page_title: Upgrading to Terraform v1.2
description: Upgrading to Terraform v1.2
---
# Upgrading to Terraform v1.2
Terraform v1.2 is a minor release in the stable Terraform v1.0 series.
Terraform v1.2 continues to honor the
[Terraform v1.0 Compatibility Promises](/language/v1-compatibility-promises),
but there are some behavior changes outside of those promises that may affect a
small number of users. Specifically, the following updates may require additional upgrade steps:
* [terraform-credentials-env functionality is built into the Terraform CLI](#the-terraform-credentials-env-functionality-is-built-into-the-terraform-cli)
* [Terraform requires Linux kernel 2.6.32 or later](#terraform-requires-linux-kernel-2-6-32-or-later)
* [Remote servers must support TLSv1.2](#remote-servers-must-support-tlsv1-2)
* [Outdated TLS features are no longer supported](#outdated-tls-features-are-no-longer-supported)
## The `terraform-credentials-env` Functionality is Built Into the Terraform CLI
We recommend disabling the [third-party credentials helper plugin terraform-credentials-env](https://github.com/apparentlymart/terraform-credentials-env) when you upgrade to Terraform v1.2. Terraform now contains similar built-in functionality.
The new v1.2 functionality supports the same environment variable naming scheme as the credentials helper, but has a difference in priority order. Specifically, `TF_TOKEN_...` environment variables now take priority over both credentials blocks in CLI configuration and credentials stored automatically when you run `terraform login`. After upgrading, ensure you do not specify credentials for the same host in multiple locations.
We also recommend upgrading the [hashicorp/tfe](https://registry.terraform.io/providers/hashicorp/tfe) provider to version 0.31 if you currently use it with the credentials helper to manage Terraform Cloud or Terraform Enterprise objects. Version 0.31 contains built-in support for the built-in `TF_TOKEN_...` environment variables.
## Terraform Requires Linux kernel 2.6.32 or Later
The Terraform runtime no longer supports Linux kernels prior to
2.6.32, and official releases of Terraform v1.2 for Linux
require distributions using kernel 2.6.32 or later. The CLI behavior on earlier
kernel versions is undefined.
## Outdated TLS Features Are No Longer Supported
Terraform no longer supports the following features when making outgoing HTTPS or other TLS connections as a client:
- TLS v1.0 and v1.1. Terraform now requires the server to support TLS v1.2. All up-to-date servers should support TLS 1.2, and mainstream web browsers have required it since 2020.
- CA certificates signed using the SHA-1 hash function. Publicly-trusted Certificate Authorities have not issued SHA-1 certificates since 2015.
This change only affects requests from Terraform, including provider installation, module installation, and interactions with your configured backend. Provider plugins are separate programs that have
their own rules about which TLS versions are supported.

View File

@ -1,10 +1,13 @@
---
page_title: Upgrade Guides
description: Upgrade Guides
page_title: Upgrading to Terraform v1.4
description: Upgrading to Terraform v1.4
---
# Upgrade Guides
# Upgrading to Terraform v1.4
Terraform's major releases can include an upgrade guide to help upgrading users
walk through backwards compatibility issues and changes to expect. See the
navigation for the available upgrade guides.
-> Do you need the upgrade guide for an earlier version of Terraform? Use the
version selector in the navigation bar to select the version you are intending
to upgrade to.
Terraform v1.4 is still under development and so its upgrade guide is not yet
finalized. This should be updated before the final v1.4.0 release.

View File

@ -1,12 +1,12 @@
---
page_title: Terraform v1.0 Compatibility Promises
page_title: Terraform v1.x Compatibility Promises
description: |-
From Terraform v1.0 onwards the Terraform team promises to preserve backward
compatibility for most of the Terraform language and the primary CLI
workflow, until the next major release.
---
# Terraform v1.0 Compatibility Promises
# Terraform v1.x Compatibility Promises
The release of Terraform v1.0 represents an important milestone in the
development of the Terraform language and workflow. Terraform v1.0 is a stable