From 08ba58c8c800a8dbea98c9f5fc24f6f828ff855e Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Fri, 31 Jul 2020 15:22:50 -0700 Subject: [PATCH] website: Documentation about the one-to-one object binding assumption Terraform's design assumes that each remote object in Terraform's care is bound to one resource instance and one alone. If the same object is bound to multiple instances then confusing behavior will often result, such as two resource configurations competing to update a single object, or objects being "left behind" when all existing Terraform deployments are destroyed. This assumption was previously only implied, though. This change is an attempt to be more explicit about it, although these are additions to some older documentation sections that have not been revised for some time and so this is just a best effort to make this information discoverable without getting drawn into a full-on reorganization of these sections. While revising this there were some particular oddities that I decided to revise while I was there, but I'll leave a fuller revision of this older content for a later commit when we have more time to review it in greater detail. --- website/docs/commands/import.html.md | 8 +++++ website/docs/import/index.html.md | 8 +++++ website/docs/import/usage.html.md | 8 +++++ website/docs/state/index.html.md | 48 +++++++++++++++++++++++----- website/docs/state/purpose.html.md | 11 +++++++ 5 files changed, 75 insertions(+), 8 deletions(-) diff --git a/website/docs/commands/import.html.md b/website/docs/commands/import.html.md index 77b405494..ed94de64c 100644 --- a/website/docs/commands/import.html.md +++ b/website/docs/commands/import.html.md @@ -31,6 +31,14 @@ it is the zone ID (`Z12ABC4UGMOZ2N`). Please reference the provider documentatio on the ID format. If you're unsure, feel free to just try an ID. If the ID is invalid, you'll just receive an error message. +~> Warning: Terraform expects that each remote object it is managing will be +bound to only one resource address, which is normally guaranteed by Terraform +itself having created all objects. If you import existing objects into Terraform, +be careful to import each remote object to only one Terraform resource address. +If you import the same object multiple times, Terraform may exhibit unwanted +behavior. For more information on this assumption, see +[the State section](/docs/state/). + The command-line flags are all optional. The list of available flags are: * `-backup=path` - Path to backup the existing state file. Defaults to diff --git a/website/docs/import/index.html.md b/website/docs/import/index.html.md index 97fb598c5..bce9ea538 100644 --- a/website/docs/import/index.html.md +++ b/website/docs/import/index.html.md @@ -20,6 +20,14 @@ This is a great way to slowly transition infrastructure to Terraform, or to be able to be confident that you can use Terraform in the future if it potentially doesn't support every feature you need today. +~> Warning: Terraform expects that each remote object it is managing will be +bound to only one resource address, which is normally guaranteed by Terraform +itself having created all objects. If you import existing objects into Terraform, +be careful to import each remote object to only one Terraform resource address. +If you import the same object multiple times, Terraform may exhibit unwanted +behavior. For more information on this assumption, see +[the State section](/docs/state/). + ## Currently State Only The current implementation of Terraform import can only import resources diff --git a/website/docs/import/usage.html.md b/website/docs/import/usage.html.md index 16009f1c1..b449fb9b2 100644 --- a/website/docs/import/usage.html.md +++ b/website/docs/import/usage.html.md @@ -17,6 +17,14 @@ you can't yet point Terraform import to an entire collection of resources such as an AWS VPC and import all of it. This workflow will be improved in a future version of Terraform. +~> Warning: Terraform expects that each remote object it is managing will be +bound to only one resource address, which is normally guaranteed by Terraform +itself having created all objects. If you import existing objects into Terraform, +be careful to import each remote object to only one Terraform resource address. +If you import the same object multiple times, Terraform may exhibit unwanted +behavior. For more information on this assumption, see +[the State section](/docs/state/). + To import a resource, first write a resource block for it in your configuration, establishing the name by which it will be known to Terraform: diff --git a/website/docs/state/index.html.md b/website/docs/state/index.html.md index 90dec2951..d315089d5 100644 --- a/website/docs/state/index.html.md +++ b/website/docs/state/index.html.md @@ -21,6 +21,13 @@ infrastructure. Prior to any operation, Terraform does a [refresh](/docs/commands/refresh.html) to update the state with the real infrastructure. +The primary purpose of Terraform state is to store bindings between objects in +a remote system and resource instances declared in your configuration. +When Terraform creates a remote object in response to a change of configuration, +it will record the identity of that remote object against a particular +resource instance, and then potentially update or delete that object in +response to future configuration changes. + For more information on why Terraform requires state and why Terraform cannot function without state, please see the page [state purpose](/docs/state/purpose.html). @@ -37,15 +44,40 @@ insulates users from any format changes within the state itself. The Terraform project will keep the CLI working while the state format underneath it may shift. -Finally, the CLI manages backups for you automatically. If you make a mistake -modifying your state, the state CLI will always have a backup available for -you that you can restore. +Terraform expects a one-to-one mapping between configured resource instances +and remote objects. Normally that is guaranteed by Terraform being the one +to create each object and record its identity in the state, or to destroy +an object and then remove the binding for it. + +If you add or remove bindings in the state by other means, such as by importing +externally-created objects with `terraform import`, or by asking Terraform to +"forget" an existing object with `terraform state rm`, you'll then need to +ensure for yourself that this one-to-one rule is followed, such as by manually +deleting an object that you asked Terraform to "forget", or by re-importing it +to bind it to some other resource instance. ## Format -The state is in JSON format and Terraform will promise backwards compatibility -with the state file. The JSON format makes it easy to write tools around the -state if you want or to modify it by hand in the case of a Terraform bug. -The "version" field on the state contents allows us to transparently move -the format forward if we make modifications. +State snapshots are stored in JSON format and new Terraform versions are +generally backward compatible with state snapshots produced by earlier versions. +However, the state format is subject to change in new Terraform versions, so +if you build software that parses or modifies it directly you should expect +to perform ongoing maintenence of that software as the state format evolves +in new versions. +Alternatively, there are several integration points which produce JSON output +that is specifically intended for consumption by external software: + +* [The `terraform output` command](/commands/output.html) +has a `-json` option, for obtaining either the full set of root module output +values or a specific named output value from the latest state snapshot. +* [The `terraform show` command](/docs/commands/show.html) has a `-json` +option for inspecting the latest state snapshot in full, and also for +inspecting saved plan files which include a copy of the prior state at the +time the plan was made. + +A typical way to use these in situations where Terraform is running in +automation is to run them immediately after a successful `terraform apply` +to obtain a representation of the latest state snapshot, and then store that +result as an artifact associated with the automated run so that other software +can potentially consume it without needing to run Terraform itself. diff --git a/website/docs/state/purpose.html.md b/website/docs/state/purpose.html.md index e541490b6..fd0a5c911 100644 --- a/website/docs/state/purpose.html.md +++ b/website/docs/state/purpose.html.md @@ -34,6 +34,17 @@ support tags. Therefore, for mapping configuration to resources in the real world, Terraform uses its own state structure. +Terraform expects that each remote object is bound to only one resource +instance, which is normally guaranteed by Terraform being responsible for +creating the objects and recording their identities in the state. If you +instead import objects that were created outside of Terraform, you'll need +to check yourself that each distinct object is imported to only one resource +instance. + +If one remote object is bound to two or more resource instances then Terraform +may take unexpected actions against those objects, because the mapping from +configuration to the remote object state has become ambiguous. + ## Metadata Alongside the mappings between resources and remote objects, Terraform must