From e119b4b4ce50cda913f99fe9e23fc78e92ed2cf4 Mon Sep 17 00:00:00 2001 From: TAY TS Date: Sat, 22 May 2021 22:54:48 +0800 Subject: [PATCH 001/107] Update one.html.md Update typo --- website/docs/language/functions/one.html.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/language/functions/one.html.md b/website/docs/language/functions/one.html.md index 0fc5918ff..e4c60a27a 100644 --- a/website/docs/language/functions/one.html.md +++ b/website/docs/language/functions/one.html.md @@ -49,7 +49,7 @@ no instances were created. ## Relationship to the "Splat" Operator The Terraform language has a built-in operator `[*]`, known as -[the _splat_ operator](../expressions/splat.html), and one if its functions +[the _splat_ operator](../expressions/splat.html), and one of its functions is to translate a primitive value that might be null into a list of either zero or one elements: From 7fd6019b674206b58cf694a2671b5e1679514fa9 Mon Sep 17 00:00:00 2001 From: Bren Date: Wed, 9 Jun 2021 12:19:22 +0100 Subject: [PATCH 002/107] Update configuration.html.md (typo) Typo under Provider Configuration --- website/docs/language/providers/configuration.html.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/language/providers/configuration.html.md b/website/docs/language/providers/configuration.html.md index 6a7d8ad60..1ff269765 100644 --- a/website/docs/language/providers/configuration.html.md +++ b/website/docs/language/providers/configuration.html.md @@ -9,7 +9,7 @@ description: |- # Provider Configuration -Providers alow Terraform to interact with cloud providers, SaaS providers, and +Providers allow Terraform to interact with cloud providers, SaaS providers, and other APIs. Some providers require you to configure them with endpoint URLs, cloud regions, From f60de8cf36a6877a35c9168ccd04dfea0690d093 Mon Sep 17 00:00:00 2001 From: Kai Date: Thu, 10 Jun 2021 02:43:23 +0200 Subject: [PATCH 003/107] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 50d33ab78..c11e38bab 100644 --- a/README.md +++ b/README.md @@ -21,11 +21,11 @@ The key features of Terraform are: - **Change Automation**: Complex changesets can be applied to your infrastructure with minimal human interaction. With the previously mentioned execution plan and resource graph, you know exactly what Terraform will change and in what order, avoiding many possible human errors. -For more information, see the [introduction section](http://www.terraform.io/intro) of the Terraform website. +For more information, see the [introduction section](https://www.terraform.io/intro) of the Terraform website. Getting Started & Documentation ------------------------------- -Documentation is available on the [Terraform website](http://www.terraform.io): +Documentation is available on the [Terraform website](https://www.terraform.io): - [Intro](https://www.terraform.io/intro/index.html) - [Docs](https://www.terraform.io/docs/index.html) From a9cc4360f5f25b77c5669e1e1f47a831cf787c45 Mon Sep 17 00:00:00 2001 From: Felix Eyetan Date: Sun, 20 Jun 2021 19:58:57 +0100 Subject: [PATCH 004/107] Update configuration.html.md Minor update to documentation --- website/docs/language/providers/configuration.html.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/language/providers/configuration.html.md b/website/docs/language/providers/configuration.html.md index 6a7d8ad60..1ff269765 100644 --- a/website/docs/language/providers/configuration.html.md +++ b/website/docs/language/providers/configuration.html.md @@ -9,7 +9,7 @@ description: |- # Provider Configuration -Providers alow Terraform to interact with cloud providers, SaaS providers, and +Providers allow Terraform to interact with cloud providers, SaaS providers, and other APIs. Some providers require you to configure them with endpoint URLs, cloud regions, From 6993bad7540f67f3cafc8697e62a36c9d67bb28f Mon Sep 17 00:00:00 2001 From: tjabbour <85514185+tjabbour@users.noreply.github.com> Date: Mon, 21 Jun 2021 17:17:14 -0600 Subject: [PATCH 005/107] fix: Fix typo in provider documentation --- website/docs/language/providers/configuration.html.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/language/providers/configuration.html.md b/website/docs/language/providers/configuration.html.md index 6a7d8ad60..1ff269765 100644 --- a/website/docs/language/providers/configuration.html.md +++ b/website/docs/language/providers/configuration.html.md @@ -9,7 +9,7 @@ description: |- # Provider Configuration -Providers alow Terraform to interact with cloud providers, SaaS providers, and +Providers allow Terraform to interact with cloud providers, SaaS providers, and other APIs. Some providers require you to configure them with endpoint URLs, cloud regions, From 54a09b059fa4b48473896a3616279ee7171dcb60 Mon Sep 17 00:00:00 2001 From: Adrian Date: Thu, 1 Jul 2021 19:22:13 -0400 Subject: [PATCH 006/107] error_count # shouldn't it be true if the error count is zero error_count (number): A zero or positive whole number giving the count of errors Terraform detected. If valid is 'true' then error_count will always be zero, because it is the presence of errors that indicates that a configuration is invalid. --- website/docs/cli/commands/validate.html.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/cli/commands/validate.html.md b/website/docs/cli/commands/validate.html.md index b6210d697..583186e3d 100644 --- a/website/docs/cli/commands/validate.html.md +++ b/website/docs/cli/commands/validate.html.md @@ -71,7 +71,7 @@ stream. The top-level JSON object will have the following properties: `false` if it detected any errors. * `error_count` (number): A zero or positive whole number giving the count - of errors Terraform detected. If `valid` is `false` then `error_count` will + of errors Terraform detected. If `valid` is `true` then `error_count` will always be zero, because it is the presence of errors that indicates that a configuration is invalid. From 8525befc22363b22d345d86660d71070d5f1e90a Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Wed, 7 Jul 2021 12:58:28 -0400 Subject: [PATCH 007/107] Add description metadata to index page --- website/docs/language/index.html.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/docs/language/index.html.md b/website/docs/language/index.html.md index c370623fc..c958f17ea 100644 --- a/website/docs/language/index.html.md +++ b/website/docs/language/index.html.md @@ -1,6 +1,8 @@ --- layout: "language" page_title: "Overview - Configuration Language" +description: |- + An introduction to the Terraform Configuration Language that is used to declare resources in infrastructure as code. --- # Terraform Language Documentation From ab06843f1da867f92dab972852e64f95d55fcaca Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Wed, 7 Jul 2021 13:11:17 -0400 Subject: [PATCH 008/107] Add description metadata to files and directories --- website/docs/language/files/index.html.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/docs/language/files/index.html.md b/website/docs/language/files/index.html.md index 109c60f73..1175a7106 100644 --- a/website/docs/language/files/index.html.md +++ b/website/docs/language/files/index.html.md @@ -1,6 +1,8 @@ --- layout: "language" page_title: "Files and Directories - Configuration Language" +description: |- + An overview of how Terraform configuration files are named, organized, and stored as well as how Terraform modules are created and evaluated. --- # Files and Directories From f6b500379d1b8d90a22ec498ae47f388c88df6c3 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Wed, 7 Jul 2021 13:17:42 -0400 Subject: [PATCH 009/107] Update description metadata to include Terraform key word --- website/docs/language/files/override.html.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/website/docs/language/files/override.html.md b/website/docs/language/files/override.html.md index 334aa2eb5..505c1c1a3 100644 --- a/website/docs/language/files/override.html.md +++ b/website/docs/language/files/override.html.md @@ -3,8 +3,7 @@ layout: "language" page_title: "Override Files - Configuration Language" sidebar_current: "docs-config-override" description: |- - Override files allow additional settings to be merged into existing - configuration objects. + How Terraform override files merge additional settings into existing configuration objects. --- # Override Files From a62e2825c7bec17551a72c2b087db47dda19997a Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Wed, 7 Jul 2021 13:23:48 -0400 Subject: [PATCH 010/107] Add description metadata to syntax overview --- website/docs/language/syntax/index.html.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/docs/language/syntax/index.html.md b/website/docs/language/syntax/index.html.md index 83de5faaa..e05b2464d 100644 --- a/website/docs/language/syntax/index.html.md +++ b/website/docs/language/syntax/index.html.md @@ -1,6 +1,8 @@ --- layout: "language" page_title: "Syntax Overview - Configuration Language" +description: |- + An introduction to Terraform Configuration Language syntax for both the native and JSON variants as well as formatting conventions. --- # Syntax From 887b019761cdc6bdfe0111c41be5ac5819f3dd5a Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Wed, 7 Jul 2021 13:33:51 -0400 Subject: [PATCH 011/107] Fix capitalization on Terraform language --- website/docs/language/syntax/index.html.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/language/syntax/index.html.md b/website/docs/language/syntax/index.html.md index e05b2464d..d1bcbf350 100644 --- a/website/docs/language/syntax/index.html.md +++ b/website/docs/language/syntax/index.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "Syntax Overview - Configuration Language" description: |- - An introduction to Terraform Configuration Language syntax for both the native and JSON variants as well as formatting conventions. + An introduction to Terraform language syntax for both the native and JSON variants as well as formatting conventions. --- # Syntax From 5384aacb5ebf67a54bfa06906993d5475cab7152 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Wed, 7 Jul 2021 13:39:14 -0400 Subject: [PATCH 012/107] Update description metadata for key words --- website/docs/language/syntax/configuration.html.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/website/docs/language/syntax/configuration.html.md b/website/docs/language/syntax/configuration.html.md index e080ed540..1fa5fc48d 100644 --- a/website/docs/language/syntax/configuration.html.md +++ b/website/docs/language/syntax/configuration.html.md @@ -3,9 +3,7 @@ layout: "language" page_title: "Syntax - Configuration Language" sidebar_current: "docs-config-syntax" description: |- - The Terraform language has its own syntax, intended to combine declarative - structure with expressions in a way that is easy for humans to read and - understand. + Key constructs of the native Terraform language syntax, including identifiers, arguments, blocks, and comments. --- # Configuration Syntax From c33970bfa449df54c199d32808183975e6db6e7b Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Wed, 7 Jul 2021 14:02:23 -0400 Subject: [PATCH 013/107] Add description metadata to JSON syntax page --- website/docs/language/syntax/json.html.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/website/docs/language/syntax/json.html.md b/website/docs/language/syntax/json.html.md index ea9917021..4d80508d5 100644 --- a/website/docs/language/syntax/json.html.md +++ b/website/docs/language/syntax/json.html.md @@ -3,8 +3,7 @@ layout: "language" page_title: "JSON Configuration Syntax - Configuration Language" sidebar_current: "docs-config-syntax-json" description: |- - In addition to the native syntax that is most commonly used with Terraform, - the Terraform language can also be expressed in a JSON-compatible syntax. + Details about the JSON-compatible Terraform language syntax, including file structure, expression mapping, and blocks. --- # JSON Configuration Syntax From 08f1d6c9e0952631a8a24eb5db16e2b188659f0f Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Wed, 7 Jul 2021 14:05:27 -0400 Subject: [PATCH 014/107] Update description metadata for style page --- website/docs/language/syntax/style.html.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/website/docs/language/syntax/style.html.md b/website/docs/language/syntax/style.html.md index c7599bd07..bc9af1f08 100644 --- a/website/docs/language/syntax/style.html.md +++ b/website/docs/language/syntax/style.html.md @@ -3,9 +3,7 @@ layout: "language" page_title: "Style Conventions - Configuration Language" sidebar_current: "docs-config-style" description: |- - The Terraform language has some idiomatic style conventions, which we - recommend users always follow for consistency between files and modules - written by different teams. + Recommended formatting conventions for the Terraform language. --- # Style Conventions From 810543b997306ed930ab3e75c8e30f3881cd3a3e Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Wed, 7 Jul 2021 14:09:20 -0400 Subject: [PATCH 015/107] Add description metadata to resources overview page --- website/docs/language/resources/index.html.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/docs/language/resources/index.html.md b/website/docs/language/resources/index.html.md index 891202d34..cd343fc0f 100644 --- a/website/docs/language/resources/index.html.md +++ b/website/docs/language/resources/index.html.md @@ -1,6 +1,8 @@ --- layout: "language" page_title: "Resources Overview - Configuration Language" +description: |- + An introduction to the Terraform language resources element that is used to describe infrastructure objects. --- # Resources From 66dfb56d4f21af9465792f3f4fb5b8c38a6d13d0 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Wed, 7 Jul 2021 14:20:57 -0400 Subject: [PATCH 016/107] Update description metadata to include key words --- website/docs/language/resources/syntax.html.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/website/docs/language/resources/syntax.html.md b/website/docs/language/resources/syntax.html.md index 65d52537e..2c3e14c51 100644 --- a/website/docs/language/resources/syntax.html.md +++ b/website/docs/language/resources/syntax.html.md @@ -3,9 +3,7 @@ layout: "language" page_title: "Resources - Configuration Language" sidebar_current: "docs-config-resources" description: |- - Resources are the most important element in a Terraform configuration. - Each resource corresponds to an infrastructure object, such as a virtual - network or compute instance. + Details about Terraform resources, which correspond to infrastructure objects like virtual networks or compute instances. --- # Resource Blocks From e60e77c68fb9418d7bd15164da45216e256e4705 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Wed, 7 Jul 2021 14:29:03 -0400 Subject: [PATCH 017/107] Add description metadata to behavior page --- website/docs/language/resources/behavior.html.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/docs/language/resources/behavior.html.md b/website/docs/language/resources/behavior.html.md index 70c0e2da7..c2f7b3e0a 100644 --- a/website/docs/language/resources/behavior.html.md +++ b/website/docs/language/resources/behavior.html.md @@ -1,6 +1,8 @@ --- layout: "language" page_title: "Resource Behavior - Configuration Language" +description: |- + How Terraform uses resource blocks to create infrastructure objects as well as details about resource attributes and dependencies. --- # Resource Behavior From ddabca8c72366e329c26ac69646c9461d9b86b9e Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Wed, 7 Jul 2021 14:54:51 -0400 Subject: [PATCH 018/107] Add description metadata to depends_on page --- website/docs/language/meta-arguments/depends_on.html.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/docs/language/meta-arguments/depends_on.html.md b/website/docs/language/meta-arguments/depends_on.html.md index fb8a35cc6..bd7a5ea81 100644 --- a/website/docs/language/meta-arguments/depends_on.html.md +++ b/website/docs/language/meta-arguments/depends_on.html.md @@ -1,6 +1,8 @@ --- layout: "language" page_title: "The depends_on Meta-Argument - Configuration Language" +description: |- + The Terraform language `depends_on` meta-argument is used to handle hidden resource or module dependencies. --- # The `depends_on` Meta-Argument From 4a2a6e8b526c21b728a2f0391194167f6f1c4ea7 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Wed, 7 Jul 2021 14:59:20 -0400 Subject: [PATCH 019/107] Add description metadata to count and update depends_on --- website/docs/language/meta-arguments/count.html.md | 2 ++ website/docs/language/meta-arguments/depends_on.html.md | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/website/docs/language/meta-arguments/count.html.md b/website/docs/language/meta-arguments/count.html.md index 4e92bdb95..43fec1c6b 100644 --- a/website/docs/language/meta-arguments/count.html.md +++ b/website/docs/language/meta-arguments/count.html.md @@ -1,6 +1,8 @@ --- layout: "language" page_title: "The count Meta-Argument - Configuration Language" +description: |- + Use the Terraform language `count` meta-argument to efficiently manage nearly identical resources without writing a separate block for each one. --- # The `count` Meta-Argument diff --git a/website/docs/language/meta-arguments/depends_on.html.md b/website/docs/language/meta-arguments/depends_on.html.md index bd7a5ea81..8a23c69c7 100644 --- a/website/docs/language/meta-arguments/depends_on.html.md +++ b/website/docs/language/meta-arguments/depends_on.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "The depends_on Meta-Argument - Configuration Language" description: |- - The Terraform language `depends_on` meta-argument is used to handle hidden resource or module dependencies. + Use the Terraform language `depends_on` meta-argument to handle hidden resource or module dependencies. --- # The `depends_on` Meta-Argument From 96994d0b01865d463773f3d962f93607ec1dc856 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Wed, 7 Jul 2021 15:02:01 -0400 Subject: [PATCH 020/107] Add description metadata to for_each page --- website/docs/language/meta-arguments/for_each.html.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/docs/language/meta-arguments/for_each.html.md b/website/docs/language/meta-arguments/for_each.html.md index ea5b30004..d3f067b15 100644 --- a/website/docs/language/meta-arguments/for_each.html.md +++ b/website/docs/language/meta-arguments/for_each.html.md @@ -1,6 +1,8 @@ --- layout: "language" page_title: "The for_each Meta-Argument - Configuration Language" +description: |- + Use the Terraform language `for_each` meta-argument to efficiently manage similar resources without writing a separate block for each one. --- # The `for_each` Meta-Argument From 66103f273efd8fe7d23c5eef406d6abd181debc8 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Wed, 7 Jul 2021 15:05:02 -0400 Subject: [PATCH 021/107] Add description metadata to resource provider page --- website/docs/language/meta-arguments/resource-provider.html.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/docs/language/meta-arguments/resource-provider.html.md b/website/docs/language/meta-arguments/resource-provider.html.md index bdecf834c..71932298c 100644 --- a/website/docs/language/meta-arguments/resource-provider.html.md +++ b/website/docs/language/meta-arguments/resource-provider.html.md @@ -1,6 +1,8 @@ --- layout: "language" page_title: "The Resource provider Meta-Argument - Configuration Language" +description: |- + Use the Terraform language `provider` meta-argument to specify which provider configuration to use for a resource. --- # The Resource `provider` Meta-Argument From 6d0569ac4515d4429029edc8c785831d22584c98 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Wed, 7 Jul 2021 15:07:00 -0400 Subject: [PATCH 022/107] Add description metadata to lifecycle page --- website/docs/language/meta-arguments/lifecycle.html.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/docs/language/meta-arguments/lifecycle.html.md b/website/docs/language/meta-arguments/lifecycle.html.md index 4cbe0b78b..d505f9ab7 100644 --- a/website/docs/language/meta-arguments/lifecycle.html.md +++ b/website/docs/language/meta-arguments/lifecycle.html.md @@ -1,6 +1,8 @@ --- layout: "language" page_title: "The lifecycle Meta-Argument - Configuration Language" +description: |- + Use the Terraform language `lifecycle` meta-argument to customize resource behavior. --- # The `lifecycle` Meta-Argument From 2e25fd04c037951d487c3753c028524b2a0c61ec Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Wed, 7 Jul 2021 15:10:14 -0400 Subject: [PATCH 023/107] Add description metadata to provisioners index page --- website/docs/language/resources/provisioners/index.html.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/docs/language/resources/provisioners/index.html.md b/website/docs/language/resources/provisioners/index.html.md index c9fef64bb..b03702066 100644 --- a/website/docs/language/resources/provisioners/index.html.md +++ b/website/docs/language/resources/provisioners/index.html.md @@ -1,6 +1,8 @@ --- layout: "language" page_title: "Provisioners Overview - Configuration Language" +description: |- + An introduction to Terraform provisioners that prepare infrastructure objects for service. --- # Provisioners From 6f8774a8ed7f39275d6754400116b22609969629 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Wed, 7 Jul 2021 17:24:58 -0400 Subject: [PATCH 024/107] Add Terraform to description metadata for SEO --- website/docs/language/resources/provisioners/syntax.html.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/language/resources/provisioners/syntax.html.md b/website/docs/language/resources/provisioners/syntax.html.md index 3a8eb95eb..188f65ef6 100644 --- a/website/docs/language/resources/provisioners/syntax.html.md +++ b/website/docs/language/resources/provisioners/syntax.html.md @@ -3,7 +3,7 @@ layout: "language" page_title: "Provisioners" sidebar_current: "docs-provisioners" description: |- - Provisioners are used to execute scripts on a local or remote machine as part of resource creation or destruction. + How to use provisioners in Terraform to execute scripts on a local or remote machine as part of resource creation or destruction. --- # Provisioners From f25d993b47f5c7c222dfaff55bddf5760b4807c9 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Wed, 7 Jul 2021 17:34:03 -0400 Subject: [PATCH 025/107] Update description metadata to include key words --- website/docs/language/resources/provisioners/connection.html.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/language/resources/provisioners/connection.html.md b/website/docs/language/resources/provisioners/connection.html.md index 698ddfad7..f86ebb6d5 100644 --- a/website/docs/language/resources/provisioners/connection.html.md +++ b/website/docs/language/resources/provisioners/connection.html.md @@ -3,7 +3,7 @@ layout: "language" page_title: "Provisioner Connection Settings" sidebar_current: "docs-provisioners-connection" description: |- - Managing connection defaults for SSH and WinRM using the `connection` block. + Managing provisioner connection defaults for SSH and WinRM using the `connection` block in Terraform language. --- # Provisioner Connection Settings From 493d4b8dc80e13f13f5fdfbdd3c01218155145cc Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Wed, 7 Jul 2021 17:37:19 -0400 Subject: [PATCH 026/107] Update description metadata --- .../docs/language/resources/provisioners/null_resource.html.md | 3 +-- website/docs/language/resources/provisioners/syntax.html.md | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/website/docs/language/resources/provisioners/null_resource.html.md b/website/docs/language/resources/provisioners/null_resource.html.md index 7fb94a4e8..49f69bc41 100644 --- a/website/docs/language/resources/provisioners/null_resource.html.md +++ b/website/docs/language/resources/provisioners/null_resource.html.md @@ -3,8 +3,7 @@ layout: "language" page_title: "Provisioners Without a Resource" sidebar_current: "docs-provisioners-null-resource" description: |- - The `null_resource` is a resource allows you to configure provisioners that - are not directly associated with a single existing resource. + Using 'null_resource' to configure Terraform provisioners that are not directly associated with a single existing resource. --- # Provisioners Without a Resource diff --git a/website/docs/language/resources/provisioners/syntax.html.md b/website/docs/language/resources/provisioners/syntax.html.md index 188f65ef6..3759b1db2 100644 --- a/website/docs/language/resources/provisioners/syntax.html.md +++ b/website/docs/language/resources/provisioners/syntax.html.md @@ -3,7 +3,7 @@ layout: "language" page_title: "Provisioners" sidebar_current: "docs-provisioners" description: |- - How to use provisioners in Terraform to execute scripts on a local or remote machine as part of resource creation or destruction. + Using provisioners in Terraform to execute scripts on a local or remote machine as part of resource creation or destruction. --- # Provisioners From f5c463c27e6467d91e6cf1aaef7f77302f56bd69 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 9 Jul 2021 10:30:35 -0400 Subject: [PATCH 027/107] Update broken link oon provisioners connection page --- website/docs/language/resources/provisioners/connection.html.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/language/resources/provisioners/connection.html.md b/website/docs/language/resources/provisioners/connection.html.md index f86ebb6d5..d173320e7 100644 --- a/website/docs/language/resources/provisioners/connection.html.md +++ b/website/docs/language/resources/provisioners/connection.html.md @@ -133,7 +133,7 @@ block would create a dependency cycle. * `insecure` - Set to `true` to not validate the HTTPS certificate chain. -* `use_ntlm` - Set to `true` to use NTLM authentication, rather than default (basic authentication), removing the requirement for basic authentication to be enabled within the target guest. Further reading for remote connection authentication can be found [here](https://msdn.microsoft.com/en-us/library/aa384295(v=vs.85).aspx). +* `use_ntlm` - Set to `true` to use NTLM authentication, rather than default (basic authentication), removing the requirement for basic authentication to be enabled within the target guest. Further reading for remote connection authentication can be found [here](https://docs.microsoft.com/en-us/windows/win32/winrm/authentication-for-remote-connections?redirectedfrom=MSDN). * `cacert` - The CA certificate to validate against. From 134170c1216341ebc110e6cb67d79ab2877f1c7a Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 9 Jul 2021 10:32:17 -0400 Subject: [PATCH 028/107] Fixing broken link on syntax page --- website/docs/language/resources/provisioners/syntax.html.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/language/resources/provisioners/syntax.html.md b/website/docs/language/resources/provisioners/syntax.html.md index 3759b1db2..388f9e01f 100644 --- a/website/docs/language/resources/provisioners/syntax.html.md +++ b/website/docs/language/resources/provisioners/syntax.html.md @@ -102,7 +102,7 @@ for launching specific configuration management products. We strongly recommend not using these, and instead running system configuration steps during a custom image build process. For example, -[HashiCorp Packer](https://packer.io/) offers a similar complement of +[HashiCorp Packer](https://www.packer.io/) offers a similar complement of configuration management provisioners and can run their installation steps during a separate build process, before creating a system disk image that you can deploy many times. From bca3957e1730bdcf82735a5f9833e652e0931846 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 9 Jul 2021 10:53:37 -0400 Subject: [PATCH 029/107] Update description metadata for input variables --- website/docs/language/values/variables.html.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/website/docs/language/values/variables.html.md b/website/docs/language/values/variables.html.md index bad454533..e48a416af 100644 --- a/website/docs/language/values/variables.html.md +++ b/website/docs/language/values/variables.html.md @@ -3,9 +3,7 @@ layout: "language" page_title: "Input Variables - Configuration Language" sidebar_current: "docs-config-variables" description: |- - Input variables allow you to customize Terraform configuration according to - set parameters. Learn about input variable syntax, including how to declare, - define, and reference variables in root and child modules. + Using input variables to customize Terraform configurations, including how to declare, define, and reference variables in root and child modules. --- # Input Variables From d107b46270ab493c42fd7bcc54ee9dd70fdc8533 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 9 Jul 2021 11:01:32 -0400 Subject: [PATCH 030/107] Make description metadata more concise --- website/docs/language/providers/index.html.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/website/docs/language/providers/index.html.md b/website/docs/language/providers/index.html.md index 648224b9c..f2a7b0a7e 100644 --- a/website/docs/language/providers/index.html.md +++ b/website/docs/language/providers/index.html.md @@ -2,9 +2,7 @@ layout: "language" page_title: "Providers - Configuration Language" description: |- - Terraform providers are plugins that allow Terraform to create resources and - use data sources from services, cloud providers, and other APIs. Read about - how to discover, install, and use providers. + An overview of how to install and use providers, Terraform plugins that interact with services, cloud providers, and other APIs. --- # Providers @@ -12,7 +10,7 @@ description: |- > **Hands-on:** Try the [Perform CRUD Operations with Providers](https://learn.hashicorp.com/tutorials/terraform/provider-use?in=terraform/configuration-language&utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial on HashiCorp Learn. Terraform relies on plugins called "providers" to interact with cloud providers, -SaaS providers, and other APIs. +SaaS providers, and other APIs. Terraform configurations must declare which providers they require so that Terraform can install and use them. Additionally, some providers require From 62b444504d5edf8a945d9a510e2334119691912e Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 9 Jul 2021 11:07:37 -0400 Subject: [PATCH 031/107] Add description metadata to provider requirements --- website/docs/language/providers/requirements.html.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/docs/language/providers/requirements.html.md b/website/docs/language/providers/requirements.html.md index 90e4cd8a4..6366bb557 100644 --- a/website/docs/language/providers/requirements.html.md +++ b/website/docs/language/providers/requirements.html.md @@ -1,6 +1,8 @@ --- layout: "language" page_title: "Provider Requirements - Configuration Language" +description: |- + Declaring providers in your module configuration so that Terraform can install them. --- # Provider Requirements From 62b11f02e2108e90c440e5661daf9357ac5a5dd9 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 9 Jul 2021 11:15:10 -0400 Subject: [PATCH 032/107] Make metadata description more concise --- website/docs/language/providers/configuration.html.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/website/docs/language/providers/configuration.html.md b/website/docs/language/providers/configuration.html.md index 6a7d8ad60..6641271a1 100644 --- a/website/docs/language/providers/configuration.html.md +++ b/website/docs/language/providers/configuration.html.md @@ -3,8 +3,7 @@ layout: "language" page_title: "Provider Configuration - Configuration Language" sidebar_current: "docs-config-providers" description: |- - Learn how to configure provider settings and alias providers to use multiple - different provider configurations in the same Terraform project. + Configuring Terraform providers, including how to use the `alias` meta-argument to specify multiple configurations for a single provider. --- # Provider Configuration From 9dc008fa1062f09436d790e0fd241feeb99aaf1c Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 9 Jul 2021 11:25:55 -0400 Subject: [PATCH 033/107] Add metadata description to dependency lock file page --- website/docs/language/dependency-lock.html.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/docs/language/dependency-lock.html.md b/website/docs/language/dependency-lock.html.md index 2a3eda96d..e3f7313f9 100644 --- a/website/docs/language/dependency-lock.html.md +++ b/website/docs/language/dependency-lock.html.md @@ -1,6 +1,8 @@ --- layout: "language" page_title: "Dependency Lock File (.terraform.lock.hcl) - Configuration Language" +description: |- + Details about the dependency lock file `.teraform.lock.hcl` that Terraform uses to track and select provider versions. --- # Dependency Lock File From fabd5abf2cfe15a266bfa4826deb92b07607a37a Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 9 Jul 2021 11:30:13 -0400 Subject: [PATCH 034/107] Make description metadata shorter --- website/docs/providers/index.html.markdown | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/website/docs/providers/index.html.markdown b/website/docs/providers/index.html.markdown index 2656c9784..f3e742b32 100644 --- a/website/docs/providers/index.html.markdown +++ b/website/docs/providers/index.html.markdown @@ -3,8 +3,7 @@ layout: "language" page_title: "Provider Documentation" sidebar_current: "docs-providers" description: |- - Terraform's resources are implemented by provider plugins. The Terraform - Registry is the main directory of publicly available Terraform providers. + Pointers to documentation for Terraform provider plugins, including the Terraform Registry. --- # Provider Documentation From 07accd7a386bc84fb213e8b019b9a92030e71c8e Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 9 Jul 2021 11:34:02 -0400 Subject: [PATCH 035/107] Add page metadata to variables and outputs overview --- website/docs/language/values/index.html.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/docs/language/values/index.html.md b/website/docs/language/values/index.html.md index e73972c41..a32ef6b39 100644 --- a/website/docs/language/values/index.html.md +++ b/website/docs/language/values/index.html.md @@ -1,6 +1,8 @@ --- layout: "language" page_title: "Variables and Outputs" +description: |- + An overview of input variables, output values, and local values in Terraform language. --- # Variables and Outputs From 14d6e0dea9b99caab22153c741bb9278e6f4056a Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 9 Jul 2021 11:37:01 -0400 Subject: [PATCH 036/107] Add Terraform key work to description metadata --- website/docs/language/values/locals.html.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/website/docs/language/values/locals.html.md b/website/docs/language/values/locals.html.md index ad755b264..e4639ae0d 100644 --- a/website/docs/language/values/locals.html.md +++ b/website/docs/language/values/locals.html.md @@ -3,8 +3,7 @@ layout: "language" page_title: "Local Values - Configuration Language" sidebar_current: "docs-config-locals" description: |- - Local values assign a name to an expression that can then be used multiple times - within a module. + Local values assign a name to an expression that can be used multiple times within a Terraform module. --- # Local Values From adf4dbdf84df2da976c0f2166e1897faec2fa948 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 9 Jul 2021 11:45:42 -0400 Subject: [PATCH 037/107] Update description metadata --- website/docs/language/data-sources/index.html.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/language/data-sources/index.html.md b/website/docs/language/data-sources/index.html.md index 35af54b4e..794b7dd23 100644 --- a/website/docs/language/data-sources/index.html.md +++ b/website/docs/language/data-sources/index.html.md @@ -3,13 +3,13 @@ layout: "language" page_title: "Data Sources - Configuration Language" sidebar_current: "docs-config-data-sources" description: |- - Data sources allow data to be fetched or computed for use elsewhere in Terraform configuration. + Using Data sources to give Terraform access to data from APIs or other Terraform configurations. --- # Data Sources _Data sources_ allow Terraform use information defined outside of Terraform, -defined by another separate Terraform configuration, or modified by functions. +defined by another separate Terraform configuration, or modified by functions. > **Hands-on:** Try the [Query Data Sources](https://learn.hashicorp.com/tutorials/terraform/data-sources) tutorial on HashiCorp Learn. From f4f8d7a6c59c8ccfde64657ab4ae3b0c7eb2edb9 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 9 Jul 2021 11:50:19 -0400 Subject: [PATCH 038/107] Change use to using for consistency with other docs --- website/docs/language/meta-arguments/count.html.md | 2 +- website/docs/language/meta-arguments/depends_on.html.md | 2 +- website/docs/language/meta-arguments/for_each.html.md | 2 +- website/docs/language/meta-arguments/lifecycle.html.md | 2 +- website/docs/language/meta-arguments/resource-provider.html.md | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/website/docs/language/meta-arguments/count.html.md b/website/docs/language/meta-arguments/count.html.md index 43fec1c6b..35380e929 100644 --- a/website/docs/language/meta-arguments/count.html.md +++ b/website/docs/language/meta-arguments/count.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "The count Meta-Argument - Configuration Language" description: |- - Use the Terraform language `count` meta-argument to efficiently manage nearly identical resources without writing a separate block for each one. + Using the Terraform language `count` meta-argument to efficiently manage nearly identical resources without writing a separate block for each one. --- # The `count` Meta-Argument diff --git a/website/docs/language/meta-arguments/depends_on.html.md b/website/docs/language/meta-arguments/depends_on.html.md index 8a23c69c7..e6ee5f6e7 100644 --- a/website/docs/language/meta-arguments/depends_on.html.md +++ b/website/docs/language/meta-arguments/depends_on.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "The depends_on Meta-Argument - Configuration Language" description: |- - Use the Terraform language `depends_on` meta-argument to handle hidden resource or module dependencies. + Using the Terraform language `depends_on` meta-argument to handle hidden resource or module dependencies. --- # The `depends_on` Meta-Argument diff --git a/website/docs/language/meta-arguments/for_each.html.md b/website/docs/language/meta-arguments/for_each.html.md index d3f067b15..dee916bfd 100644 --- a/website/docs/language/meta-arguments/for_each.html.md +++ b/website/docs/language/meta-arguments/for_each.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "The for_each Meta-Argument - Configuration Language" description: |- - Use the Terraform language `for_each` meta-argument to efficiently manage similar resources without writing a separate block for each one. + Using the Terraform language `for_each` meta-argument to efficiently manage similar resources without writing a separate block for each one. --- # The `for_each` Meta-Argument diff --git a/website/docs/language/meta-arguments/lifecycle.html.md b/website/docs/language/meta-arguments/lifecycle.html.md index d505f9ab7..69423f175 100644 --- a/website/docs/language/meta-arguments/lifecycle.html.md +++ b/website/docs/language/meta-arguments/lifecycle.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "The lifecycle Meta-Argument - Configuration Language" description: |- - Use the Terraform language `lifecycle` meta-argument to customize resource behavior. + Using the Terraform language `lifecycle` meta-argument to customize resource behavior. --- # The `lifecycle` Meta-Argument diff --git a/website/docs/language/meta-arguments/resource-provider.html.md b/website/docs/language/meta-arguments/resource-provider.html.md index 71932298c..6be261947 100644 --- a/website/docs/language/meta-arguments/resource-provider.html.md +++ b/website/docs/language/meta-arguments/resource-provider.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "The Resource provider Meta-Argument - Configuration Language" description: |- - Use the Terraform language `provider` meta-argument to specify which provider configuration to use for a resource. + Using the Terraform language `provider` meta-argument to specify which provider configuration to use for a resource. --- # The Resource `provider` Meta-Argument From 4044fe30d38f538310e1d0e521db9376dd3f33e9 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 9 Jul 2021 11:59:38 -0400 Subject: [PATCH 039/107] Add description metadata to modules overview page --- website/docs/language/modules/index.html.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/docs/language/modules/index.html.md b/website/docs/language/modules/index.html.md index 2aef04ab3..7feca688b 100644 --- a/website/docs/language/modules/index.html.md +++ b/website/docs/language/modules/index.html.md @@ -1,6 +1,8 @@ --- layout: "language" page_title: "Modules Overview - Configuration Language" +description: |- + An overview of Terraform modules, containers for multiple resources that are used together in a configuration. --- # Modules From e348477c793f6a050a69534e511e67d68d38b023 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 9 Jul 2021 12:08:48 -0400 Subject: [PATCH 040/107] Add description metadata to module sources --- website/docs/language/modules/sources.html.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/language/modules/sources.html.md b/website/docs/language/modules/sources.html.md index fd5cce8d8..d6423c25d 100644 --- a/website/docs/language/modules/sources.html.md +++ b/website/docs/language/modules/sources.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "Module Sources" sidebar_current: "docs-modules-sources" -description: The source argument within a module block specifies the location of the source code of a child module. +description: Using `source` in Terraform modules to specify child modules in locations like GitHub, the Terraform Registry, Bitbucket, Git, Mercurial, S3, and GCS. --- # Module Sources @@ -36,7 +36,7 @@ types, as listed below. * [S3 buckets](#s3-bucket) * [GCS buckets](#gcs-bucket) - + * [Modules in Package Sub-directories](#modules-in-package-sub-directories) Each of these is described in the following sections. Module source addresses From 3baddbef0e0286d73a2606a887a55aca1c8719d0 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 9 Jul 2021 12:14:58 -0400 Subject: [PATCH 041/107] Add description metadata to creating modules pagey --- website/docs/language/modules/develop/index.html.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/language/modules/develop/index.html.md b/website/docs/language/modules/develop/index.html.md index 5e71edd59..d7b2f3bae 100644 --- a/website/docs/language/modules/develop/index.html.md +++ b/website/docs/language/modules/develop/index.html.md @@ -3,7 +3,7 @@ layout: "language" page_title: "Creating Modules" sidebar_current: "docs-modules" description: |- - A module is a container for multiple resources that are used together. + An introduction to creating modules, containers for multiple resources that are used together in a Terraform configuration. --- # Creating Modules From d9f7ce19fe74f01f28621ee25143d497a7f0f64a Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 9 Jul 2021 15:17:18 -0400 Subject: [PATCH 042/107] Add description metadata to conditionals page --- website/docs/language/expressions/conditionals.html.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/docs/language/expressions/conditionals.html.md b/website/docs/language/expressions/conditionals.html.md index cd7bc0129..9b63d3af6 100644 --- a/website/docs/language/expressions/conditionals.html.md +++ b/website/docs/language/expressions/conditionals.html.md @@ -1,6 +1,8 @@ --- layout: "language" page_title: "Conditional Expressions - Configuration Language" +description: |- + Using conditional expressions in Terraform configurations. --- # Conditional Expressions From df160961416456e76ba196b864b651244e922897 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 9 Jul 2021 15:28:28 -0400 Subject: [PATCH 043/107] Add description metadata to dynamic blocks, types, and module providers --- website/docs/language/expressions/dynamic-blocks.html.md | 2 ++ website/docs/language/expressions/types.html.md | 2 ++ website/docs/language/meta-arguments/module-providers.html.md | 2 ++ 3 files changed, 6 insertions(+) diff --git a/website/docs/language/expressions/dynamic-blocks.html.md b/website/docs/language/expressions/dynamic-blocks.html.md index 83551060d..6d672c0c5 100644 --- a/website/docs/language/expressions/dynamic-blocks.html.md +++ b/website/docs/language/expressions/dynamic-blocks.html.md @@ -1,6 +1,8 @@ --- layout: "language" page_title: "Dynamic Blocks - Configuration Language" +description: |- + Using dynamic blocks in Terraform configurations. --- diff --git a/website/docs/language/expressions/types.html.md b/website/docs/language/expressions/types.html.md index c197a7f8e..4fe5efab0 100644 --- a/website/docs/language/expressions/types.html.md +++ b/website/docs/language/expressions/types.html.md @@ -1,6 +1,8 @@ --- layout: "language" page_title: "Types and Values - Configuration Language" +description: |- + An overview of values and their types in the Terraform language. --- # Types and Values diff --git a/website/docs/language/meta-arguments/module-providers.html.md b/website/docs/language/meta-arguments/module-providers.html.md index 993b9f23f..d5af20f25 100644 --- a/website/docs/language/meta-arguments/module-providers.html.md +++ b/website/docs/language/meta-arguments/module-providers.html.md @@ -1,6 +1,8 @@ --- layout: "language" page_title: "The Module providers Meta-Argument - Configuration Language" +description: |- + Using the Terraform language `providers` meta-argument to specify which provider configurations from a parent module are available inside a child module. --- # The Module `providers` Meta-Argument From 2718d2addcdfc634001dcabc5501b20cccd2cf01 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 9 Jul 2021 15:32:25 -0400 Subject: [PATCH 044/107] Add description metadata to module block page --- website/docs/language/modules/syntax.html.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/language/modules/syntax.html.md b/website/docs/language/modules/syntax.html.md index 9bbf78d9f..58ac14539 100644 --- a/website/docs/language/modules/syntax.html.md +++ b/website/docs/language/modules/syntax.html.md @@ -3,7 +3,7 @@ layout: "language" page_title: "Modules - Configuration Language" sidebar_current: "docs-config-modules" description: |- - Modules allow multiple resources to be grouped together and encapsulated. + Calling one module from another in Terraform configurations. --- # Module Blocks From 7dba0e511f92e16bac204894d26ea688dac933cc Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 9 Jul 2021 15:40:05 -0400 Subject: [PATCH 045/107] Add description metadata to remaining expressions pages --- website/docs/language/expressions/for.html.md | 2 ++ website/docs/language/expressions/function-calls.html.md | 2 ++ website/docs/language/expressions/index.html.md | 2 ++ website/docs/language/expressions/operators.html.md | 2 ++ website/docs/language/expressions/references.html.md | 2 ++ website/docs/language/expressions/splat.html.md | 2 ++ website/docs/language/expressions/strings.html.md | 2 ++ website/docs/language/expressions/version-constraints.html.md | 2 ++ 8 files changed, 16 insertions(+) diff --git a/website/docs/language/expressions/for.html.md b/website/docs/language/expressions/for.html.md index c62d5fe4f..c34b1197d 100644 --- a/website/docs/language/expressions/for.html.md +++ b/website/docs/language/expressions/for.html.md @@ -1,6 +1,8 @@ --- layout: "language" page_title: "For Expressions - Configuration Language" +description: |- + Using `for` expressions in Terraform configurations. --- # `for` Expressions diff --git a/website/docs/language/expressions/function-calls.html.md b/website/docs/language/expressions/function-calls.html.md index 26e230350..eb526fa65 100644 --- a/website/docs/language/expressions/function-calls.html.md +++ b/website/docs/language/expressions/function-calls.html.md @@ -1,6 +1,8 @@ --- layout: "language" page_title: "Function Calls - Configuration Language" +description: |- + Using function calls in Terraform configurations. --- # Function Calls diff --git a/website/docs/language/expressions/index.html.md b/website/docs/language/expressions/index.html.md index 5a6a18a0f..cdf1dc5c1 100644 --- a/website/docs/language/expressions/index.html.md +++ b/website/docs/language/expressions/index.html.md @@ -1,6 +1,8 @@ --- layout: "language" page_title: "Expressions - Configuration Language" +description: |- + An overview of expressions used to compute values in in Terraform configurations. --- # Expressions diff --git a/website/docs/language/expressions/operators.html.md b/website/docs/language/expressions/operators.html.md index 542232680..0f1dff2cc 100644 --- a/website/docs/language/expressions/operators.html.md +++ b/website/docs/language/expressions/operators.html.md @@ -1,6 +1,8 @@ --- layout: "language" page_title: "Operators - Configuration Language" +description: |- + Using operators in Terraform configurations. --- # Arithmetic and Logical Operators diff --git a/website/docs/language/expressions/references.html.md b/website/docs/language/expressions/references.html.md index f69420f92..100eb57af 100644 --- a/website/docs/language/expressions/references.html.md +++ b/website/docs/language/expressions/references.html.md @@ -1,6 +1,8 @@ --- layout: "language" page_title: "References to Values - Configuration Language" +description: |- + Using references to values in Terraform configurations. --- # References to Named Values diff --git a/website/docs/language/expressions/splat.html.md b/website/docs/language/expressions/splat.html.md index 731aa767f..a9eb259b6 100644 --- a/website/docs/language/expressions/splat.html.md +++ b/website/docs/language/expressions/splat.html.md @@ -1,6 +1,8 @@ --- layout: "language" page_title: "Splat Expressions - Configuration Language" +description: |- + Using splat expressions in Terraform configurations. --- # Splat Expressions diff --git a/website/docs/language/expressions/strings.html.md b/website/docs/language/expressions/strings.html.md index 72cd0bba0..bbf363b63 100644 --- a/website/docs/language/expressions/strings.html.md +++ b/website/docs/language/expressions/strings.html.md @@ -1,6 +1,8 @@ --- layout: "language" page_title: "Strings and Templates - Configuration Language" +description: |- + Using strings and templates in Terraform configurations. --- # Strings and Templates diff --git a/website/docs/language/expressions/version-constraints.html.md b/website/docs/language/expressions/version-constraints.html.md index 0f7ebba54..1c462c20b 100644 --- a/website/docs/language/expressions/version-constraints.html.md +++ b/website/docs/language/expressions/version-constraints.html.md @@ -1,6 +1,8 @@ --- layout: "language" page_title: "Version Constraints - Configuration Language" +description: |- + Using version constraints in Terraform configurations. --- # Version Constraints From 952cb331037067965e4f18932b2355988fc0ed06 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 9 Jul 2021 15:42:58 -0400 Subject: [PATCH 046/107] Add description metadata to functions overview page --- website/docs/language/functions/index.html.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/website/docs/language/functions/index.html.md b/website/docs/language/functions/index.html.md index f062b32a7..2da4a6cb9 100644 --- a/website/docs/language/functions/index.html.md +++ b/website/docs/language/functions/index.html.md @@ -3,8 +3,7 @@ layout: "language" page_title: "Functions - Configuration Language" sidebar_current: "docs-config-functions" description: |- - The Terraform language has a number of built-in functions that can be called - from within expressions to transform and combine values. + An introduction to functions in the Terraform language that can transform and combine values. --- # Built-in Functions From a37fd2f5f794057a01a80d7e02af34fc064da23e Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 9 Jul 2021 15:46:07 -0400 Subject: [PATCH 047/107] Upate description metadata on terraform settings overview --- website/docs/language/settings/index.html.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/website/docs/language/settings/index.html.md b/website/docs/language/settings/index.html.md index b3b82a3aa..50c5e9cf7 100644 --- a/website/docs/language/settings/index.html.md +++ b/website/docs/language/settings/index.html.md @@ -3,8 +3,7 @@ layout: "language" page_title: "Terraform Settings - Configuration Language" sidebar_current: "docs-config-terraform" description: |- - The "terraform" configuration section is used to configure some behaviors - of Terraform itself. + Using the `terraform` block type to configure Terraform behavior. --- # Terraform Settings From 69ebfd6f037f8d51709770cc36d266bb86cf950d Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 9 Jul 2021 15:56:12 -0400 Subject: [PATCH 048/107] Add/update description metadata on backend and state overview pages --- website/docs/language/settings/backends/index.html.md | 2 ++ website/docs/language/state/index.html.md | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/website/docs/language/settings/backends/index.html.md b/website/docs/language/settings/backends/index.html.md index 6e477c5ef..ce78a4d2d 100644 --- a/website/docs/language/settings/backends/index.html.md +++ b/website/docs/language/settings/backends/index.html.md @@ -1,6 +1,8 @@ --- layout: "language" page_title: "Backend Overview - Configuration Language" +description: |- + An introduction to Terraform configuration backends. --- # Backends diff --git a/website/docs/language/state/index.html.md b/website/docs/language/state/index.html.md index 071cee81e..4e225913f 100644 --- a/website/docs/language/state/index.html.md +++ b/website/docs/language/state/index.html.md @@ -3,7 +3,7 @@ layout: "language" page_title: "State" sidebar_current: "docs-state" description: |- - Terraform must store state about your managed infrastructure and configuration. This state is used by Terraform to map real world resources to your configuration, keep track of metadata, and to improve performance for large infrastructures. + An introduction to state, information that Terraform uses to map resources to a configuration, track metadata, and improve performance. --- # State From eadbb7cd1377bc64b1e7c6b49a34426bdee30219 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 9 Jul 2021 17:16:41 -0400 Subject: [PATCH 049/107] Remove temporary providers doc reference --- website/docs/providers/index.html.markdown | 33 +++------------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/website/docs/providers/index.html.markdown b/website/docs/providers/index.html.markdown index f3e742b32..04d0f2728 100644 --- a/website/docs/providers/index.html.markdown +++ b/website/docs/providers/index.html.markdown @@ -8,36 +8,11 @@ description: |- # Provider Documentation -Every Terraform provider has its own documentation, describing its resource -types and their arguments. - -The [Terraform Registry](https://registry.terraform.io/browse/providers) is the -main home for provider documentation. When viewing a provider's page on the -Terraform Registry, you can click the "Documentation" link in the header to -browse its documentation. - -Provider documentation in the Registry is versioned; you can use the version -menu in the header to change which version you're viewing. +## Find Provider Docs +Every Terraform provider has its own documentation that describes its resource +types and their arguments available on the [Terraform Registry](https://registry.terraform.io/browse/providers) +## Write Provider Docs Learn more about writing, generating, and rendering provider documentation in the [provider publishing documentation](/docs/registry/providers/docs.html). -## Temporary Provider Documentation - -The following providers will be published on the Terraform Registry soon, but -aren't quite ready. Until they're published, their documentation is available at -the links below: - -- [Avi Vantage](/docs/providers/avi/index.html) -- [Chef](/docs/providers/chef/index.html) -- [Cobbler](/docs/providers/cobbler/index.html) -- [Genymotion](/docs/providers/genymotion/index.html) -- [Infoblox](/docs/providers/infoblox/index.html) -- [MySQL](/docs/providers/mysql/index.html) -- [Rubrik](/docs/providers/rubrik/index.html) -- [Rundeck](/docs/providers/rundeck/index.html) - -## Useful tools - -- [Doc preview tool](https://registry.terraform.io/tools/doc-preview) -- [terraform-plugin-docs](https://github.com/hashicorp/terraform-plugin-docs) From 5b187a16666812207bf766d99e86dd8424dbe819 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 9 Jul 2021 17:24:21 -0400 Subject: [PATCH 050/107] Update language on provider docs page --- website/docs/providers/index.html.markdown | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/website/docs/providers/index.html.markdown b/website/docs/providers/index.html.markdown index 04d0f2728..9872df783 100644 --- a/website/docs/providers/index.html.markdown +++ b/website/docs/providers/index.html.markdown @@ -9,8 +9,7 @@ description: |- # Provider Documentation ## Find Provider Docs -Every Terraform provider has its own documentation that describes its resource -types and their arguments available on the [Terraform Registry](https://registry.terraform.io/browse/providers) +Every Terraform provider has its own documentation on the [Terraform Registry](https://registry.terraform.io/browse/providers) that describes its resource types and their arguments. ## Write Provider Docs Learn more about writing, generating, and rendering provider documentation From 6cf2ad27a7af25eecb7ef862b57169f66ff678f6 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 9 Jul 2021 17:26:30 -0400 Subject: [PATCH 051/107] Fix typo in description on expressions overview page --- website/docs/language/expressions/index.html.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/language/expressions/index.html.md b/website/docs/language/expressions/index.html.md index cdf1dc5c1..2923d5d88 100644 --- a/website/docs/language/expressions/index.html.md +++ b/website/docs/language/expressions/index.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "Expressions - Configuration Language" description: |- - An overview of expressions used to compute values in in Terraform configurations. + An overview of expressions used to compute values in Terraform configurations. --- # Expressions From 12d1706562054479358282da28f6bef55f405faf Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Tue, 13 Jul 2021 17:23:07 -0400 Subject: [PATCH 052/107] Update data sources metadata to remove ing and include more detailXy --- website/docs/language/data-sources/index.html.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/language/data-sources/index.html.md b/website/docs/language/data-sources/index.html.md index 794b7dd23..ebc21c7ee 100644 --- a/website/docs/language/data-sources/index.html.md +++ b/website/docs/language/data-sources/index.html.md @@ -3,12 +3,12 @@ layout: "language" page_title: "Data Sources - Configuration Language" sidebar_current: "docs-config-data-sources" description: |- - Using Data sources to give Terraform access to data from APIs or other Terraform configurations. +Data sources allow Terraform to use external data, function output, and data from separate configurations. Learn about data resource arguments, behavior, dependencies, meta-arguments, and lifecycle. --- # Data Sources -_Data sources_ allow Terraform use information defined outside of Terraform, +_Data sources_ allow Terraform to use information defined outside of Terraform, defined by another separate Terraform configuration, or modified by functions. > **Hands-on:** Try the [Query Data Sources](https://learn.hashicorp.com/tutorials/terraform/data-sources) tutorial on HashiCorp Learn. From a740d758825f99cc22b4542cc77d16cc96b8c372 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Tue, 13 Jul 2021 17:34:34 -0400 Subject: [PATCH 053/107] Update dependency lock file description with more detail and remove 'ing' --- website/docs/language/dependency-lock.html.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/language/dependency-lock.html.md b/website/docs/language/dependency-lock.html.md index e3f7313f9..d2df7395a 100644 --- a/website/docs/language/dependency-lock.html.md +++ b/website/docs/language/dependency-lock.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "Dependency Lock File (.terraform.lock.hcl) - Configuration Language" description: |- - Details about the dependency lock file `.teraform.lock.hcl` that Terraform uses to track and select provider versions. + Terraform uses the dependency lock file `.teraform.lock.hcl` to track and select provider versions. Learn about dependency installation and lock file changes. --- # Dependency Lock File From 8abbbc7c7fefd3920cdaca19c73b991496a58ef6 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Tue, 13 Jul 2021 17:40:16 -0400 Subject: [PATCH 054/107] Update conditionals metadata to include more detail and remove 'ing' --- website/docs/language/expressions/conditionals.html.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/language/expressions/conditionals.html.md b/website/docs/language/expressions/conditionals.html.md index 9b63d3af6..d3bd181bd 100644 --- a/website/docs/language/expressions/conditionals.html.md +++ b/website/docs/language/expressions/conditionals.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "Conditional Expressions - Configuration Language" description: |- - Using conditional expressions in Terraform configurations. + Use conditional expressions in configurations to select one of two values. They are commonly used to define defaults to replace invalid values. --- # Conditional Expressions From eebbdd6778d4a6db5cfead0198163c38f64ea0f7 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Tue, 13 Jul 2021 17:48:28 -0400 Subject: [PATCH 055/107] Update dynamic blocks description with more detail and to remove 'ing' --- website/docs/language/expressions/dynamic-blocks.html.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/language/expressions/dynamic-blocks.html.md b/website/docs/language/expressions/dynamic-blocks.html.md index 6d672c0c5..0174b7c65 100644 --- a/website/docs/language/expressions/dynamic-blocks.html.md +++ b/website/docs/language/expressions/dynamic-blocks.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "Dynamic Blocks - Configuration Language" description: |- - Using dynamic blocks in Terraform configurations. + Use `dynamic` blocks in configurations to dynamically construct multi-level, nested block structures. --- From 3bf053a5fc41948c8f6686ea8e4193f192a4760e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?= Date: Wed, 14 Jul 2021 11:57:28 +0200 Subject: [PATCH 056/107] Add a test to ensure that workspaces must have a unique name in pg backend --- .../backend/remote-state/pg/backend_test.go | 48 ++++++++++++++----- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/internal/backend/remote-state/pg/backend_test.go b/internal/backend/remote-state/pg/backend_test.go index 815adf54c..da058483d 100644 --- a/internal/backend/remote-state/pg/backend_test.go +++ b/internal/backend/remote-state/pg/backend_test.go @@ -89,11 +89,13 @@ func TestBackendConfigSkipOptions(t *testing.T) { SkipSchemaCreation bool SkipTableCreation bool SkipIndexCreation bool + TestIndexIsPresent bool Setup func(t *testing.T, db *sql.DB, schemaName string) }{ { Name: "skip_schema_creation", SkipSchemaCreation: true, + TestIndexIsPresent: true, Setup: func(t *testing.T, db *sql.DB, schemaName string) { // create the schema as a prerequisites _, err := db.Query(fmt.Sprintf(`CREATE SCHEMA IF NOT EXISTS %s`, schemaName)) @@ -103,8 +105,9 @@ func TestBackendConfigSkipOptions(t *testing.T) { }, }, { - Name: "skip_table_creation", - SkipTableCreation: true, + Name: "skip_table_creation", + SkipTableCreation: true, + TestIndexIsPresent: true, Setup: func(t *testing.T, db *sql.DB, schemaName string) { // since the table needs to be already created the schema must be too _, err := db.Query(fmt.Sprintf(`CREATE SCHEMA %s`, schemaName)) @@ -122,8 +125,9 @@ func TestBackendConfigSkipOptions(t *testing.T) { }, }, { - Name: "skip_index_creation", - SkipIndexCreation: true, + Name: "skip_index_creation", + SkipIndexCreation: true, + TestIndexIsPresent: true, Setup: func(t *testing.T, db *sql.DB, schemaName string) { // Everything need to exists for the index to be created _, err := db.Query(fmt.Sprintf(`CREATE SCHEMA %s`, schemaName)) @@ -144,6 +148,10 @@ func TestBackendConfigSkipOptions(t *testing.T) { } }, }, + { + Name: "missing_index", + SkipIndexCreation: true, + }, } for _, tc := range testCases { @@ -163,7 +171,9 @@ func TestBackendConfigSkipOptions(t *testing.T) { t.Fatal(err) } - tc.Setup(t, db, schemaName) + if tc.Setup != nil { + tc.Setup(t, db, schemaName) + } defer db.Query(fmt.Sprintf("DROP SCHEMA IF EXISTS %s CASCADE", schemaName)) b := backend.TestBackendConfig(t, New(), config).(*Backend) @@ -179,14 +189,16 @@ func TestBackendConfigSkipOptions(t *testing.T) { if err != nil { t.Fatal(err) } - // Make sure that the index exists - query := `select count(*) from pg_indexes where schemaname=$1 and tablename=$2 and indexname=$3;` - var count int - if err := b.db.QueryRow(query, tc.Name, statesTableName, statesIndexName).Scan(&count); err != nil { - t.Fatal(err) - } - if count != 1 { - t.Fatalf("The index has not been created (%d)", count) + if tc.TestIndexIsPresent { + // Make sure that the index exists + query := `select count(*) from pg_indexes where schemaname=$1 and tablename=$2 and indexname=$3;` + var count int + if err := b.db.QueryRow(query, tc.Name, statesTableName, statesIndexName).Scan(&count); err != nil { + t.Fatal(err) + } + if count != 1 { + t.Fatalf("The index has not been created (%d)", count) + } } _, err = b.StateMgr(backend.DefaultStateName) @@ -202,6 +214,16 @@ func TestBackendConfigSkipOptions(t *testing.T) { if c.Name != backend.DefaultStateName { t.Fatal("RemoteClient name is not configured") } + + // Make sure that all workspace must have a unique name + _, err = db.Exec(fmt.Sprintf(`INSERT INTO %s.%s VALUES (100, 'unique_name_test', '')`, schemaName, statesTableName)) + if err != nil { + t.Fatal(err) + } + _, err = db.Exec(fmt.Sprintf(`INSERT INTO %s.%s VALUES (101, 'unique_name_test', '')`, schemaName, statesTableName)) + if err == nil { + t.Fatal("Creating two workspaces with the same name did not raise an error") + } }) } From b8e0d6f41864d595a49a6e714ad499d1c6f03a5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?= Date: Wed, 14 Jul 2021 11:59:14 +0200 Subject: [PATCH 057/107] Add UNIQUE constraint in the states table for the pg backend --- internal/backend/remote-state/pg/backend.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/backend/remote-state/pg/backend.go b/internal/backend/remote-state/pg/backend.go index e7e63028d..cdcfb3a6e 100644 --- a/internal/backend/remote-state/pg/backend.go +++ b/internal/backend/remote-state/pg/backend.go @@ -111,7 +111,7 @@ func (b *Backend) configure(ctx context.Context) error { query = `CREATE TABLE IF NOT EXISTS %s.%s ( id bigint NOT NULL DEFAULT nextval('public.global_states_id_seq') PRIMARY KEY, - name text, + name text UNIQUE, data text )` if _, err := db.Exec(fmt.Sprintf(query, b.schemaName, statesTableName)); err != nil { From 4177bd98b995b0570d0aca410fe76ef765cc9903 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?= Date: Wed, 14 Jul 2021 12:01:54 +0200 Subject: [PATCH 058/107] Change wording for the skip_... options of the pg backend --- website/docs/language/settings/backends/pg.html.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/docs/language/settings/backends/pg.html.md b/website/docs/language/settings/backends/pg.html.md index e83d6512a..4c72d7ffe 100644 --- a/website/docs/language/settings/backends/pg.html.md +++ b/website/docs/language/settings/backends/pg.html.md @@ -73,9 +73,9 @@ The following configuration options or environment variables are supported: * `conn_str` - (Required) Postgres connection string; a `postgres://` URL * `schema_name` - Name of the automatically-managed Postgres schema, default `terraform_remote_state`. - * `skip_schema_creation` - If set to `true`, the Postgres schema must already exist. Terraform won't try to create the schema. Useful when the Postgres user does not have "create schema" permission on the database. - * `skip_table_creation` - If set to `true`, the Postgres table must already exist. Terraform won't try to create the table. Useful when the Postgres user does not have "create table" permission on the database. - * `skip_index_creation` - If set to `true`, the Postgres index must already exist. Terraform won't try to create the index. Useful when the Postgres user does not have "create index" permission on the database. + * `skip_schema_creation` - If set to `true`, the Postgres schema must already exist. Terraform won't try to create the schema, this is useful when it has already been created by a database administrator. + * `skip_table_creation` - If set to `true`, the Postgres table must already exist. Terraform won't try to create the table, this is useful when it has already been created by a database administrator. + * `skip_index_creation` - If set to `true`, the Postgres index must already exist. Terraform won't try to create the index, this is useful when it has already been created by a database administrator. ## Technical Design From 3b61e8df7a0e17cd6748764f693e15e9a3b53fa0 Mon Sep 17 00:00:00 2001 From: hc-github-team-tf-core Date: Wed, 14 Jul 2021 16:55:22 +0000 Subject: [PATCH 059/107] Release v1.1.0-alpha20210714 --- version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version/version.go b/version/version.go index 86f22153d..6e9dceab7 100644 --- a/version/version.go +++ b/version/version.go @@ -16,7 +16,7 @@ var Version = "1.1.0" // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. -var Prerelease = "dev" +var Prerelease = "alpha20210714" // SemVer is an instance of version.Version. This has the secondary // benefit of verifying during tests and init time that our version is a From b6614cf2b301b5153c9a0dac7a70c581b1505318 Mon Sep 17 00:00:00 2001 From: hc-github-team-tf-core Date: Wed, 14 Jul 2021 17:18:47 +0000 Subject: [PATCH 060/107] Cleanup after v1.1.0-alpha20210714 release --- version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version/version.go b/version/version.go index 6e9dceab7..86f22153d 100644 --- a/version/version.go +++ b/version/version.go @@ -16,7 +16,7 @@ var Version = "1.1.0" // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. -var Prerelease = "alpha20210714" +var Prerelease = "dev" // SemVer is an instance of version.Version. This has the secondary // benefit of verifying during tests and init time that our version is a From 3174dfd63f6fe2c89f72236cb436e39126193513 Mon Sep 17 00:00:00 2001 From: Russell Rollins Date: Wed, 14 Jul 2021 14:08:52 -0400 Subject: [PATCH 061/107] Adds anchor for TF_CLI_ARGS. --- website/docs/cli/config/environment-variables.html.md | 1 + 1 file changed, 1 insertion(+) diff --git a/website/docs/cli/config/environment-variables.html.md b/website/docs/cli/config/environment-variables.html.md index 891f8d231..fb33a1a1f 100644 --- a/website/docs/cli/config/environment-variables.html.md +++ b/website/docs/cli/config/environment-variables.html.md @@ -62,6 +62,7 @@ export TF_VAR_amap='{ foo = "bar", baz = "qux" }' For more on how to use `TF_VAR_name` in context, check out the section on [Variable Configuration](/docs/language/values/variables.html). ## TF_CLI_ARGS and TF_CLI_ARGS_name + The value of `TF_CLI_ARGS` will specify additional arguments to the command-line. This allows easier automation in CI environments as well as From bc9065334e4de62e73d2b943bfbe2e808a079bd5 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Wed, 14 Jul 2021 16:54:26 -0400 Subject: [PATCH 062/107] Update description metadata per PR feedback --- website/docs/language/data-sources/index.html.md | 2 +- website/docs/language/expressions/conditionals.html.md | 2 +- website/docs/language/expressions/dynamic-blocks.html.md | 2 +- website/docs/language/expressions/for.html.md | 2 +- website/docs/language/expressions/function-calls.html.md | 2 +- website/docs/language/expressions/index.html.md | 2 +- website/docs/language/expressions/operators.html.md | 2 +- website/docs/language/expressions/references.html.md | 2 +- website/docs/language/expressions/splat.html.md | 6 ++---- website/docs/language/expressions/strings.html.md | 2 +- website/docs/language/expressions/type-constraints.html.md | 3 +-- website/docs/language/expressions/types.html.md | 2 +- .../docs/language/expressions/version-constraints.html.md | 2 +- website/docs/language/files/index.html.md | 2 +- website/docs/language/files/override.html.md | 2 +- website/docs/language/functions/index.html.md | 2 +- website/docs/language/index.html.md | 2 +- website/docs/language/meta-arguments/count.html.md | 2 +- website/docs/language/meta-arguments/depends_on.html.md | 2 +- website/docs/language/meta-arguments/for_each.html.md | 2 +- website/docs/language/meta-arguments/lifecycle.html.md | 2 +- .../docs/language/meta-arguments/module-providers.html.md | 2 +- .../docs/language/meta-arguments/resource-provider.html.md | 2 +- website/docs/language/modules/develop/index.html.md | 2 +- website/docs/language/modules/index.html.md | 2 +- website/docs/language/modules/sources.html.md | 3 ++- website/docs/language/modules/syntax.html.md | 2 +- website/docs/language/providers/configuration.html.md | 4 ++-- website/docs/language/providers/requirements.html.md | 2 +- website/docs/language/resources/behavior.html.md | 2 +- website/docs/language/resources/index.html.md | 2 +- .../docs/language/resources/provisioners/connection.html.md | 2 +- 32 files changed, 35 insertions(+), 37 deletions(-) diff --git a/website/docs/language/data-sources/index.html.md b/website/docs/language/data-sources/index.html.md index ebc21c7ee..3121c1ed8 100644 --- a/website/docs/language/data-sources/index.html.md +++ b/website/docs/language/data-sources/index.html.md @@ -3,7 +3,7 @@ layout: "language" page_title: "Data Sources - Configuration Language" sidebar_current: "docs-config-data-sources" description: |- -Data sources allow Terraform to use external data, function output, and data from separate configurations. Learn about data resource arguments, behavior, dependencies, meta-arguments, and lifecycle. +Data sources allow Terraform to use external data, function output, and data from other configurations. Terraform accesses them via data resources. --- # Data Sources diff --git a/website/docs/language/expressions/conditionals.html.md b/website/docs/language/expressions/conditionals.html.md index d3bd181bd..f12d44933 100644 --- a/website/docs/language/expressions/conditionals.html.md +++ b/website/docs/language/expressions/conditionals.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "Conditional Expressions - Configuration Language" description: |- - Use conditional expressions in configurations to select one of two values. They are commonly used to define defaults to replace invalid values. + Conditional expressions in configurations select one of two values. You can use them to define defaults to replace invalid values. --- # Conditional Expressions diff --git a/website/docs/language/expressions/dynamic-blocks.html.md b/website/docs/language/expressions/dynamic-blocks.html.md index 0174b7c65..b86f89364 100644 --- a/website/docs/language/expressions/dynamic-blocks.html.md +++ b/website/docs/language/expressions/dynamic-blocks.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "Dynamic Blocks - Configuration Language" description: |- - Use `dynamic` blocks in configurations to dynamically construct multi-level, nested block structures. + `dynamic` blocks dynamically construct multi-level, nested block structures. Learn to configure `dynamic` blocks and understand their behavior. --- diff --git a/website/docs/language/expressions/for.html.md b/website/docs/language/expressions/for.html.md index c34b1197d..11eb71cd4 100644 --- a/website/docs/language/expressions/for.html.md +++ b/website/docs/language/expressions/for.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "For Expressions - Configuration Language" description: |- - Using `for` expressions in Terraform configurations. + `for` expressions transform complex input values into complex output values. Learn how Terraform orders elements and how to filter inputs and group results. --- # `for` Expressions diff --git a/website/docs/language/expressions/function-calls.html.md b/website/docs/language/expressions/function-calls.html.md index eb526fa65..961043439 100644 --- a/website/docs/language/expressions/function-calls.html.md +++ b/website/docs/language/expressions/function-calls.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "Function Calls - Configuration Language" description: |- - Using function calls in Terraform configurations. + Function calls transform and combine values. Learn about Terraform's built-in functions. --- # Function Calls diff --git a/website/docs/language/expressions/index.html.md b/website/docs/language/expressions/index.html.md index 2923d5d88..9cb666677 100644 --- a/website/docs/language/expressions/index.html.md +++ b/website/docs/language/expressions/index.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "Expressions - Configuration Language" description: |- - An overview of expressions used to compute values in Terraform configurations. + An overview of expressions you can use to reference or compute values in Terraform configurations, including types, operators, and functions. --- # Expressions diff --git a/website/docs/language/expressions/operators.html.md b/website/docs/language/expressions/operators.html.md index 0f1dff2cc..eb79dcbb6 100644 --- a/website/docs/language/expressions/operators.html.md +++ b/website/docs/language/expressions/operators.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "Operators - Configuration Language" description: |- - Using operators in Terraform configurations. + Operators transform or combine expressions. Learn about arithmetic, logical, equality, and comparison operators. --- # Arithmetic and Logical Operators diff --git a/website/docs/language/expressions/references.html.md b/website/docs/language/expressions/references.html.md index 100eb57af..8a877ce61 100644 --- a/website/docs/language/expressions/references.html.md +++ b/website/docs/language/expressions/references.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "References to Values - Configuration Language" description: |- - Using references to values in Terraform configurations. + Reference named values in configurations, including resources, input variables, local and block-local values, module outputs, data sources, and workspace data. --- # References to Named Values diff --git a/website/docs/language/expressions/splat.html.md b/website/docs/language/expressions/splat.html.md index a9eb259b6..0ea75f58b 100644 --- a/website/docs/language/expressions/splat.html.md +++ b/website/docs/language/expressions/splat.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "Splat Expressions - Configuration Language" description: |- - Using splat expressions in Terraform configurations. + Splat expressions concisely express common operations. They also transform single, non-null values into a single-element tuple. --- # Splat Expressions @@ -63,9 +63,7 @@ tuple value. If the value is _null_ then the splat expression will return an empty tuple. This special behavior can be useful for modules that accept optional input -variables whose default value is `null` to represent the absense of any value, -to adapt the variable value to work with other Terraform language features that -are designed to work with collections. For example: +variables whose default value is `null` to represent the absence of any value. This allows the module to adapt the variable value for Terraform language features designed to work with collections. For example: ``` variable "website" { diff --git a/website/docs/language/expressions/strings.html.md b/website/docs/language/expressions/strings.html.md index bbf363b63..5c4f2c62b 100644 --- a/website/docs/language/expressions/strings.html.md +++ b/website/docs/language/expressions/strings.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "Strings and Templates - Configuration Language" description: |- - Using strings and templates in Terraform configurations. + String literals and template sequences interpolate values and manipulate text. Learn about both quoted and "heredoc" string syntax. --- # Strings and Templates diff --git a/website/docs/language/expressions/type-constraints.html.md b/website/docs/language/expressions/type-constraints.html.md index 43d7f938c..ec59f1b9b 100644 --- a/website/docs/language/expressions/type-constraints.html.md +++ b/website/docs/language/expressions/type-constraints.html.md @@ -3,8 +3,7 @@ layout: "language" page_title: "Type Constraints - Configuration Language" sidebar_current: "docs-config-types" description: |- - Terraform module authors and provider developers can use detailed type - constraints to validate the inputs of their modules and resources. + Learn how to use type constraints to validate user inputs to modules and resources. --- # Type Constraints diff --git a/website/docs/language/expressions/types.html.md b/website/docs/language/expressions/types.html.md index 4fe5efab0..1ad317b15 100644 --- a/website/docs/language/expressions/types.html.md +++ b/website/docs/language/expressions/types.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "Types and Values - Configuration Language" description: |- - An overview of values and their types in the Terraform language. + Learn about value types and their syntax, including string, number, bool, list, and map. Also learn about complex types and type conversion. --- # Types and Values diff --git a/website/docs/language/expressions/version-constraints.html.md b/website/docs/language/expressions/version-constraints.html.md index 1c462c20b..861773c66 100644 --- a/website/docs/language/expressions/version-constraints.html.md +++ b/website/docs/language/expressions/version-constraints.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "Version Constraints - Configuration Language" description: |- - Using version constraints in Terraform configurations. + Version constraint strings specify a range of acceptable versions for modules, providers, and Terraform itself. Learn version constraint syntax and behavior. --- # Version Constraints diff --git a/website/docs/language/files/index.html.md b/website/docs/language/files/index.html.md index 1175a7106..72ceb13c8 100644 --- a/website/docs/language/files/index.html.md +++ b/website/docs/language/files/index.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "Files and Directories - Configuration Language" description: |- - An overview of how Terraform configuration files are named, organized, and stored as well as how Terraform modules are created and evaluated. + Learn how to name, organize, and store Terraform configuration files as well as how Terraform evaluates modules. --- # Files and Directories diff --git a/website/docs/language/files/override.html.md b/website/docs/language/files/override.html.md index 505c1c1a3..1d549cbe2 100644 --- a/website/docs/language/files/override.html.md +++ b/website/docs/language/files/override.html.md @@ -3,7 +3,7 @@ layout: "language" page_title: "Override Files - Configuration Language" sidebar_current: "docs-config-override" description: |- - How Terraform override files merge additional settings into existing configuration objects. + Override files merge additional settings into existing configuration objects. Learn how to use override files and about merging behavior. --- # Override Files diff --git a/website/docs/language/functions/index.html.md b/website/docs/language/functions/index.html.md index 2da4a6cb9..2a7af09ff 100644 --- a/website/docs/language/functions/index.html.md +++ b/website/docs/language/functions/index.html.md @@ -3,7 +3,7 @@ layout: "language" page_title: "Functions - Configuration Language" sidebar_current: "docs-config-functions" description: |- - An introduction to functions in the Terraform language that can transform and combine values. + An introduction to the built-in functions that you can use to transform and combine values in expressions. --- # Built-in Functions diff --git a/website/docs/language/index.html.md b/website/docs/language/index.html.md index c958f17ea..ca4e2a22c 100644 --- a/website/docs/language/index.html.md +++ b/website/docs/language/index.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "Overview - Configuration Language" description: |- - An introduction to the Terraform Configuration Language that is used to declare resources in infrastructure as code. +You can use the Terraform language to write configuration files that tell Terraform how to manage a collection of infrastructure. --- # Terraform Language Documentation diff --git a/website/docs/language/meta-arguments/count.html.md b/website/docs/language/meta-arguments/count.html.md index 35380e929..8a2b1a16e 100644 --- a/website/docs/language/meta-arguments/count.html.md +++ b/website/docs/language/meta-arguments/count.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "The count Meta-Argument - Configuration Language" description: |- - Using the Terraform language `count` meta-argument to efficiently manage nearly identical resources without writing a separate block for each one. + The `count` meta-argument helps you efficiently manage nearly identical infrastructure resources without writing a separate block for each one. --- # The `count` Meta-Argument diff --git a/website/docs/language/meta-arguments/depends_on.html.md b/website/docs/language/meta-arguments/depends_on.html.md index e6ee5f6e7..c5de7e120 100644 --- a/website/docs/language/meta-arguments/depends_on.html.md +++ b/website/docs/language/meta-arguments/depends_on.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "The depends_on Meta-Argument - Configuration Language" description: |- - Using the Terraform language `depends_on` meta-argument to handle hidden resource or module dependencies. + The `depends_on` meta-argument allows you to handle hidden resource or module dependencies. --- # The `depends_on` Meta-Argument diff --git a/website/docs/language/meta-arguments/for_each.html.md b/website/docs/language/meta-arguments/for_each.html.md index dee916bfd..46491790a 100644 --- a/website/docs/language/meta-arguments/for_each.html.md +++ b/website/docs/language/meta-arguments/for_each.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "The for_each Meta-Argument - Configuration Language" description: |- - Using the Terraform language `for_each` meta-argument to efficiently manage similar resources without writing a separate block for each one. + The `for_each` meta-argument allows you to efficiently manage similar infrastructure resources without writing a separate block for each one. --- # The `for_each` Meta-Argument diff --git a/website/docs/language/meta-arguments/lifecycle.html.md b/website/docs/language/meta-arguments/lifecycle.html.md index 69423f175..72f78e255 100644 --- a/website/docs/language/meta-arguments/lifecycle.html.md +++ b/website/docs/language/meta-arguments/lifecycle.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "The lifecycle Meta-Argument - Configuration Language" description: |- - Using the Terraform language `lifecycle` meta-argument to customize resource behavior. + The meta-arguments in a `lifecycle` block allow you to customize resource behavior. For example, preventing Terraform from destroying associated infrastructure. --- # The `lifecycle` Meta-Argument diff --git a/website/docs/language/meta-arguments/module-providers.html.md b/website/docs/language/meta-arguments/module-providers.html.md index d5af20f25..4c9ff6b16 100644 --- a/website/docs/language/meta-arguments/module-providers.html.md +++ b/website/docs/language/meta-arguments/module-providers.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "The Module providers Meta-Argument - Configuration Language" description: |- - Using the Terraform language `providers` meta-argument to specify which provider configurations from a parent module are available inside a child module. + The `providers` meta-argument specifies which provider configurations from a parent module are available inside a child module. --- # The Module `providers` Meta-Argument diff --git a/website/docs/language/meta-arguments/resource-provider.html.md b/website/docs/language/meta-arguments/resource-provider.html.md index 6be261947..e66f66453 100644 --- a/website/docs/language/meta-arguments/resource-provider.html.md +++ b/website/docs/language/meta-arguments/resource-provider.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "The Resource provider Meta-Argument - Configuration Language" description: |- - Using the Terraform language `provider` meta-argument to specify which provider configuration to use for a resource. + The `provider` meta-argument specifies which provider configuration Terraform should use for a resource. --- # The Resource `provider` Meta-Argument diff --git a/website/docs/language/modules/develop/index.html.md b/website/docs/language/modules/develop/index.html.md index d7b2f3bae..d651ee91e 100644 --- a/website/docs/language/modules/develop/index.html.md +++ b/website/docs/language/modules/develop/index.html.md @@ -3,7 +3,7 @@ layout: "language" page_title: "Creating Modules" sidebar_current: "docs-modules" description: |- - An introduction to creating modules, containers for multiple resources that are used together in a Terraform configuration. + Modules are containers for multiple resources that are used together in a configuration. Learn when to create modules and about module structure. --- # Creating Modules diff --git a/website/docs/language/modules/index.html.md b/website/docs/language/modules/index.html.md index 7feca688b..669ad5f44 100644 --- a/website/docs/language/modules/index.html.md +++ b/website/docs/language/modules/index.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "Modules Overview - Configuration Language" description: |- - An overview of Terraform modules, containers for multiple resources that are used together in a configuration. + Modules are containers for multiple resources that are used together in a configuration. Find resources for using, developing, and publishing modules. --- # Modules diff --git a/website/docs/language/modules/sources.html.md b/website/docs/language/modules/sources.html.md index d6423c25d..21ee57dfd 100644 --- a/website/docs/language/modules/sources.html.md +++ b/website/docs/language/modules/sources.html.md @@ -2,7 +2,8 @@ layout: "language" page_title: "Module Sources" sidebar_current: "docs-modules-sources" -description: Using `source` in Terraform modules to specify child modules in locations like GitHub, the Terraform Registry, Bitbucket, Git, Mercurial, S3, and GCS. +description: |- + The `source` argument tells Terraform where to find child modules in locations like GitHub, the Terraform Registry, Bitbucket, Git, Mercurial, S3, and GCS. --- # Module Sources diff --git a/website/docs/language/modules/syntax.html.md b/website/docs/language/modules/syntax.html.md index 58ac14539..0010e3056 100644 --- a/website/docs/language/modules/syntax.html.md +++ b/website/docs/language/modules/syntax.html.md @@ -3,7 +3,7 @@ layout: "language" page_title: "Modules - Configuration Language" sidebar_current: "docs-config-modules" description: |- - Calling one module from another in Terraform configurations. + Modules are containers for multiple resources that are used together. Learn how to call one module from another in configurations. --- # Module Blocks diff --git a/website/docs/language/providers/configuration.html.md b/website/docs/language/providers/configuration.html.md index 6641271a1..27f5544a4 100644 --- a/website/docs/language/providers/configuration.html.md +++ b/website/docs/language/providers/configuration.html.md @@ -3,12 +3,12 @@ layout: "language" page_title: "Provider Configuration - Configuration Language" sidebar_current: "docs-config-providers" description: |- - Configuring Terraform providers, including how to use the `alias` meta-argument to specify multiple configurations for a single provider. + Learn how to configure Terraform providers, including how to use the `alias` meta-argument to specify multiple configurations for a single provider. --- # Provider Configuration -Providers alow Terraform to interact with cloud providers, SaaS providers, and +Providers allow Terraform to interact with cloud providers, SaaS providers, and other APIs. Some providers require you to configure them with endpoint URLs, cloud regions, diff --git a/website/docs/language/providers/requirements.html.md b/website/docs/language/providers/requirements.html.md index 6366bb557..5a4ccd58d 100644 --- a/website/docs/language/providers/requirements.html.md +++ b/website/docs/language/providers/requirements.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "Provider Requirements - Configuration Language" description: |- - Declaring providers in your module configuration so that Terraform can install them. + Providers are plugins that allow Terraform to interact with remote systems. Learn how to declare providers in your configuration. --- # Provider Requirements diff --git a/website/docs/language/resources/behavior.html.md b/website/docs/language/resources/behavior.html.md index c2f7b3e0a..f0fe4463c 100644 --- a/website/docs/language/resources/behavior.html.md +++ b/website/docs/language/resources/behavior.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "Resource Behavior - Configuration Language" description: |- - How Terraform uses resource blocks to create infrastructure objects as well as details about resource attributes and dependencies. + Learn how Terraform uses `resource` blocks to create infrastructure objects. Also learn about resource dependencies and accessing resource attributes. --- # Resource Behavior diff --git a/website/docs/language/resources/index.html.md b/website/docs/language/resources/index.html.md index cd343fc0f..2e5bd229a 100644 --- a/website/docs/language/resources/index.html.md +++ b/website/docs/language/resources/index.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "Resources Overview - Configuration Language" description: |- - An introduction to the Terraform language resources element that is used to describe infrastructure objects. + An introduction to the `resources` element that describes infrastructure objects in Terraform configurations. --- # Resources diff --git a/website/docs/language/resources/provisioners/connection.html.md b/website/docs/language/resources/provisioners/connection.html.md index d173320e7..c68bd94e1 100644 --- a/website/docs/language/resources/provisioners/connection.html.md +++ b/website/docs/language/resources/provisioners/connection.html.md @@ -3,7 +3,7 @@ layout: "language" page_title: "Provisioner Connection Settings" sidebar_current: "docs-provisioners-connection" description: |- - Managing provisioner connection defaults for SSH and WinRM using the `connection` block in Terraform language. + The `connection` block allows you to manage provisioner connection defaults for SSH and WinRM. --- # Provisioner Connection Settings From f3a57db2930a168c2c043ef7bec48d901e8a5ae6 Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Sat, 10 Jul 2021 15:18:19 -0700 Subject: [PATCH 063/107] addrs: UniqueKey and UniqueKeyer Many times now we've seen situations where we need to use addresses as map keys, but not all of our address types are comparable and thus we tend to end up using string representations as keys instead. That's problematic because conversion to string uses type information and some of the address types have string representations that are ambiguous with one another. UniqueKey therefore represents an opaque key that is unique for each functionally-distinct address across all types that implement UniqueKeyer. For this initial commit I've implemented UniqueKeyer only for the Referenceable family of types. These are an easy case because they were all already comparable (intentionally) anyway. Later commits can implement UniqueKeyer for other types that are not naturally comparable, such as any which include a ModuleInstance. This also includes a new type addrs.Set which wraps a map as a set of addresses, using the unique keys to ensure that there can be only one element for each distinct address. --- internal/addrs/count_attr.go | 6 +++ internal/addrs/for_each_attr.go | 6 +++ internal/addrs/input_variable.go | 6 +++ internal/addrs/local_value.go | 6 +++ internal/addrs/module_call.go | 24 ++++++++++++ internal/addrs/path_attr.go | 6 +++ internal/addrs/referenceable.go | 3 ++ internal/addrs/resource.go | 12 ++++++ internal/addrs/resource_phase.go | 12 ++++++ internal/addrs/self.go | 6 +++ internal/addrs/set.go | 43 +++++++++++++++++++++ internal/addrs/terraform_attr.go | 6 +++ internal/addrs/unique_key.go | 23 +++++++++++ internal/addrs/unique_key_test.go | 64 +++++++++++++++++++++++++++++++ 14 files changed, 223 insertions(+) create mode 100644 internal/addrs/set.go create mode 100644 internal/addrs/unique_key.go create mode 100644 internal/addrs/unique_key_test.go diff --git a/internal/addrs/count_attr.go b/internal/addrs/count_attr.go index 90a5faf0e..0be5c0264 100644 --- a/internal/addrs/count_attr.go +++ b/internal/addrs/count_attr.go @@ -10,3 +10,9 @@ type CountAttr struct { func (ca CountAttr) String() string { return "count." + ca.Name } + +func (ca CountAttr) UniqueKey() UniqueKey { + return ca // A CountAttr is its own UniqueKey +} + +func (ca CountAttr) uniqueKeySigil() {} diff --git a/internal/addrs/for_each_attr.go b/internal/addrs/for_each_attr.go index 7a6385035..6b0c06096 100644 --- a/internal/addrs/for_each_attr.go +++ b/internal/addrs/for_each_attr.go @@ -10,3 +10,9 @@ type ForEachAttr struct { func (f ForEachAttr) String() string { return "each." + f.Name } + +func (f ForEachAttr) UniqueKey() UniqueKey { + return f // A ForEachAttr is its own UniqueKey +} + +func (f ForEachAttr) uniqueKeySigil() {} diff --git a/internal/addrs/input_variable.go b/internal/addrs/input_variable.go index 975c72f1e..e85743bcd 100644 --- a/internal/addrs/input_variable.go +++ b/internal/addrs/input_variable.go @@ -14,6 +14,12 @@ func (v InputVariable) String() string { return "var." + v.Name } +func (v InputVariable) UniqueKey() UniqueKey { + return v // A InputVariable is its own UniqueKey +} + +func (v InputVariable) uniqueKeySigil() {} + // Absolute converts the receiver into an absolute address within the given // module instance. func (v InputVariable) Absolute(m ModuleInstance) AbsInputVariableInstance { diff --git a/internal/addrs/local_value.go b/internal/addrs/local_value.go index 61a07b9c7..601765006 100644 --- a/internal/addrs/local_value.go +++ b/internal/addrs/local_value.go @@ -14,6 +14,12 @@ func (v LocalValue) String() string { return "local." + v.Name } +func (v LocalValue) UniqueKey() UniqueKey { + return v // A LocalValue is its own UniqueKey +} + +func (v LocalValue) uniqueKeySigil() {} + // Absolute converts the receiver into an absolute address within the given // module instance. func (v LocalValue) Absolute(m ModuleInstance) AbsLocalValue { diff --git a/internal/addrs/module_call.go b/internal/addrs/module_call.go index c55433ac6..c6af85f08 100644 --- a/internal/addrs/module_call.go +++ b/internal/addrs/module_call.go @@ -15,6 +15,12 @@ func (c ModuleCall) String() string { return "module." + c.Name } +func (c ModuleCall) UniqueKey() UniqueKey { + return c // A ModuleCall is its own UniqueKey +} + +func (c ModuleCall) uniqueKeySigil() {} + // Instance returns the address of an instance of the receiver identified by // the given key. func (c ModuleCall) Instance(key InstanceKey) ModuleCallInstance { @@ -79,6 +85,12 @@ func (c ModuleCallInstance) String() string { return fmt.Sprintf("module.%s%s", c.Call.Name, c.Key) } +func (c ModuleCallInstance) UniqueKey() UniqueKey { + return c // A ModuleCallInstance is its own UniqueKey +} + +func (c ModuleCallInstance) uniqueKeySigil() {} + func (c ModuleCallInstance) Absolute(moduleAddr ModuleInstance) ModuleInstance { ret := make(ModuleInstance, len(moduleAddr), len(moduleAddr)+1) copy(ret, moduleAddr) @@ -118,6 +130,12 @@ func (m ModuleCallOutput) String() string { return fmt.Sprintf("%s.%s", m.Call.String(), m.Name) } +func (m ModuleCallOutput) UniqueKey() UniqueKey { + return m // A ModuleCallOutput is its own UniqueKey +} + +func (m ModuleCallOutput) uniqueKeySigil() {} + // ModuleCallInstanceOutput is the address of a particular named output produced by // an instance of a module call. type ModuleCallInstanceOutput struct { @@ -139,6 +157,12 @@ func (co ModuleCallInstanceOutput) String() string { return fmt.Sprintf("%s.%s", co.Call.String(), co.Name) } +func (co ModuleCallInstanceOutput) UniqueKey() UniqueKey { + return co // A ModuleCallInstanceOutput is its own UniqueKey +} + +func (co ModuleCallInstanceOutput) uniqueKeySigil() {} + // AbsOutputValue returns the absolute output value address that corresponds // to the receving module call output address, once resolved in the given // calling module. diff --git a/internal/addrs/path_attr.go b/internal/addrs/path_attr.go index cfc13f4bc..9de5e134d 100644 --- a/internal/addrs/path_attr.go +++ b/internal/addrs/path_attr.go @@ -10,3 +10,9 @@ type PathAttr struct { func (pa PathAttr) String() string { return "path." + pa.Name } + +func (pa PathAttr) UniqueKey() UniqueKey { + return pa // A PathAttr is its own UniqueKey +} + +func (pa PathAttr) uniqueKeySigil() {} diff --git a/internal/addrs/referenceable.go b/internal/addrs/referenceable.go index 211083a5f..fbbc753d4 100644 --- a/internal/addrs/referenceable.go +++ b/internal/addrs/referenceable.go @@ -7,6 +7,9 @@ type Referenceable interface { // in lang.Scope.buildEvalContext. referenceableSigil() + // All Referenceable address types must have unique keys. + UniqueKeyer + // String produces a string representation of the address that could be // parsed as a HCL traversal and passed to ParseRef to produce an identical // result. diff --git a/internal/addrs/resource.go b/internal/addrs/resource.go index 97b7f5dd9..f22db05cb 100644 --- a/internal/addrs/resource.go +++ b/internal/addrs/resource.go @@ -32,6 +32,12 @@ func (r Resource) Equal(o Resource) bool { return r.Mode == o.Mode && r.Name == o.Name && r.Type == o.Type } +func (r Resource) UniqueKey() UniqueKey { + return r // A Resource is its own UniqueKey +} + +func (r Resource) uniqueKeySigil() {} + // Instance produces the address for a specific instance of the receiver // that is idenfied by the given key. func (r Resource) Instance(key InstanceKey) ResourceInstance { @@ -94,6 +100,12 @@ func (r ResourceInstance) Equal(o ResourceInstance) bool { return r.Key == o.Key && r.Resource.Equal(o.Resource) } +func (r ResourceInstance) UniqueKey() UniqueKey { + return r // A ResourceInstance is its own UniqueKey +} + +func (r ResourceInstance) uniqueKeySigil() {} + // Absolute returns an AbsResourceInstance from the receiver and the given module // instance address. func (r ResourceInstance) Absolute(module ModuleInstance) AbsResourceInstance { diff --git a/internal/addrs/resource_phase.go b/internal/addrs/resource_phase.go index 9bdbdc421..c62a7fc83 100644 --- a/internal/addrs/resource_phase.go +++ b/internal/addrs/resource_phase.go @@ -44,6 +44,12 @@ func (rp ResourceInstancePhase) String() string { return fmt.Sprintf("%s#%s", rp.ResourceInstance, rp.Phase) } +func (rp ResourceInstancePhase) UniqueKey() UniqueKey { + return rp // A ResourceInstancePhase is its own UniqueKey +} + +func (rp ResourceInstancePhase) uniqueKeySigil() {} + // ResourceInstancePhaseType is an enumeration used with ResourceInstancePhase. type ResourceInstancePhaseType string @@ -103,3 +109,9 @@ func (rp ResourcePhase) String() string { // because this special address type should never be exposed in the UI. return fmt.Sprintf("%s#%s", rp.Resource, rp.Phase) } + +func (rp ResourcePhase) UniqueKey() UniqueKey { + return rp // A ResourcePhase is its own UniqueKey +} + +func (rp ResourcePhase) uniqueKeySigil() {} diff --git a/internal/addrs/self.go b/internal/addrs/self.go index 7f24eaf08..64c8f6ecf 100644 --- a/internal/addrs/self.go +++ b/internal/addrs/self.go @@ -12,3 +12,9 @@ func (s selfT) referenceableSigil() { func (s selfT) String() string { return "self" } + +func (s selfT) UniqueKey() UniqueKey { + return Self // Self is its own UniqueKey +} + +func (s selfT) uniqueKeySigil() {} diff --git a/internal/addrs/set.go b/internal/addrs/set.go new file mode 100644 index 000000000..ef82c5915 --- /dev/null +++ b/internal/addrs/set.go @@ -0,0 +1,43 @@ +package addrs + +// Set represents a set of addresses of types that implement UniqueKeyer. +type Set map[UniqueKey]UniqueKeyer + +func (s Set) Has(addr UniqueKeyer) bool { + _, exists := s[addr.UniqueKey()] + return exists +} + +func (s Set) Add(addr UniqueKeyer) { + s[addr.UniqueKey()] = addr +} + +func (s Set) Remove(addr UniqueKeyer) { + delete(s, addr.UniqueKey()) +} + +func (s Set) Union(other Set) Set { + ret := make(Set) + for k, addr := range s { + ret[k] = addr + } + for k, addr := range other { + ret[k] = addr + } + return ret +} + +func (s Set) Intersection(other Set) Set { + ret := make(Set) + for k, addr := range s { + if _, exists := other[k]; exists { + ret[k] = addr + } + } + for k, addr := range other { + if _, exists := s[k]; exists { + ret[k] = addr + } + } + return ret +} diff --git a/internal/addrs/terraform_attr.go b/internal/addrs/terraform_attr.go index a880182ae..d3d11677c 100644 --- a/internal/addrs/terraform_attr.go +++ b/internal/addrs/terraform_attr.go @@ -10,3 +10,9 @@ type TerraformAttr struct { func (ta TerraformAttr) String() string { return "terraform." + ta.Name } + +func (ta TerraformAttr) UniqueKey() UniqueKey { + return ta // A TerraformAttr is its own UniqueKey +} + +func (ta TerraformAttr) uniqueKeySigil() {} diff --git a/internal/addrs/unique_key.go b/internal/addrs/unique_key.go new file mode 100644 index 000000000..c3321a298 --- /dev/null +++ b/internal/addrs/unique_key.go @@ -0,0 +1,23 @@ +package addrs + +// UniqueKey is an interface implemented by values that serve as unique map +// keys for particular addresses. +// +// All implementations of UniqueKey are comparable and can thus be used as +// map keys. Unique keys generated from different address types are always +// distinct. All functionally-equivalent keys for the same address type +// always compare equal, and likewise functionally-different values do not. +type UniqueKey interface { + uniqueKeySigil() +} + +// UniqueKeyer is an interface implemented by types that can be represented +// by a unique key. +// +// Some address types naturally comply with the expectations of a UniqueKey +// and may thus be their own unique key type. However, address types that +// are not naturally comparable can implement this interface by returning +// proxy values. +type UniqueKeyer interface { + UniqueKey() UniqueKey +} diff --git a/internal/addrs/unique_key_test.go b/internal/addrs/unique_key_test.go new file mode 100644 index 000000000..416899ca4 --- /dev/null +++ b/internal/addrs/unique_key_test.go @@ -0,0 +1,64 @@ +package addrs + +import ( + "fmt" + "testing" +) + +// TestUniqueKeyer aims to ensure that all of the types that have unique keys +// will continue to meet the UniqueKeyer contract under future changes. +// +// If you add a new implementation of UniqueKey, consider adding a test case +// for it here. +func TestUniqueKeyer(t *testing.T) { + tests := []UniqueKeyer{ + CountAttr{Name: "index"}, + ForEachAttr{Name: "key"}, + TerraformAttr{Name: "workspace"}, + PathAttr{Name: "module"}, + InputVariable{Name: "foo"}, + ModuleCall{Name: "foo"}, + ModuleCallInstance{ + Call: ModuleCall{Name: "foo"}, + Key: StringKey("a"), + }, + ModuleCallOutput{ + Call: ModuleCall{Name: "foo"}, + Name: "bar", + }, + ModuleCallInstanceOutput{ + Call: ModuleCallInstance{ + Call: ModuleCall{Name: "foo"}, + Key: StringKey("a"), + }, + Name: "bar", + }, + Resource{ + Mode: ManagedResourceMode, + Type: "foo", + Name: "bar", + }, + ResourceInstance{ + Resource: Resource{ + Mode: ManagedResourceMode, + Type: "foo", + Name: "bar", + }, + Key: IntKey(1), + }, + Self, + } + + for _, test := range tests { + t.Run(fmt.Sprintf("%s", test), func(t *testing.T) { + a := test.UniqueKey() + b := test.UniqueKey() + + // The following comparison will panic if the unique key is not + // of a comparable type. + if a != b { + t.Fatalf("the two unique keys are not equal\na: %#v\b: %#v", a, b) + } + }) + } +} From cd06572c4fda7b0771215193358d677799e26263 Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Mon, 12 Jul 2021 16:30:31 -0700 Subject: [PATCH 064/107] addrs: ModuleInstance and AbsResourceInstance are UniqueKeyers Since these address types are not directly comparable themselves, we use an unexported named type around the string representation, whereby the special type can avoid any ambiguity between string representations of different types and thus each type only needs to worry about possible ambiguity of its _own_ string representation. --- internal/addrs/module_instance.go | 8 ++++++++ internal/addrs/resource.go | 8 ++++++++ internal/addrs/unique_key_test.go | 8 ++++++++ 3 files changed, 24 insertions(+) diff --git a/internal/addrs/module_instance.go b/internal/addrs/module_instance.go index 2eb57948d..21afcb077 100644 --- a/internal/addrs/module_instance.go +++ b/internal/addrs/module_instance.go @@ -275,6 +275,14 @@ func (m ModuleInstance) String() string { return buf.String() } +type moduleInstanceKey string + +func (m ModuleInstance) UniqueKey() UniqueKey { + return moduleInstanceKey(m.String()) +} + +func (mk moduleInstanceKey) uniqueKeySigil() {} + // Equal returns true if the receiver and the given other value // contains the exact same parts. func (m ModuleInstance) Equal(o ModuleInstance) bool { diff --git a/internal/addrs/resource.go b/internal/addrs/resource.go index f22db05cb..a7b7ee308 100644 --- a/internal/addrs/resource.go +++ b/internal/addrs/resource.go @@ -292,6 +292,14 @@ func (r AbsResourceInstance) Less(o AbsResourceInstance) bool { } } +type absResourceInstanceKey string + +func (r AbsResourceInstance) UniqueKey() UniqueKey { + return absResourceInstanceKey(r.String()) +} + +func (r absResourceInstanceKey) uniqueKeySigil() {} + func (r AbsResourceInstance) absMoveableSigil() { // AbsResourceInstance is moveable } diff --git a/internal/addrs/unique_key_test.go b/internal/addrs/unique_key_test.go index 416899ca4..0926a0c37 100644 --- a/internal/addrs/unique_key_test.go +++ b/internal/addrs/unique_key_test.go @@ -46,6 +46,14 @@ func TestUniqueKeyer(t *testing.T) { }, Key: IntKey(1), }, + RootModuleInstance, + RootModuleInstance.Child("foo", NoKey), + RootModuleInstance.ResourceInstance( + DataResourceMode, + "boop", + "beep", + NoKey, + ), Self, } From 22eee529e399f42cacd431682e8f9be0e4b6c925 Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Mon, 12 Jul 2021 12:23:10 -0700 Subject: [PATCH 065/107] addrs: MoveEndpointInModule We previously built out addrs.UnifyMoveEndpoints with a different implementation strategy in mind, but that design turns out to not be viable because it forces us to move to AbsMoveable addresses too soon, before we've done the analysis required to identify chained and nested moves. Instead, UnifyMoveEndpoints will return a new type MoveEndpointInModule which conceptually represents a matching pattern which either matches or doesn't match a particular AbsMoveable. It does this by just binding the unified relative address from the MoveEndpoint to the module where it was declared, and thus allows us to distinguish between the part of the module path which applies to any instances of the given modules vs. the user-specified part which must identify particular module instances. --- internal/addrs/module_call.go | 6 +- internal/addrs/move_endpoint.go | 66 +++--- internal/addrs/move_endpoint_kind.go | 33 +++ internal/addrs/move_endpoint_module.go | 101 ++++++++++ internal/addrs/move_endpoint_test.go | 234 ++++++---------------- internal/addrs/moveable.go | 1 - internal/addrs/moveendpointkind_string.go | 29 +++ internal/refactoring/move_execute.go | 63 ++++++ internal/refactoring/move_statement.go | 43 ++++ 9 files changed, 367 insertions(+), 209 deletions(-) create mode 100644 internal/addrs/move_endpoint_kind.go create mode 100644 internal/addrs/move_endpoint_module.go create mode 100644 internal/addrs/moveendpointkind_string.go create mode 100644 internal/refactoring/move_execute.go create mode 100644 internal/refactoring/move_statement.go diff --git a/internal/addrs/module_call.go b/internal/addrs/module_call.go index c6af85f08..d80b35a58 100644 --- a/internal/addrs/module_call.go +++ b/internal/addrs/module_call.go @@ -53,7 +53,11 @@ func (c AbsModuleCall) absMoveableSigil() { } func (c AbsModuleCall) String() string { - return fmt.Sprintf("%s.%s", c.Module, c.Call.Name) + if len(c.Module) == 0 { + return "module." + c.Call.Name + + } + return fmt.Sprintf("%s.module.%s", c.Module, c.Call.Name) } func (c AbsModuleCall) Instance(key InstanceKey) ModuleInstance { diff --git a/internal/addrs/move_endpoint.go b/internal/addrs/move_endpoint.go index b7c529dd5..2b44c5cd1 100644 --- a/internal/addrs/move_endpoint.go +++ b/internal/addrs/move_endpoint.go @@ -39,6 +39,10 @@ type MoveEndpoint struct { relSubject AbsMoveable } +func (e *MoveEndpoint) ObjectKind() MoveEndpointKind { + return absMoveableEndpointKind(e.relSubject) +} + func (e *MoveEndpoint) String() string { // Our internal pseudo-AbsMovable representing the relative // address (either ModuleInstance or AbsResourceInstance) is @@ -73,7 +77,7 @@ func (e *MoveEndpoint) MightUnifyWith(other *MoveEndpoint) bool { // address, because the rules for whether unify can succeed depend // only on the relative part of the addresses, not on which module // they were declared in. - from, to := UnifyMoveEndpoints(RootModuleInstance, e, other) + from, to := UnifyMoveEndpoints(RootModule, e, other) return from != nil && to != nil } @@ -147,11 +151,10 @@ func ParseMoveEndpoint(traversal hcl.Traversal) (*MoveEndpoint, tfdiags.Diagnost // UnifyMoveEndpoints takes a pair of MoveEndpoint objects representing the // "from" and "to" addresses in a moved block, and returns a pair of -// AbsMoveable addresses guaranteed to be of the same dynamic type +// MoveEndpointInModule addresses guaranteed to be of the same dynamic type // that represent what the two MoveEndpoint addresses refer to. // -// moduleAddr must be the address of the module instance where the move -// was declared. +// moduleAddr must be the address of the module where the move was declared. // // This function deals both with the conversion from relative to absolute // addresses and with resolving the ambiguity between no-key instance @@ -163,7 +166,7 @@ func ParseMoveEndpoint(traversal hcl.Traversal) (*MoveEndpoint, tfdiags.Diagnost // given addresses are incompatible then UnifyMoveEndpoints returns (nil, nil), // in which case the caller should typically report an error to the user // stating the unification constraints. -func UnifyMoveEndpoints(moduleAddr ModuleInstance, relFrom, relTo *MoveEndpoint) (absFrom, absTo AbsMoveable) { +func UnifyMoveEndpoints(moduleAddr Module, relFrom, relTo *MoveEndpoint) (modFrom, modTo *MoveEndpointInModule) { // First we'll make a decision about which address type we're // ultimately trying to unify to. For our internal purposes @@ -197,17 +200,17 @@ func UnifyMoveEndpoints(moduleAddr ModuleInstance, relFrom, relTo *MoveEndpoint) panic("unhandled move address types") } - absFrom = relFrom.prepareAbsMoveable(moduleAddr, wantType) - absTo = relTo.prepareAbsMoveable(moduleAddr, wantType) - if absFrom == nil || absTo == nil { + modFrom = relFrom.prepareMoveEndpointInModule(moduleAddr, wantType) + modTo = relTo.prepareMoveEndpointInModule(moduleAddr, wantType) + if modFrom == nil || modTo == nil { // if either of them failed then they both failed, to make the // caller's life a little easier. return nil, nil } - return absFrom, absTo + return modFrom, modTo } -func (e *MoveEndpoint) prepareAbsMoveable(moduleAddr ModuleInstance, wantType TargetableAddrType) AbsMoveable { +func (e *MoveEndpoint) prepareMoveEndpointInModule(moduleAddr Module, wantType TargetableAddrType) *MoveEndpointInModule { // relAddr can only be either AbsResourceInstance or ModuleInstance, the // internal intermediate representation produced by ParseMoveEndpoint. relAddr := e.relSubject @@ -216,40 +219,43 @@ func (e *MoveEndpoint) prepareAbsMoveable(moduleAddr ModuleInstance, wantType Ta case ModuleInstance: switch wantType { case ModuleInstanceAddrType: - ret := make(ModuleInstance, 0, len(moduleAddr)+len(relAddr)) - ret = append(ret, moduleAddr...) - ret = append(ret, relAddr...) - return ret + // Since our internal representation is already a module instance, + // we can just rewrap this one. + return &MoveEndpointInModule{ + SourceRange: e.SourceRange, + module: moduleAddr, + relSubject: relAddr, + } case ModuleAddrType: // NOTE: We're fudging a little here and using // ModuleAddrType to represent AbsModuleCall rather // than Module. - callerAddr := make(ModuleInstance, 0, len(moduleAddr)+len(relAddr)-1) - callerAddr = append(callerAddr, moduleAddr...) - callerAddr = append(callerAddr, relAddr[:len(relAddr)-1]...) - return AbsModuleCall{ + callerAddr, callAddr := relAddr.Call() + absCallAddr := AbsModuleCall{ Module: callerAddr, - Call: ModuleCall{ - Name: relAddr[len(relAddr)-1].Name, - }, + Call: callAddr, + } + return &MoveEndpointInModule{ + SourceRange: e.SourceRange, + module: moduleAddr, + relSubject: absCallAddr, } default: return nil // can't make any other types from a ModuleInstance } case AbsResourceInstance: - callerAddr := make(ModuleInstance, 0, len(moduleAddr)+len(relAddr.Module)) - callerAddr = append(callerAddr, moduleAddr...) - callerAddr = append(callerAddr, relAddr.Module...) switch wantType { case AbsResourceInstanceAddrType: - return AbsResourceInstance{ - Module: callerAddr, - Resource: relAddr.Resource, + return &MoveEndpointInModule{ + SourceRange: e.SourceRange, + module: moduleAddr, + relSubject: relAddr, } case AbsResourceAddrType: - return AbsResource{ - Module: callerAddr, - Resource: relAddr.Resource.Resource, + return &MoveEndpointInModule{ + SourceRange: e.SourceRange, + module: moduleAddr, + relSubject: relAddr.ContainingResource(), } default: return nil // can't make any other types from an AbsResourceInstance diff --git a/internal/addrs/move_endpoint_kind.go b/internal/addrs/move_endpoint_kind.go new file mode 100644 index 000000000..cd8adab8f --- /dev/null +++ b/internal/addrs/move_endpoint_kind.go @@ -0,0 +1,33 @@ +package addrs + +import "fmt" + +// MoveEndpointKind represents the different kinds of object that a movable +// address can refer to. +type MoveEndpointKind rune + +//go:generate go run golang.org/x/tools/cmd/stringer -type MoveEndpointKind + +const ( + // MoveEndpointModule indicates that a move endpoint either refers to + // an individual module instance or to all instances of a particular + // module call. + MoveEndpointModule MoveEndpointKind = 'M' + + // MoveEndpointResource indicates that a move endpoint either refers to + // an individual resource instance or to all instances of a particular + // resource. + MoveEndpointResource MoveEndpointKind = 'R' +) + +func absMoveableEndpointKind(addr AbsMoveable) MoveEndpointKind { + switch addr := addr.(type) { + case ModuleInstance, AbsModuleCall: + return MoveEndpointModule + case AbsResourceInstance, AbsResource: + return MoveEndpointResource + default: + // The above should be exhaustive for all AbsMoveable types. + panic(fmt.Sprintf("unsupported address type %T", addr)) + } +} diff --git a/internal/addrs/move_endpoint_module.go b/internal/addrs/move_endpoint_module.go new file mode 100644 index 000000000..db07af2cd --- /dev/null +++ b/internal/addrs/move_endpoint_module.go @@ -0,0 +1,101 @@ +package addrs + +import ( + "strings" + + "github.com/hashicorp/terraform/internal/tfdiags" +) + +// MoveEndpointInModule annotates a MoveEndpoint with the address of the +// module where it was declared, which is the form we use for resolving +// whether move statements chain from or are nested within other move +// statements. +type MoveEndpointInModule struct { + // SourceRange is the location of the physical endpoint address + // in configuration, if this MoveEndpoint was decoded from a + // configuration expresson. + SourceRange tfdiags.SourceRange + + // The internals are unexported here because, as with MoveEndpoint, + // we're somewhat abusing AbsMoveable here to represent an address + // relative to the module, rather than as an absolute address. + // Conceptually, the following two fields represent a matching pattern + // for AbsMoveables where the elements of "module" behave as + // ModuleInstanceStep values with a wildcard instance key, because + // a moved block in a module affects all instances of that module. + // Unlike MoveEndpoint, relSubject in this case can be any of the + // address types that implement AbsMoveable. + module Module + relSubject AbsMoveable +} + +func (e *MoveEndpointInModule) ObjectKind() MoveEndpointKind { + return absMoveableEndpointKind(e.relSubject) +} + +// String produces a string representation of the object matching pattern +// represented by the reciever. +// +// Since there is no direct syntax for representing such an object matching +// pattern, this function uses a splat-operator-like representation to stand +// in for the wildcard instance keys. +func (e *MoveEndpointInModule) String() string { + if e == nil { + return "" + } + var buf strings.Builder + for _, name := range e.module { + buf.WriteString("module.") + buf.WriteString(name) + buf.WriteString("[*].") + } + buf.WriteString(e.relSubject.String()) + + // For consistency we'll also use the splat-like wildcard syntax to + // represent the final step being either a resource or module call + // rather than an instance, so we can more easily distinguish the two + // in the string representation. + switch e.relSubject.(type) { + case AbsModuleCall, AbsResource: + buf.WriteString("[*]") + } + + return buf.String() +} + +// SelectsMoveable returns true if the reciever directly selects the object +// represented by the given address, without any consideration of nesting. +// +// This is a good function to use for deciding whether a specific object +// found in the state should be acted on by a particular move statement. +func (e *MoveEndpointInModule) SelectsMoveable(addr AbsMoveable) bool { + // Only addresses of the same kind can possibly match. This guarantees + // that our logic below only needs to deal with combinations of resources + // and resource instances or with combinations of module calls and + // module instances. + if e.ObjectKind() != absMoveableEndpointKind(addr) { + return false + } + + // TODO: implement + return false +} + +// CanChainFrom returns true if the reciever describes an address that could +// potentially select an object that the other given address could select. +// +// In other words, this decides whether the move chaining rule applies, if +// the reciever is the "to" from one statement and the other given address +// is the "from" of another statement. +func (e *MoveEndpointInModule) CanChainFrom(other *MoveEndpointInModule) bool { + // TODO: implement + return false +} + +// NestedWithin returns true if the reciever describes an address that is +// contained within one of the objects that the given other address could +// select. +func (e *MoveEndpointInModule) NestedWithin(other *MoveEndpointInModule) bool { + // TODO: implement + return false +} diff --git a/internal/addrs/move_endpoint_test.go b/internal/addrs/move_endpoint_test.go index a54b79c85..6e117139b 100644 --- a/internal/addrs/move_endpoint_test.go +++ b/internal/addrs/move_endpoint_test.go @@ -5,7 +5,6 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclsyntax" ) @@ -339,245 +338,127 @@ func TestParseMoveEndpoint(t *testing.T) { func TestUnifyMoveEndpoints(t *testing.T) { tests := []struct { InputFrom, InputTo string - Module ModuleInstance - WantFrom, WantTo AbsMoveable + Module Module + WantFrom, WantTo string }{ { InputFrom: `foo.bar`, InputTo: `foo.baz`, - Module: RootModuleInstance, - WantFrom: AbsResource{ - Module: RootModuleInstance, - Resource: Resource{ - Mode: ManagedResourceMode, - Type: "foo", - Name: "bar", - }, - }, - WantTo: AbsResource{ - Module: RootModuleInstance, - Resource: Resource{ - Mode: ManagedResourceMode, - Type: "foo", - Name: "baz", - }, - }, + Module: RootModule, + WantFrom: `foo.bar[*]`, + WantTo: `foo.baz[*]`, }, { InputFrom: `foo.bar`, InputTo: `foo.baz`, - Module: RootModuleInstance.Child("a", NoKey), - WantFrom: AbsResource{ - Module: RootModuleInstance.Child("a", NoKey), - Resource: Resource{ - Mode: ManagedResourceMode, - Type: "foo", - Name: "bar", - }, - }, - WantTo: AbsResource{ - Module: RootModuleInstance.Child("a", NoKey), - Resource: Resource{ - Mode: ManagedResourceMode, - Type: "foo", - Name: "baz", - }, - }, + Module: RootModule.Child("a"), + WantFrom: `module.a[*].foo.bar[*]`, + WantTo: `module.a[*].foo.baz[*]`, }, { InputFrom: `foo.bar`, InputTo: `module.b[0].foo.baz`, - Module: RootModuleInstance.Child("a", NoKey), - WantFrom: AbsResource{ - Module: RootModuleInstance.Child("a", NoKey), - Resource: Resource{ - Mode: ManagedResourceMode, - Type: "foo", - Name: "bar", - }, - }, - WantTo: AbsResource{ - Module: RootModuleInstance.Child("a", NoKey).Child("b", IntKey(0)), - Resource: Resource{ - Mode: ManagedResourceMode, - Type: "foo", - Name: "baz", - }, - }, + Module: RootModule.Child("a"), + WantFrom: `module.a[*].foo.bar[*]`, + WantTo: `module.a[*].module.b[0].foo.baz[*]`, }, { InputFrom: `foo.bar`, InputTo: `foo.bar["thing"]`, - Module: RootModuleInstance, - WantFrom: AbsResourceInstance{ - Module: RootModuleInstance, - Resource: ResourceInstance{ - Resource: Resource{ - Mode: ManagedResourceMode, - Type: "foo", - Name: "bar", - }, - }, - }, - WantTo: AbsResourceInstance{ - Module: RootModuleInstance, - Resource: ResourceInstance{ - Resource: Resource{ - Mode: ManagedResourceMode, - Type: "foo", - Name: "bar", - }, - Key: StringKey("thing"), - }, - }, + Module: RootModule, + WantFrom: `foo.bar`, + WantTo: `foo.bar["thing"]`, }, { InputFrom: `foo.bar["thing"]`, InputTo: `foo.bar`, - Module: RootModuleInstance, - WantFrom: AbsResourceInstance{ - Module: RootModuleInstance, - Resource: ResourceInstance{ - Resource: Resource{ - Mode: ManagedResourceMode, - Type: "foo", - Name: "bar", - }, - Key: StringKey("thing"), - }, - }, - WantTo: AbsResourceInstance{ - Module: RootModuleInstance, - Resource: ResourceInstance{ - Resource: Resource{ - Mode: ManagedResourceMode, - Type: "foo", - Name: "bar", - }, - }, - }, + Module: RootModule, + WantFrom: `foo.bar["thing"]`, + WantTo: `foo.bar`, }, { InputFrom: `foo.bar["a"]`, InputTo: `foo.bar["b"]`, - Module: RootModuleInstance, - WantFrom: AbsResourceInstance{ - Module: RootModuleInstance, - Resource: ResourceInstance{ - Resource: Resource{ - Mode: ManagedResourceMode, - Type: "foo", - Name: "bar", - }, - Key: StringKey("a"), - }, - }, - WantTo: AbsResourceInstance{ - Module: RootModuleInstance, - Resource: ResourceInstance{ - Resource: Resource{ - Mode: ManagedResourceMode, - Type: "foo", - Name: "bar", - }, - Key: StringKey("b"), - }, - }, + Module: RootModule, + WantFrom: `foo.bar["a"]`, + WantTo: `foo.bar["b"]`, }, { InputFrom: `module.foo`, InputTo: `module.bar`, - Module: RootModuleInstance, - WantFrom: AbsModuleCall{ - Module: RootModuleInstance, - Call: ModuleCall{Name: "foo"}, - }, - WantTo: AbsModuleCall{ - Module: RootModuleInstance, - Call: ModuleCall{Name: "bar"}, - }, + Module: RootModule, + WantFrom: `module.foo[*]`, + WantTo: `module.bar[*]`, }, { InputFrom: `module.foo`, InputTo: `module.bar.module.baz`, - Module: RootModuleInstance, - WantFrom: AbsModuleCall{ - Module: RootModuleInstance, - Call: ModuleCall{Name: "foo"}, - }, - WantTo: AbsModuleCall{ - Module: RootModuleInstance.Child("bar", NoKey), - Call: ModuleCall{Name: "baz"}, - }, + Module: RootModule, + WantFrom: `module.foo[*]`, + WantTo: `module.bar.module.baz[*]`, }, { InputFrom: `module.foo`, InputTo: `module.bar.module.baz`, - Module: RootModuleInstance.Child("bloop", StringKey("hi")), - WantFrom: AbsModuleCall{ - Module: RootModuleInstance.Child("bloop", StringKey("hi")), - Call: ModuleCall{Name: "foo"}, - }, - WantTo: AbsModuleCall{ - Module: RootModuleInstance.Child("bloop", StringKey("hi")).Child("bar", NoKey), - Call: ModuleCall{Name: "baz"}, - }, + Module: RootModule.Child("bloop"), + WantFrom: `module.bloop[*].module.foo[*]`, + WantTo: `module.bloop[*].module.bar.module.baz[*]`, }, { InputFrom: `module.foo[0]`, InputTo: `module.foo["a"]`, - Module: RootModuleInstance, - WantFrom: RootModuleInstance.Child("foo", IntKey(0)), - WantTo: RootModuleInstance.Child("foo", StringKey("a")), + Module: RootModule, + WantFrom: `module.foo[0]`, + WantTo: `module.foo["a"]`, }, { InputFrom: `module.foo`, InputTo: `module.foo["a"]`, - Module: RootModuleInstance, - WantFrom: RootModuleInstance.Child("foo", NoKey), - WantTo: RootModuleInstance.Child("foo", StringKey("a")), + Module: RootModule, + WantFrom: `module.foo`, + WantTo: `module.foo["a"]`, }, { InputFrom: `module.foo[0]`, InputTo: `module.foo`, - Module: RootModuleInstance, - WantFrom: RootModuleInstance.Child("foo", IntKey(0)), - WantTo: RootModuleInstance.Child("foo", NoKey), + Module: RootModule, + WantFrom: `module.foo[0]`, + WantTo: `module.foo`, }, { InputFrom: `module.foo[0]`, InputTo: `module.foo`, - Module: RootModuleInstance.Child("bloop", NoKey), - WantFrom: RootModuleInstance.Child("bloop", NoKey).Child("foo", IntKey(0)), - WantTo: RootModuleInstance.Child("bloop", NoKey).Child("foo", NoKey), + Module: RootModule.Child("bloop"), + WantFrom: `module.bloop[*].module.foo[0]`, + WantTo: `module.bloop[*].module.foo`, }, { InputFrom: `module.foo`, InputTo: `foo.bar`, - Module: RootModuleInstance, - WantFrom: nil, // Can't unify module call with resource - WantTo: nil, + Module: RootModule, + WantFrom: ``, // Can't unify module call with resource + WantTo: ``, }, { InputFrom: `module.foo[0]`, InputTo: `foo.bar`, - Module: RootModuleInstance, - WantFrom: nil, // Can't unify module instance with resource - WantTo: nil, + Module: RootModule, + WantFrom: ``, // Can't unify module instance with resource + WantTo: ``, }, { InputFrom: `module.foo`, InputTo: `foo.bar[0]`, - Module: RootModuleInstance, - WantFrom: nil, // Can't unify module call with resource instance - WantTo: nil, + Module: RootModule, + WantFrom: ``, // Can't unify module call with resource instance + WantTo: ``, }, { InputFrom: `module.foo[0]`, InputTo: `foo.bar[0]`, - Module: RootModuleInstance, - WantFrom: nil, // Can't unify module instance with resource instance - WantTo: nil, + Module: RootModule, + WantFrom: ``, // Can't unify module instance with resource instance + WantTo: ``, }, } @@ -604,13 +485,12 @@ func TestUnifyMoveEndpoints(t *testing.T) { fromEp := parseInput(test.InputFrom) toEp := parseInput(test.InputTo) - diffOpts := cmpopts.IgnoreUnexported(ModuleCall{}) gotFrom, gotTo := UnifyMoveEndpoints(test.Module, fromEp, toEp) - if diff := cmp.Diff(test.WantFrom, gotFrom, diffOpts); diff != "" { - t.Errorf("wrong 'from' address\n%s", diff) + if got, want := gotFrom.String(), test.WantFrom; got != want { + t.Errorf("wrong 'from' result\ngot: %s\nwant: %s", got, want) } - if diff := cmp.Diff(test.WantTo, gotTo, diffOpts); diff != "" { - t.Errorf("wrong 'to' address\n%s", diff) + if got, want := gotTo.String(), test.WantTo; got != want { + t.Errorf("wrong 'to' result\ngot: %s\nwant: %s", got, want) } }) } diff --git a/internal/addrs/moveable.go b/internal/addrs/moveable.go index cac6eceb8..fd93b58dc 100644 --- a/internal/addrs/moveable.go +++ b/internal/addrs/moveable.go @@ -9,7 +9,6 @@ package addrs // of the configuration, which is different than the direct representation // of these in configuration where the author gives an address relative to // the current module where the address is defined. The type MoveEndpoint - type AbsMoveable interface { absMoveableSigil() diff --git a/internal/addrs/moveendpointkind_string.go b/internal/addrs/moveendpointkind_string.go new file mode 100644 index 000000000..f706fb9ca --- /dev/null +++ b/internal/addrs/moveendpointkind_string.go @@ -0,0 +1,29 @@ +// Code generated by "stringer -type MoveEndpointKind"; DO NOT EDIT. + +package addrs + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[MoveEndpointModule-77] + _ = x[MoveEndpointResource-82] +} + +const ( + _MoveEndpointKind_name_0 = "MoveEndpointModule" + _MoveEndpointKind_name_1 = "MoveEndpointResource" +) + +func (i MoveEndpointKind) String() string { + switch { + case i == 77: + return _MoveEndpointKind_name_0 + case i == 82: + return _MoveEndpointKind_name_1 + default: + return "MoveEndpointKind(" + strconv.FormatInt(int64(i), 10) + ")" + } +} diff --git a/internal/refactoring/move_execute.go b/internal/refactoring/move_execute.go new file mode 100644 index 000000000..3581793df --- /dev/null +++ b/internal/refactoring/move_execute.go @@ -0,0 +1,63 @@ +package refactoring + +import ( + "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/internal/dag" + "github.com/hashicorp/terraform/internal/states" +) + +type MoveResult struct { + From, To addrs.AbsResourceInstance +} + +// ApplyMoves modifies in-place the given state object so that any existing +// objects that are matched by a "from" argument of one of the move statements +// will be moved to instead appear at the "to" argument of that statement. +// +// The result is a map from the unique key of each absolute address that was +// either the source or destination of a move to a MoveResult describing +// what happened at that address. +// +// ApplyMoves does not have any error situations itself, and will instead just +// ignore any unresolvable move statements. Validation of a set of moves is +// a separate concern applied to the configuration, because validity of +// moves is always dependent only on the configuration, not on the state. +func ApplyMoves(stmts []MoveStatement, state *states.State) map[addrs.UniqueKey]MoveResult { + // The methodology here is to construct a small graph of all of the move + // statements where the edges represent where a particular statement + // is either chained from or nested inside the effect of another statement. + // That then means we can traverse the graph in topological sort order + // to gradually move objects through potentially multiple moves each. + + g := &dag.AcyclicGraph{} + for _, stmt := range stmts { + // The graph nodes are pointers to the actual statements directly. + g.Add(&stmt) + } + + // Now we'll add the edges representing chaining and nesting relationships. + // We assume that a reasonable configuration will have at most tens of + // move statements and thus this N*M algorithm is acceptable. + for _, depender := range stmts { + for _, dependee := range stmts { + dependeeTo := dependee.To + dependerFrom := depender.From + if dependerFrom.CanChainFrom(dependeeTo) || dependerFrom.NestedWithin(dependeeTo) { + g.Connect(dag.BasicEdge(depender, dependee)) + } + } + } + + // If there are any cycles in the graph then we'll not take any action + // at all. The separate validation step should detect this and return + // an error. + if len(g.Cycles()) != 0 { + return nil + } + + // The starting nodes are the ones that don't depend on any other nodes. + //startNodes := make(dag.Set, len(stmts)) + //g.DepthFirstWalk() + + return nil +} diff --git a/internal/refactoring/move_statement.go b/internal/refactoring/move_statement.go new file mode 100644 index 000000000..cb2cff40c --- /dev/null +++ b/internal/refactoring/move_statement.go @@ -0,0 +1,43 @@ +package refactoring + +import ( + "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/internal/configs" + "github.com/hashicorp/terraform/internal/tfdiags" +) + +type MoveStatement struct { + From, To *addrs.MoveEndpointInModule + DeclRange tfdiags.SourceRange +} + +// FindMoveStatements recurses through the modules of the given configuration +// and returns a flat set of all "moved" blocks defined within, in a +// deterministic but undefined order. +func FindMoveStatements(rootCfg *configs.Config) []MoveStatement { + return findMoveStatements(rootCfg, nil) +} + +func findMoveStatements(cfg *configs.Config, into []MoveStatement) []MoveStatement { + modAddr := cfg.Path + for _, mc := range cfg.Module.Moved { + fromAddr, toAddr := addrs.UnifyMoveEndpoints(modAddr, mc.From, mc.To) + if fromAddr == nil || toAddr == nil { + // Invalid combination should get caught by our separate + // validation rules elsewhere. + continue + } + + into = append(into, MoveStatement{ + From: fromAddr, + To: toAddr, + DeclRange: tfdiags.SourceRangeFromHCL(mc.DeclRange), + }) + } + + for _, childCfg := range cfg.Children { + into = findMoveStatements(childCfg, into) + } + + return into +} From 3e5bfa736418e61bd882b2aafe08fb0ba4b80574 Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Mon, 12 Jul 2021 14:26:35 -0700 Subject: [PATCH 066/107] refactoring: Stubbing of the logic for handling moves This is a whole lot of nothing right now, just stubbing out some control flow that ultimately just leads to TODOs that cause it to do nothing at all. My intent here is to get this cross-cutting skeleton in place and thus make it easier for us to collaborate on adding the meat to it, so that it's more likely we can work on different parts separately and still get a result that tessellates. --- internal/addrs/move_endpoint_module.go | 114 ++++++++++-- internal/refactoring/move_execute.go | 150 ++++++++++++--- internal/refactoring/move_execute_test.go | 213 ++++++++++++++++++++++ internal/refactoring/move_statement.go | 15 +- internal/refactoring/move_validate.go | 40 ++++ internal/terraform/context.go | 32 ++++ 6 files changed, 528 insertions(+), 36 deletions(-) create mode 100644 internal/refactoring/move_execute_test.go create mode 100644 internal/refactoring/move_validate.go diff --git a/internal/addrs/move_endpoint_module.go b/internal/addrs/move_endpoint_module.go index db07af2cd..0b6461bd9 100644 --- a/internal/addrs/move_endpoint_module.go +++ b/internal/addrs/move_endpoint_module.go @@ -1,6 +1,7 @@ package addrs import ( + "fmt" "strings" "github.com/hashicorp/terraform/internal/tfdiags" @@ -63,22 +64,66 @@ func (e *MoveEndpointInModule) String() string { return buf.String() } -// SelectsMoveable returns true if the reciever directly selects the object -// represented by the given address, without any consideration of nesting. +// SelectsModule returns true if the reciever directly selects either +// the given module or a resource nested directly inside that module. // -// This is a good function to use for deciding whether a specific object -// found in the state should be acted on by a particular move statement. -func (e *MoveEndpointInModule) SelectsMoveable(addr AbsMoveable) bool { - // Only addresses of the same kind can possibly match. This guarantees - // that our logic below only needs to deal with combinations of resources - // and resource instances or with combinations of module calls and - // module instances. - if e.ObjectKind() != absMoveableEndpointKind(addr) { +// This is a good function to use to decide which modules in a state +// to consider when processing a particular move statement. For a +// module move the given module itself is what will move, while a +// resource move indicates that we should search each of the resources in +// the given module to see if they match. +func (e *MoveEndpointInModule) SelectsModule(addr ModuleInstance) bool { + // In order to match the given module path should be at least as + // long as the path to the module where the move endpoint was defined. + if len(addr) < len(e.module) { return false } - // TODO: implement - return false + containerPart := addr[:len(e.module)] + relPart := addr[len(e.module):] + + // The names of all of the steps that align with e.module must match, + // though the instance keys are wildcards for this part. + for i := range e.module { + if containerPart[i].Name != e.module[i] { + return false + } + } + + // The remaining module address steps must match both name and key. + // The logic for all of these is similar but we will retrieve the + // module address differently for each type. + var relMatch ModuleInstance + switch relAddr := e.relSubject.(type) { + case ModuleInstance: + relMatch = relAddr + case AbsModuleCall: + // This one requires a little more fuss because the call effectively + // slices in two the final step of the module address. + if len(relPart) != len(relAddr.Module)+1 { + return false + } + callPart := relPart[len(relPart)-1] + if callPart.Name != relAddr.Call.Name { + return false + } + case AbsResource: + relMatch = relAddr.Module + case AbsResourceInstance: + relMatch = relAddr.Module + default: + panic(fmt.Sprintf("unhandled relative address type %T", relAddr)) + } + + if len(relPart) != len(relMatch) { + return false + } + for i := range relMatch { + if relPart[i] != relMatch[i] { + return false + } + } + return true } // CanChainFrom returns true if the reciever describes an address that could @@ -99,3 +144,48 @@ func (e *MoveEndpointInModule) NestedWithin(other *MoveEndpointInModule) bool { // TODO: implement return false } + +// MoveDestination considers a an address representing a module +// instance in the context of source and destination move endpoints and then, +// if the module address matches the from endpoint, returns the corresponding +// new module address that the object should move to. +// +// MoveDestination will return false in its second return value if the receiver +// doesn't match fromMatch, indicating that the given move statement doesn't +// apply to this object. +// +// Both of the given endpoints must be from the same move statement and thus +// must have matching object types. If not, MoveDestination will panic. +func (m ModuleInstance) MoveDestination(fromMatch, toMatch *MoveEndpointInModule) (ModuleInstance, bool) { + return nil, false +} + +// MoveDestination considers a an address representing a resource +// in the context of source and destination move endpoints and then, +// if the resource address matches the from endpoint, returns the corresponding +// new resource address that the object should move to. +// +// MoveDestination will return false in its second return value if the receiver +// doesn't match fromMatch, indicating that the given move statement doesn't +// apply to this object. +// +// Both of the given endpoints must be from the same move statement and thus +// must have matching object types. If not, MoveDestination will panic. +func (r AbsResource) MoveDestination(fromMatch, toMatch *MoveEndpointInModule) (AbsResource, bool) { + return AbsResource{}, false +} + +// MoveDestination considers a an address representing a resource +// instance in the context of source and destination move endpoints and then, +// if the instance address matches the from endpoint, returns the corresponding +// new instance address that the object should move to. +// +// MoveDestination will return false in its second return value if the receiver +// doesn't match fromMatch, indicating that the given move statement doesn't +// apply to this object. +// +// Both of the given endpoints must be from the same move statement and thus +// must have matching object types. If not, MoveDestination will panic. +func (r AbsResourceInstance) MoveDestination(fromMatch, toMatch *MoveEndpointInModule) (AbsResourceInstance, bool) { + return AbsResourceInstance{}, false +} diff --git a/internal/refactoring/move_execute.go b/internal/refactoring/move_execute.go index 3581793df..1fc60f85f 100644 --- a/internal/refactoring/move_execute.go +++ b/internal/refactoring/move_execute.go @@ -1,6 +1,8 @@ package refactoring import ( + "fmt" + "github.com/hashicorp/terraform/internal/addrs" "github.com/hashicorp/terraform/internal/dag" "github.com/hashicorp/terraform/internal/states" @@ -22,6 +24,9 @@ type MoveResult struct { // ignore any unresolvable move statements. Validation of a set of moves is // a separate concern applied to the configuration, because validity of // moves is always dependent only on the configuration, not on the state. +// +// ApplyMoves expects exclusive access to the given state while it's running. +// Don't read or write any part of the state structure until ApplyMoves returns. func ApplyMoves(stmts []MoveStatement, state *states.State) map[addrs.UniqueKey]MoveResult { // The methodology here is to construct a small graph of all of the move // statements where the edges represent where a particular statement @@ -29,24 +34,7 @@ func ApplyMoves(stmts []MoveStatement, state *states.State) map[addrs.UniqueKey] // That then means we can traverse the graph in topological sort order // to gradually move objects through potentially multiple moves each. - g := &dag.AcyclicGraph{} - for _, stmt := range stmts { - // The graph nodes are pointers to the actual statements directly. - g.Add(&stmt) - } - - // Now we'll add the edges representing chaining and nesting relationships. - // We assume that a reasonable configuration will have at most tens of - // move statements and thus this N*M algorithm is acceptable. - for _, depender := range stmts { - for _, dependee := range stmts { - dependeeTo := dependee.To - dependerFrom := depender.From - if dependerFrom.CanChainFrom(dependeeTo) || dependerFrom.NestedWithin(dependeeTo) { - g.Connect(dag.BasicEdge(depender, dependee)) - } - } - } + g := buildMoveStatementGraph(stmts) // If there are any cycles in the graph then we'll not take any action // at all. The separate validation step should detect this and return @@ -56,8 +44,128 @@ func ApplyMoves(stmts []MoveStatement, state *states.State) map[addrs.UniqueKey] } // The starting nodes are the ones that don't depend on any other nodes. - //startNodes := make(dag.Set, len(stmts)) - //g.DepthFirstWalk() + startNodes := make(dag.Set, len(stmts)) + for _, v := range g.Vertices() { + if len(g.UpEdges(v)) == 0 { + startNodes.Add(v) + } + } - return nil + results := make(map[addrs.UniqueKey]MoveResult) + g.DepthFirstWalk(startNodes, func(v dag.Vertex, depth int) error { + stmt := v.(*MoveStatement) + + for _, ms := range state.Modules { + modAddr := ms.Addr + if !stmt.From.SelectsModule(modAddr) { + continue + } + + // We now know that the current module is relevant but what + // we'll do with it depends on the object kind. + switch kind := stmt.ObjectKind(); kind { + case addrs.MoveEndpointModule: + // For a module endpoint we just try the module address + // directly. + if newAddr, matches := modAddr.MoveDestination(stmt.From, stmt.To); matches { + // We need to visit all of the resource instances in the + // module and record them individually as results. + for _, rs := range ms.Resources { + relAddr := rs.Addr.Resource + for key := range rs.Instances { + oldInst := relAddr.Instance(key).Absolute(modAddr) + newInst := relAddr.Instance(key).Absolute(newAddr) + result := MoveResult{ + From: oldInst, + To: newInst, + } + results[oldInst.UniqueKey()] = result + results[newInst.UniqueKey()] = result + } + } + + state.MoveModuleInstance(modAddr, newAddr) + continue + } + case addrs.MoveEndpointResource: + // For a resource endpoint we need to search each of the + // resources and resource instances in the module. + for _, rs := range ms.Resources { + rAddr := rs.Addr + if newAddr, matches := rAddr.MoveDestination(stmt.From, stmt.To); matches { + for key := range rs.Instances { + oldInst := rAddr.Instance(key) + newInst := newAddr.Instance(key) + result := MoveResult{ + From: oldInst, + To: newInst, + } + results[oldInst.UniqueKey()] = result + results[newInst.UniqueKey()] = result + } + state.MoveAbsResource(rAddr, newAddr) + continue + } + for key := range rs.Instances { + iAddr := rAddr.Instance(key) + if newAddr, matches := iAddr.MoveDestination(stmt.From, stmt.To); matches { + result := MoveResult{From: iAddr, To: newAddr} + results[iAddr.UniqueKey()] = result + results[newAddr.UniqueKey()] = result + + state.MoveAbsResourceInstance(iAddr, newAddr) + continue + } + } + } + default: + panic(fmt.Sprintf("unhandled move object kind %s", kind)) + } + } + + return nil + }) + + // FIXME: In the case of either chained or nested moves, "results" will + // be left in a pretty interesting shape where the "old" address will + // refer to a result that describes only the first step, while the "new" + // address will refer to a result that describes only the last step. + // To make that actually useful we'll need a different strategy where + // the result describes the _effective_ source and destination, skipping + // over any intermediate steps we took to get there, so that ultimately + // we'll have enough information to annotate items in the plan with the + // addresses the originally moved from. + + return results +} + +// buildMoveStatementGraph constructs a dependency graph of the given move +// statements, where the nodes are all pointers to statements in the given +// slice and the edges represent either chaining or nesting relationships. +// +// buildMoveStatementGraph doesn't do any validation of the graph, so it +// may contain cycles and other sorts of invalidity. +func buildMoveStatementGraph(stmts []MoveStatement) *dag.AcyclicGraph { + g := &dag.AcyclicGraph{} + for _, stmt := range stmts { + // The graph nodes are pointers to the actual statements directly. + g.Add(&stmt) + } + + // Now we'll add the edges representing chaining and nesting relationships. + // We assume that a reasonable configuration will have at most tens of + // move statements and thus this N*M algorithm is acceptable. + for dependerI := range stmts { + depender := &stmts[dependerI] + for dependeeI := range stmts { + dependee := &stmts[dependeeI] + dependeeTo := dependee.To + dependerFrom := depender.From + if dependerFrom.CanChainFrom(dependeeTo) || dependerFrom.NestedWithin(dependeeTo) { + g.Connect(dag.BasicEdge(depender, dependee)) + } + } + } + + return g } diff --git a/internal/refactoring/move_execute_test.go b/internal/refactoring/move_execute_test.go new file mode 100644 index 000000000..eed56e911 --- /dev/null +++ b/internal/refactoring/move_execute_test.go @@ -0,0 +1,213 @@ +package refactoring + +import ( + "fmt" + "sort" + "strings" + "testing" + + "github.com/davecgh/go-spew/spew" + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/hcl/v2" + "github.com/hashicorp/hcl/v2/hclsyntax" + "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/internal/states" +) + +func TestApplyMoves(t *testing.T) { + // TODO: Renable this once we're ready to implement the intended behaviors + // it is describing. + t.Skip("ApplyMoves is not yet fully implemented") + + providerAddr := addrs.AbsProviderConfig{ + Module: addrs.RootModule, + Provider: addrs.MustParseProviderSourceString("example.com/foo/bar"), + } + rootNoKeyResourceAddr := [...]addrs.AbsResourceInstance{ + addrs.Resource{ + Mode: addrs.ManagedResourceMode, + Type: "foo", + Name: "from", + }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), + addrs.Resource{ + Mode: addrs.ManagedResourceMode, + Type: "foo", + Name: "to", + }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), + } + rootIntKeyResourceAddr := [...]addrs.AbsResourceInstance{ + addrs.Resource{ + Mode: addrs.ManagedResourceMode, + Type: "foo", + Name: "from", + }.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance), + addrs.Resource{ + Mode: addrs.ManagedResourceMode, + Type: "foo", + Name: "to", + }.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance), + } + + tests := map[string]struct { + Stmts []MoveStatement + State *states.State + + WantResults map[addrs.UniqueKey]MoveResult + WantInstanceAddrs []string + }{ + "no moves and empty state": { + []MoveStatement{}, + states.NewState(), + nil, + nil, + }, + "no moves": { + []MoveStatement{}, + states.BuildState(func(s *states.SyncState) { + s.SetResourceInstanceCurrent( + rootNoKeyResourceAddr[0], + &states.ResourceInstanceObjectSrc{ + Status: states.ObjectReady, + AttrsJSON: []byte(`{}`), + }, + providerAddr, + ) + }), + nil, + []string{ + `foo.from`, + }, + }, + "single move of whole singleton resource": { + []MoveStatement{ + testMoveStatement(t, "", "foo.from", "foo.to"), + }, + states.BuildState(func(s *states.SyncState) { + s.SetResourceInstanceCurrent( + rootNoKeyResourceAddr[0], + &states.ResourceInstanceObjectSrc{ + Status: states.ObjectReady, + AttrsJSON: []byte(`{}`), + }, + providerAddr, + ) + }), + map[addrs.UniqueKey]MoveResult{ + rootNoKeyResourceAddr[0].UniqueKey(): { + From: rootNoKeyResourceAddr[0], + To: rootNoKeyResourceAddr[1], + }, + rootNoKeyResourceAddr[1].UniqueKey(): { + From: rootNoKeyResourceAddr[1], + To: rootNoKeyResourceAddr[1], + }, + }, + []string{ + `foo.to`, + }, + }, + "single move of whole 'count' resource": { + []MoveStatement{ + testMoveStatement(t, "", "foo.from", "foo.to"), + }, + states.BuildState(func(s *states.SyncState) { + s.SetResourceInstanceCurrent( + rootIntKeyResourceAddr[0], + &states.ResourceInstanceObjectSrc{ + Status: states.ObjectReady, + AttrsJSON: []byte(`{}`), + }, + providerAddr, + ) + }), + map[addrs.UniqueKey]MoveResult{ + rootNoKeyResourceAddr[0].UniqueKey(): { + From: rootIntKeyResourceAddr[0], + To: rootIntKeyResourceAddr[1], + }, + rootNoKeyResourceAddr[1].UniqueKey(): { + From: rootIntKeyResourceAddr[0], + To: rootIntKeyResourceAddr[1], + }, + }, + []string{ + `foo.to[0]`, + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + var stmtsBuf strings.Builder + for _, stmt := range test.Stmts { + fmt.Fprintf(&stmtsBuf, "- from: %s\n to: %s", stmt.From, stmt.To) + } + t.Logf("move statements:\n%s", stmtsBuf.String()) + + t.Logf("resource instances in prior state:\n%s", spew.Sdump(allResourceInstanceAddrsInState(test.State))) + + state := test.State.DeepCopy() // don't modify the test case in-place + gotResults := ApplyMoves(test.Stmts, state) + + if diff := cmp.Diff(test.WantResults, gotResults); diff != "" { + t.Errorf("wrong results\n%s", diff) + } + + gotInstAddrs := allResourceInstanceAddrsInState(state) + if diff := cmp.Diff(test.WantInstanceAddrs, gotInstAddrs); diff != "" { + t.Errorf("wrong resource instances in final state\n%s", diff) + } + }) + } +} + +func testMoveStatement(t *testing.T, module string, from string, to string) MoveStatement { + t.Helper() + + moduleAddr := addrs.RootModule + if len(module) != 0 { + moduleAddr = addrs.Module(strings.Split(module, ".")) + } + + fromTraversal, hclDiags := hclsyntax.ParseTraversalAbs([]byte(from), "from", hcl.InitialPos) + if hclDiags.HasErrors() { + t.Fatalf("invalid 'from' argument: %s", hclDiags.Error()) + } + fromAddr, diags := addrs.ParseMoveEndpoint(fromTraversal) + if diags.HasErrors() { + t.Fatalf("invalid 'from' argument: %s", diags.Err().Error()) + } + toTraversal, hclDiags := hclsyntax.ParseTraversalAbs([]byte(to), "to", hcl.InitialPos) + if diags.HasErrors() { + t.Fatalf("invalid 'to' argument: %s", hclDiags.Error()) + } + toAddr, diags := addrs.ParseMoveEndpoint(toTraversal) + if diags.HasErrors() { + t.Fatalf("invalid 'from' argument: %s", diags.Err().Error()) + } + + fromInModule, toInModule := addrs.UnifyMoveEndpoints(moduleAddr, fromAddr, toAddr) + if fromInModule == nil || toInModule == nil { + t.Fatalf("incompatible endpoints") + } + + return MoveStatement{ + From: fromInModule, + To: toInModule, + + // DeclRange not populated because it's unimportant for our tests + } +} + +func allResourceInstanceAddrsInState(state *states.State) []string { + var ret []string + for _, ms := range state.Modules { + for _, rs := range ms.Resources { + for key := range rs.Instances { + ret = append(ret, rs.Addr.Instance(key).String()) + } + } + } + sort.Strings(ret) + return ret +} diff --git a/internal/refactoring/move_statement.go b/internal/refactoring/move_statement.go index cb2cff40c..59f7f55de 100644 --- a/internal/refactoring/move_statement.go +++ b/internal/refactoring/move_statement.go @@ -1,6 +1,8 @@ package refactoring import ( + "fmt" + "github.com/hashicorp/terraform/internal/addrs" "github.com/hashicorp/terraform/internal/configs" "github.com/hashicorp/terraform/internal/tfdiags" @@ -23,9 +25,9 @@ func findMoveStatements(cfg *configs.Config, into []MoveStatement) []MoveStateme for _, mc := range cfg.Module.Moved { fromAddr, toAddr := addrs.UnifyMoveEndpoints(modAddr, mc.From, mc.To) if fromAddr == nil || toAddr == nil { - // Invalid combination should get caught by our separate - // validation rules elsewhere. - continue + // Invalid combination should've been caught during original + // configuration decoding, in the configs package. + panic(fmt.Sprintf("incompatible move endpoints in %s", mc.DeclRange)) } into = append(into, MoveStatement{ @@ -41,3 +43,10 @@ func findMoveStatements(cfg *configs.Config, into []MoveStatement) []MoveStateme return into } + +func (s *MoveStatement) ObjectKind() addrs.MoveEndpointKind { + // addrs.UnifyMoveEndpoints guarantees that both of our addresses have + // the same kind, so we can just arbitrary use From and assume To will + // match it. + return s.From.ObjectKind() +} diff --git a/internal/refactoring/move_validate.go b/internal/refactoring/move_validate.go new file mode 100644 index 000000000..40ee5f654 --- /dev/null +++ b/internal/refactoring/move_validate.go @@ -0,0 +1,40 @@ +package refactoring + +import ( + "fmt" + + "github.com/hashicorp/terraform/internal/configs" + "github.com/hashicorp/terraform/internal/instances" + "github.com/hashicorp/terraform/internal/tfdiags" +) + +// ValidateMoves tests whether all of the given move statements comply with +// both the single-statement validation rules and the "big picture" rules +// that constrain statements in relation to one another. +// +// The validation rules are primarily in terms of the configuration, but +// ValidateMoves also takes the expander that resulted from creating a plan +// so that it can see which instances are defined for each module and resource, +// to precisely validate move statements involving specific-instance addresses. +// +// Because validation depends on the planning result but move execution must +// happen _before_ planning, we have the unusual situation where sibling +// function ApplyMoves must run before ValidateMoves and must therefore +// tolerate and ignore any invalid statements. The plan walk will then +// construct in incorrect plan (because it'll be starting from the wrong +// prior state) but ValidateMoves will block actually showing that invalid +// plan to the user. +func ValidateMoves(stmts []MoveStatement, rootCfg *configs.Config, expander *instances.Expander) tfdiags.Diagnostics { + var diags tfdiags.Diagnostics + + g := buildMoveStatementGraph(stmts) + + if len(g.Cycles()) != 0 { + // TODO: proper error messages for this + diags = diags.Append(fmt.Errorf("move statement cycles")) + } + + // TODO: Various other validation rules + + return diags +} diff --git a/internal/terraform/context.go b/internal/terraform/context.go index c0934d778..3ae479eed 100644 --- a/internal/terraform/context.go +++ b/internal/terraform/context.go @@ -15,6 +15,7 @@ import ( "github.com/hashicorp/terraform/internal/plans" "github.com/hashicorp/terraform/internal/providers" "github.com/hashicorp/terraform/internal/provisioners" + "github.com/hashicorp/terraform/internal/refactoring" "github.com/hashicorp/terraform/internal/states" "github.com/hashicorp/terraform/internal/tfdiags" "github.com/zclconf/go-cty/cty" @@ -608,6 +609,33 @@ The -target option is not for routine use, and is provided only for exceptional )) } + moveStmts := refactoring.FindMoveStatements(c.config) + if len(moveStmts) != 0 { + // TEMP: we haven't fully implemented moving yet, so we'll just + // reject it outright for now to reduce confusion. + diags = diags.Append(tfdiags.Sourceless( + tfdiags.Error, + "Moves are not yet supported", + "There is currently no handling of \"moved\" blocks in the configuration.", + )) + } + moveResults := refactoring.ApplyMoves(moveStmts, c.prevRunState) + if len(c.targets) > 0 { + for _, result := range moveResults { + matchesTarget := false + for _, targetAddr := range c.targets { + if targetAddr.TargetContains(result.From) { + matchesTarget = true + break + } + } + if !matchesTarget { + // TODO: Return an error stating that a targeted plan is + // only valid if it includes this address that was moved. + } + } + } + var plan *plans.Plan var planDiags tfdiags.Diagnostics switch c.planMode { @@ -625,6 +653,10 @@ The -target option is not for routine use, and is provided only for exceptional return nil, diags } + // TODO: Call refactoring.ValidateMoves, but need to figure out how to + // get hold of the plan's expander here, or somehow otherwise export + // the necessary subset of its data for ValidateMoves to do its work. + // convert the variables into the format expected for the plan varVals := make(map[string]plans.DynamicValue, len(c.variables)) for k, iv := range c.variables { From c495caafeb15d37492a85de07809e44625924999 Mon Sep 17 00:00:00 2001 From: xiaozhu36 Date: Thu, 15 Jul 2021 16:07:18 +0800 Subject: [PATCH 067/107] backend/oss: Changes the DescribeEndpoint to DescribeEndpoints to fixes the unsupported sts bug --- internal/backend/remote-state/oss/backend.go | 26 +++++++------------ .../backend/remote-state/oss/backend_test.go | 10 ++++--- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/internal/backend/remote-state/oss/backend.go b/internal/backend/remote-state/oss/backend.go index e8e357a73..de08af37d 100644 --- a/internal/backend/remote-state/oss/backend.go +++ b/internal/backend/remote-state/oss/backend.go @@ -319,20 +319,14 @@ func (b *Backend) configure(ctx context.Context) error { } if endpoint == "" { - endpointItem, _ := b.getOSSEndpointByRegion(accessKey, secretKey, securityToken, region) - if endpointItem != nil && len(endpointItem.Endpoint) > 0 { - if len(endpointItem.Protocols.Protocols) > 0 { - // HTTP or HTTPS - schma = strings.ToLower(endpointItem.Protocols.Protocols[0]) - for _, p := range endpointItem.Protocols.Protocols { - if strings.ToLower(p) == "https" { - schma = strings.ToLower(p) - break - } - } + endpointsResponse, _ := b.getOSSEndpointByRegion(accessKey, secretKey, securityToken, region) + for _, endpointItem := range endpointsResponse.Endpoints.Endpoint { + if endpointItem.Type == "openAPI" { + endpoint = endpointItem.Endpoint + break } - endpoint = endpointItem.Endpoint - } else { + } + if endpoint == "" { endpoint = fmt.Sprintf("oss-%s.aliyuncs.com", region) } } @@ -367,8 +361,8 @@ func (b *Backend) configure(ctx context.Context) error { return err } -func (b *Backend) getOSSEndpointByRegion(access_key, secret_key, security_token, region string) (*location.DescribeEndpointResponse, error) { - args := location.CreateDescribeEndpointRequest() +func (b *Backend) getOSSEndpointByRegion(access_key, secret_key, security_token, region string) (*location.DescribeEndpointsResponse, error) { + args := location.CreateDescribeEndpointsRequest() args.ServiceCode = "oss" args.Id = region args.Domain = "location-readonly.aliyuncs.com" @@ -379,7 +373,7 @@ func (b *Backend) getOSSEndpointByRegion(access_key, secret_key, security_token, } locationClient.AppendUserAgent(TerraformUA, TerraformVersion) - endpointsResponse, err := locationClient.DescribeEndpoint(args) + endpointsResponse, err := locationClient.DescribeEndpoints(args) if err != nil { return nil, fmt.Errorf("Describe oss endpoint using region: %#v got an error: %#v.", region, err) } diff --git a/internal/backend/remote-state/oss/backend_test.go b/internal/backend/remote-state/oss/backend_test.go index e11e46eb2..e9bc88716 100644 --- a/internal/backend/remote-state/oss/backend_test.go +++ b/internal/backend/remote-state/oss/backend_test.go @@ -2,6 +2,7 @@ package oss import ( "fmt" + "math/rand" "os" "testing" "time" @@ -69,9 +70,10 @@ func TestBackendConfig(t *testing.T) { func TestBackendConfigWorkSpace(t *testing.T) { testACC(t) + bucketName := fmt.Sprintf("terraform-backend-oss-test-%d", rand.Intn(1000)) config := map[string]interface{}{ "region": "cn-beijing", - "bucket": "terraform-backend-oss-test", + "bucket": bucketName, "prefix": "mystate", "key": "first.tfstate", "tablestore_endpoint": "https://terraformstate.cn-beijing.ots.aliyuncs.com", @@ -79,15 +81,15 @@ func TestBackendConfigWorkSpace(t *testing.T) { } b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(config)).(*Backend) - createOSSBucket(t, b.ossClient, "terraform-backend-oss-test") - defer deleteOSSBucket(t, b.ossClient, "terraform-backend-oss-test") + createOSSBucket(t, b.ossClient, bucketName) + defer deleteOSSBucket(t, b.ossClient, bucketName) if _, err := b.Workspaces(); err != nil { t.Fatal(err.Error()) } if !strings.HasPrefix(b.ossClient.Config.Endpoint, "https://oss-cn-beijing") { t.Fatalf("Incorrect region was provided") } - if b.bucketName != "terraform-backend-oss-test" { + if b.bucketName != bucketName { t.Fatalf("Incorrect bucketName was provided") } if b.statePrefix != "mystate" { From c51112a30ceee0cd752c4a8fa97db8fea51efe15 Mon Sep 17 00:00:00 2001 From: Alisdair McDiarmid Date: Thu, 15 Jul 2021 12:03:01 -0400 Subject: [PATCH 068/107] Fix flapping JSON output test This test would previously fail randomly due to the use of multiple resource instances. Instance keys are iterated over as a map for presentation, which has intentionally inconsistent ordering. To fix this, I changed the test to use different resource addresses for the three drift cases. I also extracted them to a separate test, and tweaked the test helper functions to reduce the number of fatal exit points, to make failed test debugging easier. --- internal/command/views/json_view_test.go | 10 +- internal/command/views/operation_test.go | 221 +++++++++++++---------- 2 files changed, 135 insertions(+), 96 deletions(-) diff --git a/internal/command/views/json_view_test.go b/internal/command/views/json_view_test.go index a88e50299..c755cf0b7 100644 --- a/internal/command/views/json_view_test.go +++ b/internal/command/views/json_view_test.go @@ -303,12 +303,16 @@ func testJSONViewOutputEqualsFull(t *testing.T, output string, want []map[string gotLines := strings.Split(output, "\n") if len(gotLines) != len(want) { - t.Fatalf("unexpected number of messages. got %d, want %d", len(gotLines), len(want)) + t.Errorf("unexpected number of messages. got %d, want %d", len(gotLines), len(want)) } // Unmarshal each line and compare to the expected value for i := range gotLines { var gotStruct map[string]interface{} + if i >= len(want) { + t.Error("reached end of want messages too soon") + break + } wantStruct := want[i] if err := json.Unmarshal([]byte(gotLines[i]), &gotStruct); err != nil { @@ -323,12 +327,12 @@ func testJSONViewOutputEqualsFull(t *testing.T, output string, want []map[string // Verify the timestamp format if _, err := time.Parse("2006-01-02T15:04:05.000000Z07:00", timestamp.(string)); err != nil { - t.Fatalf("error parsing timestamp: %s", err) + t.Errorf("error parsing timestamp on line %d: %s", i, err) } } if !cmp.Equal(wantStruct, gotStruct) { - t.Fatalf("unexpected output on line %d:\n%s", i, cmp.Diff(wantStruct, gotStruct)) + t.Errorf("unexpected output on line %d:\n%s", i, cmp.Diff(wantStruct, gotStruct)) } } } diff --git a/internal/command/views/operation_test.go b/internal/command/views/operation_test.go index 4f9c20e8a..7d2964443 100644 --- a/internal/command/views/operation_test.go +++ b/internal/command/views/operation_test.go @@ -517,103 +517,10 @@ func TestOperationJSON_plan(t *testing.T) { }, }, }, - PrevRunState: states.BuildState(func(state *states.SyncState) { - // Update - state.SetResourceInstanceCurrent( - boop.Instance(addrs.IntKey(0)).Absolute(root), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"foo":"bar"}`), - }, - root.ProviderConfigDefault(addrs.NewDefaultProvider("test")), - ) - // Delete - state.SetResourceInstanceCurrent( - boop.Instance(addrs.IntKey(1)).Absolute(root), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"foo":"boop"}`), - }, - root.ProviderConfigDefault(addrs.NewDefaultProvider("test")), - ) - // No-op - state.SetResourceInstanceCurrent( - beep.Instance(addrs.NoKey).Absolute(root), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"foo":"boop"}`), - }, - root.ProviderConfigDefault(addrs.NewDefaultProvider("test")), - ) - }), - PriorState: states.BuildState(func(state *states.SyncState) { - // Update - state.SetResourceInstanceCurrent( - boop.Instance(addrs.IntKey(0)).Absolute(root), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"foo":"baz"}`), - }, - root.ProviderConfigDefault(addrs.NewDefaultProvider("test")), - ) - // Delete - state.SetResourceInstanceCurrent( - boop.Instance(addrs.IntKey(1)).Absolute(root), - nil, - root.ProviderConfigDefault(addrs.NewDefaultProvider("test")), - ) - // No-op - state.SetResourceInstanceCurrent( - beep.Instance(addrs.NoKey).Absolute(root), - &states.ResourceInstanceObjectSrc{ - Status: states.ObjectReady, - AttrsJSON: []byte(`{"foo":"boop"}`), - }, - root.ProviderConfigDefault(addrs.NewDefaultProvider("test")), - ) - }), } v.Plan(plan, testSchemas()) want := []map[string]interface{}{ - // Drift detected: update - { - "@level": "info", - "@message": "test_resource.boop[0]: Drift detected (update)", - "@module": "terraform.ui", - "type": "resource_drift", - "change": map[string]interface{}{ - "action": "update", - "resource": map[string]interface{}{ - "addr": "test_resource.boop[0]", - "implied_provider": "test", - "module": "", - "resource": "test_resource.boop[0]", - "resource_key": float64(0), - "resource_name": "boop", - "resource_type": "test_resource", - }, - }, - }, - // Drift detected: delete - { - "@level": "info", - "@message": "test_resource.boop[1]: Drift detected (delete)", - "@module": "terraform.ui", - "type": "resource_drift", - "change": map[string]interface{}{ - "action": "delete", - "resource": map[string]interface{}{ - "addr": "test_resource.boop[1]", - "implied_provider": "test", - "module": "", - "resource": "test_resource.boop[1]", - "resource_key": float64(1), - "resource_name": "boop", - "resource_type": "test_resource", - }, - }, - }, // Create-then-delete should result in replace { "@level": "info", @@ -728,6 +635,134 @@ func TestOperationJSON_plan(t *testing.T) { testJSONViewOutputEquals(t, done(t).Stdout(), want) } +func TestOperationJSON_planDrift(t *testing.T) { + streams, done := terminal.StreamsForTesting(t) + v := &OperationJSON{view: NewJSONView(NewView(streams))} + + root := addrs.RootModuleInstance + boop := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_resource", Name: "boop"} + beep := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_resource", Name: "beep"} + derp := addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "test_resource", Name: "derp"} + + plan := &plans.Plan{ + Changes: &plans.Changes{ + Resources: []*plans.ResourceInstanceChangeSrc{}, + }, + PrevRunState: states.BuildState(func(state *states.SyncState) { + // Update + state.SetResourceInstanceCurrent( + boop.Instance(addrs.NoKey).Absolute(root), + &states.ResourceInstanceObjectSrc{ + Status: states.ObjectReady, + AttrsJSON: []byte(`{"foo":"bar"}`), + }, + root.ProviderConfigDefault(addrs.NewDefaultProvider("test")), + ) + // Delete + state.SetResourceInstanceCurrent( + beep.Instance(addrs.NoKey).Absolute(root), + &states.ResourceInstanceObjectSrc{ + Status: states.ObjectReady, + AttrsJSON: []byte(`{"foo":"boop"}`), + }, + root.ProviderConfigDefault(addrs.NewDefaultProvider("test")), + ) + // No-op + state.SetResourceInstanceCurrent( + derp.Instance(addrs.NoKey).Absolute(root), + &states.ResourceInstanceObjectSrc{ + Status: states.ObjectReady, + AttrsJSON: []byte(`{"foo":"boop"}`), + }, + root.ProviderConfigDefault(addrs.NewDefaultProvider("test")), + ) + }), + PriorState: states.BuildState(func(state *states.SyncState) { + // Update + state.SetResourceInstanceCurrent( + boop.Instance(addrs.NoKey).Absolute(root), + &states.ResourceInstanceObjectSrc{ + Status: states.ObjectReady, + AttrsJSON: []byte(`{"foo":"baz"}`), + }, + root.ProviderConfigDefault(addrs.NewDefaultProvider("test")), + ) + // Delete + state.SetResourceInstanceCurrent( + beep.Instance(addrs.NoKey).Absolute(root), + nil, + root.ProviderConfigDefault(addrs.NewDefaultProvider("test")), + ) + // No-op + state.SetResourceInstanceCurrent( + derp.Instance(addrs.NoKey).Absolute(root), + &states.ResourceInstanceObjectSrc{ + Status: states.ObjectReady, + AttrsJSON: []byte(`{"foo":"boop"}`), + }, + root.ProviderConfigDefault(addrs.NewDefaultProvider("test")), + ) + }), + } + v.Plan(plan, testSchemas()) + + want := []map[string]interface{}{ + // Drift detected: update + { + "@level": "info", + "@message": "test_resource.boop: Drift detected (update)", + "@module": "terraform.ui", + "type": "resource_drift", + "change": map[string]interface{}{ + "action": "update", + "resource": map[string]interface{}{ + "addr": "test_resource.boop", + "implied_provider": "test", + "module": "", + "resource": "test_resource.boop", + "resource_key": nil, + "resource_name": "boop", + "resource_type": "test_resource", + }, + }, + }, + // Drift detected: delete + { + "@level": "info", + "@message": "test_resource.beep: Drift detected (delete)", + "@module": "terraform.ui", + "type": "resource_drift", + "change": map[string]interface{}{ + "action": "delete", + "resource": map[string]interface{}{ + "addr": "test_resource.beep", + "implied_provider": "test", + "module": "", + "resource": "test_resource.beep", + "resource_key": nil, + "resource_name": "beep", + "resource_type": "test_resource", + }, + }, + }, + // No changes + { + "@level": "info", + "@message": "Plan: 0 to add, 0 to change, 0 to destroy.", + "@module": "terraform.ui", + "type": "change_summary", + "changes": map[string]interface{}{ + "operation": "plan", + "add": float64(0), + "change": float64(0), + "remove": float64(0), + }, + }, + } + + testJSONViewOutputEquals(t, done(t).Stdout(), want) +} + func TestOperationJSON_plannedChange(t *testing.T) { streams, done := terminal.StreamsForTesting(t) v := &OperationJSON{view: NewJSONView(NewView(streams))} From 563f1436eb3086677ffd53532cff47ef039b570d Mon Sep 17 00:00:00 2001 From: Kristin Laemmert Date: Thu, 15 Jul 2021 12:22:17 -0400 Subject: [PATCH 069/107] various docs updates (#29018) * website/docs: add sensitivity warning to output documentation fixes #28005 * website/docs: add note about ** to fileset documentation closes #24220 * website/docs: add note that `dynamic` expressions aren't included in json config output closes #28346 * website: the provider installer isn't necessarily concurrency safe closes #28367 --- website/docs/cli/commands/output.html.md | 4 ++++ website/docs/cli/config/config-file.html.md | 4 ++++ website/docs/internals/json-format.html.md | 2 ++ website/docs/language/functions/fileset.html.md | 4 ++++ 4 files changed, 14 insertions(+) diff --git a/website/docs/cli/commands/output.html.md b/website/docs/cli/commands/output.html.md index 1a828612d..a09725e21 100644 --- a/website/docs/cli/commands/output.html.md +++ b/website/docs/cli/commands/output.html.md @@ -33,6 +33,10 @@ The command-line flags are all optional. The list of available flags are: * `-state=path` - Path to the state file. Defaults to "terraform.tfstate". Ignored when [remote state](/docs/language/state/remote.html) is used. +-> **Note:** When using the `-json` or `-raw` command-line flag, any sensitive +values in Terraform state will be displayed in plain text. For more information, +see [Sensitive Data in State](/docs/language/state/sensitive-data.html). + ## Examples These examples assume the following Terraform output snippet. diff --git a/website/docs/cli/config/config-file.html.md b/website/docs/cli/config/config-file.html.md index cc4a1763a..2df6203f3 100644 --- a/website/docs/cli/config/config-file.html.md +++ b/website/docs/cli/config/config-file.html.md @@ -358,6 +358,10 @@ Terraform will never itself delete a plugin from the plugin cache once it has been placed there. Over time, as plugins are upgraded, the cache directory may grow to contain several unused versions which you must delete manually. +-> **Note:** The plugin cache directory is not guaranteed to be concurrency +safe. The provider installer's behavior in environments with multiple `terraform +init` calls is undefined. + ### Development Overrides for Provider Developers -> **Note:** Development overrides work only in Terraform v0.14 and later. diff --git a/website/docs/internals/json-format.html.md b/website/docs/internals/json-format.html.md index d2c9cff69..9a3efeff5 100644 --- a/website/docs/internals/json-format.html.md +++ b/website/docs/internals/json-format.html.md @@ -451,6 +451,8 @@ Each unevaluated expression in the configuration is represented with an ` **Note:** Expressions in `dynamic` blocks are not included in the configuration representation. + ### Block Expressions Representation In some cases, it is the entire content of a block (possibly after certain special arguments have already been handled and removed) that must be represented. For that, we have an `` structure: diff --git a/website/docs/language/functions/fileset.html.md b/website/docs/language/functions/fileset.html.md index 147ac08ba..820f42d43 100644 --- a/website/docs/language/functions/fileset.html.md +++ b/website/docs/language/functions/fileset.html.md @@ -26,6 +26,10 @@ Supported pattern matches: - `[CLASS]` - matches any single non-separator character inside a class of characters (see below) - `[^CLASS]` - matches any single non-separator character outside a class of characters (see below) +Note that the doublestar (`**`) must appear as a path component by itself. A +pattern such as /path** is invalid and will be treated the same as /path*, but +/path*/** should achieve the desired result. + Character classes support the following: - `[abc]` - matches any single character within the set From 8bdea502ab05d5fa7bf78f7b376b9d12264ad03a Mon Sep 17 00:00:00 2001 From: Paddy Date: Thu, 15 Jul 2021 09:39:40 -0700 Subject: [PATCH 070/107] Add support for protocol 6 providers during init. (#29153) Update the version constraints for what providers will be downloaded from the registry, allowing protocol 6 providers to be downloaded from the registry. --- internal/getproviders/registry_client.go | 2 +- internal/getproviders/registry_client_test.go | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/internal/getproviders/registry_client.go b/internal/getproviders/registry_client.go index ac0abd4c6..0a9c5e80a 100644 --- a/internal/getproviders/registry_client.go +++ b/internal/getproviders/registry_client.go @@ -55,7 +55,7 @@ func init() { configureRequestTimeout() } -var SupportedPluginProtocols = MustParseVersionConstraints("~> 5") +var SupportedPluginProtocols = MustParseVersionConstraints(">= 5, <7") // registryClient is a client for the provider registry protocol that is // specialized only for the needs of this package. It's not intended as a diff --git a/internal/getproviders/registry_client_test.go b/internal/getproviders/registry_client_test.go index 252d4dd00..85fe00aa8 100644 --- a/internal/getproviders/registry_client_test.go +++ b/internal/getproviders/registry_client_test.go @@ -218,6 +218,10 @@ func fakeRegistryHandler(resp http.ResponseWriter, req *http.Request) { resp.Header().Set("Content-Type", "application/json") resp.WriteHeader(200) resp.Write([]byte(`{"versions":[{"version":"1.0.0","protocols":["0.1"]}]}`)) + case "weaksauce/protocol-six": + resp.Header().Set("Content-Type", "application/json") + resp.WriteHeader(200) + resp.Write([]byte(`{"versions":[{"version":"1.0.0","protocols":["6.0"]}]}`)) case "weaksauce/no-versions": resp.Header().Set("Content-Type", "application/json") resp.WriteHeader(200) @@ -412,6 +416,12 @@ func TestFindClosestProtocolCompatibleVersion(t *testing.T) { versions.Unspecified, ``, }, + "provider protocol six": { + addrs.MustParseProviderSourceString("example.com/weaksauce/protocol-six"), + MustParseVersion("1.0.0"), + MustParseVersion("1.0.0"), + ``, + }, } for name, test := range tests { t.Run(name, func(t *testing.T) { From 0d80a745390e67ac675403f52c68e60e1ec26fd1 Mon Sep 17 00:00:00 2001 From: Kristin Laemmert Date: Thu, 15 Jul 2021 13:00:07 -0400 Subject: [PATCH 071/107] configs/configschema: fix missing "computed" attributes from NestedObject's ImpliedType (#29172) * configs/configschema: fix missing "computed" attributes from NestedObject's ImpliedType listOptionalAttrsFromObject was not including "computed" attributes in the list of optional object attributes. This is now fixed. I've also added some tests and fixed some panics and otherwise bad behavior when bad input is given. One natable change is in ImpliedType, which was panicking on an invalid nesting mode. The comment expressly states that it will return a result even when the schema is inconsistent, so I removed the panic and instead return an empty object. --- internal/configs/configschema/decoder_spec.go | 10 ++- .../configs/configschema/decoder_spec_test.go | 42 ++++++++++ internal/configs/configschema/implied_type.go | 2 +- .../configs/configschema/implied_type_test.go | 81 +++++++++++-------- internal/plans/objchange/objchange_test.go | 2 +- 5 files changed, 100 insertions(+), 37 deletions(-) diff --git a/internal/configs/configschema/decoder_spec.go b/internal/configs/configschema/decoder_spec.go index 333274503..19bea4917 100644 --- a/internal/configs/configschema/decoder_spec.go +++ b/internal/configs/configschema/decoder_spec.go @@ -211,9 +211,15 @@ func (a *Attribute) decoderSpec(name string) hcldec.Spec { // belong to their own cty.Object definitions. It is used in other functions // which themselves handle that recursion. func listOptionalAttrsFromObject(o *Object) []string { - var ret []string + ret := make([]string, 0) + + // This is unlikely to happen outside of tests. + if o == nil { + return ret + } + for name, attr := range o.Attributes { - if attr.Optional == true { + if attr.Optional || attr.Computed { ret = append(ret, name) } } diff --git a/internal/configs/configschema/decoder_spec_test.go b/internal/configs/configschema/decoder_spec_test.go index a6571eaa6..12fdee761 100644 --- a/internal/configs/configschema/decoder_spec_test.go +++ b/internal/configs/configschema/decoder_spec_test.go @@ -1,10 +1,12 @@ package configschema import ( + "sort" "testing" "github.com/apparentlymart/go-dump/dump" "github.com/davecgh/go-spew/spew" + "github.com/google/go-cmp/cmp" "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hcldec" @@ -885,3 +887,43 @@ func TestAttributeDecoderSpec_panic(t *testing.T) { attrS.decoderSpec("attr") t.Errorf("expected panic") } + +func TestListOptionalAttrsFromObject(t *testing.T) { + tests := []struct { + input *Object + want []string + }{ + { + nil, + []string{}, + }, + { + &Object{}, + []string{}, + }, + { + &Object{ + Nesting: NestingSingle, + Attributes: map[string]*Attribute{ + "optional": {Type: cty.String, Optional: true}, + "required": {Type: cty.Number, Required: true}, + "computed": {Type: cty.List(cty.Bool), Computed: true}, + "optional_computed": {Type: cty.Map(cty.Bool), Optional: true, Computed: true}, + }, + }, + []string{"optional", "computed", "optional_computed"}, + }, + } + + for _, test := range tests { + got := listOptionalAttrsFromObject(test.input) + + // order is irrelevant + sort.Strings(got) + sort.Strings(test.want) + + if diff := cmp.Diff(got, test.want); diff != "" { + t.Fatalf("wrong result: %s\n", diff) + } + } +} diff --git a/internal/configs/configschema/implied_type.go b/internal/configs/configschema/implied_type.go index 4d4a042c3..58b995110 100644 --- a/internal/configs/configschema/implied_type.go +++ b/internal/configs/configschema/implied_type.go @@ -79,7 +79,7 @@ func (o *Object) ImpliedType() cty.Type { case NestingSet: return cty.Set(ret) default: // Should never happen - panic("invalid Nesting") + return cty.EmptyObject } } diff --git a/internal/configs/configschema/implied_type_test.go b/internal/configs/configschema/implied_type_test.go index 7cd0f7309..d36239615 100644 --- a/internal/configs/configschema/implied_type_test.go +++ b/internal/configs/configschema/implied_type_test.go @@ -37,6 +37,7 @@ func TestBlockImpliedType(t *testing.T) { "optional_computed": { Type: cty.Map(cty.Bool), Optional: true, + Computed: true, }, }, }, @@ -132,26 +133,18 @@ func TestObjectImpliedType(t *testing.T) { nil, cty.EmptyObject, }, + "empty": { + &Object{}, + cty.EmptyObject, + }, "attributes": { &Object{ Nesting: NestingSingle, Attributes: map[string]*Attribute{ - "optional": { - Type: cty.String, - Optional: true, - }, - "required": { - Type: cty.Number, - Required: true, - }, - "computed": { - Type: cty.List(cty.Bool), - Computed: true, - }, - "optional_computed": { - Type: cty.Map(cty.Bool), - Optional: true, - }, + "optional": {Type: cty.String, Optional: true}, + "required": {Type: cty.Number, Required: true}, + "computed": {Type: cty.List(cty.Bool), Computed: true}, + "optional_computed": {Type: cty.Map(cty.Bool), Optional: true, Computed: true}, }, }, cty.ObjectWithOptionalAttrs( @@ -161,7 +154,7 @@ func TestObjectImpliedType(t *testing.T) { "computed": cty.List(cty.Bool), "optional_computed": cty.Map(cty.Bool), }, - []string{"optional", "optional_computed"}, + []string{"optional", "computed", "optional_computed"}, ), }, "nested attributes": { @@ -172,21 +165,42 @@ func TestObjectImpliedType(t *testing.T) { NestedType: &Object{ Nesting: NestingSingle, Attributes: map[string]*Attribute{ - "optional": { - Type: cty.String, - Optional: true, - }, - "required": { - Type: cty.Number, - Required: true, - }, - "computed": { - Type: cty.List(cty.Bool), - Computed: true, - }, - "optional_computed": { - Type: cty.Map(cty.Bool), - Optional: true, + "optional": {Type: cty.String, Optional: true}, + "required": {Type: cty.Number, Required: true}, + "computed": {Type: cty.List(cty.Bool), Computed: true}, + "optional_computed": {Type: cty.Map(cty.Bool), Optional: true, Computed: true}, + }, + }, + Optional: true, + }, + }, + }, + cty.ObjectWithOptionalAttrs(map[string]cty.Type{ + "nested_type": cty.ObjectWithOptionalAttrs(map[string]cty.Type{ + "optional": cty.String, + "required": cty.Number, + "computed": cty.List(cty.Bool), + "optional_computed": cty.Map(cty.Bool), + }, []string{"optional", "computed", "optional_computed"}), + }, []string{"nested_type"}), + }, + "nested object-type attributes": { + &Object{ + Nesting: NestingSingle, + Attributes: map[string]*Attribute{ + "nested_type": { + NestedType: &Object{ + Nesting: NestingSingle, + Attributes: map[string]*Attribute{ + "optional": {Type: cty.String, Optional: true}, + "required": {Type: cty.Number, Required: true}, + "computed": {Type: cty.List(cty.Bool), Computed: true}, + "optional_computed": {Type: cty.Map(cty.Bool), Optional: true, Computed: true}, + "object": { + Type: cty.ObjectWithOptionalAttrs(map[string]cty.Type{ + "optional": cty.String, + "required": cty.Number, + }, []string{"optional"}), }, }, }, @@ -200,7 +214,8 @@ func TestObjectImpliedType(t *testing.T) { "required": cty.Number, "computed": cty.List(cty.Bool), "optional_computed": cty.Map(cty.Bool), - }, []string{"optional", "optional_computed"}), + "object": cty.ObjectWithOptionalAttrs(map[string]cty.Type{"optional": cty.String, "required": cty.Number}, []string{"optional"}), + }, []string{"optional", "computed", "optional_computed"}), }, []string{"nested_type"}), }, "NestingList": { diff --git a/internal/plans/objchange/objchange_test.go b/internal/plans/objchange/objchange_test.go index 3e9cc2055..8221f99bd 100644 --- a/internal/plans/objchange/objchange_test.go +++ b/internal/plans/objchange/objchange_test.go @@ -1457,7 +1457,7 @@ func TestProposedNew(t *testing.T) { "computed": cty.String, "optional_computed": cty.String, "required": cty.String, - }, []string{"optional", "optional_computed"}), + }, []string{"computed", "optional", "optional_computed"}), }))), }), }, From a456d030db92a827df6e2bb78db3089acecc99c2 Mon Sep 17 00:00:00 2001 From: Alisdair McDiarmid Date: Thu, 15 Jul 2021 13:30:11 -0400 Subject: [PATCH 072/107] Fix flapping JSON output test properly This commit makes the output order of the resource drift messages stable, by building a slice of changes and sorting it by address. --- internal/command/views/operation.go | 12 +++++++- internal/command/views/operation_test.go | 38 ++++++++++++------------ 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/internal/command/views/operation.go b/internal/command/views/operation.go index d564ea9fc..c617dd187 100644 --- a/internal/command/views/operation.go +++ b/internal/command/views/operation.go @@ -3,6 +3,7 @@ package views import ( "bytes" "fmt" + "sort" "strings" "github.com/hashicorp/terraform/internal/addrs" @@ -202,6 +203,7 @@ func (v *OperationJSON) resourceDrift(oldState, newState *states.State, schemas // resource instances. return nil } + var changes []*json.ResourceInstanceChange for _, ms := range oldState.Modules { for _, rs := range ms.Resources { if rs.Addr.Resource.Mode != addrs.ManagedResourceMode { @@ -266,10 +268,18 @@ func (v *OperationJSON) resourceDrift(oldState, newState *states.State, schemas Action: action, }, } - v.view.ResourceDrift(json.NewResourceInstanceChange(change)) + changes = append(changes, json.NewResourceInstanceChange(change)) } } } + + // Sort the change structs lexically by address to give stable output + sort.Slice(changes, func(i, j int) bool { return changes[i].Resource.Addr < changes[j].Resource.Addr }) + + for _, change := range changes { + v.view.ResourceDrift(change) + } + return nil } diff --git a/internal/command/views/operation_test.go b/internal/command/views/operation_test.go index 7d2964443..e642dbfab 100644 --- a/internal/command/views/operation_test.go +++ b/internal/command/views/operation_test.go @@ -707,25 +707,6 @@ func TestOperationJSON_planDrift(t *testing.T) { v.Plan(plan, testSchemas()) want := []map[string]interface{}{ - // Drift detected: update - { - "@level": "info", - "@message": "test_resource.boop: Drift detected (update)", - "@module": "terraform.ui", - "type": "resource_drift", - "change": map[string]interface{}{ - "action": "update", - "resource": map[string]interface{}{ - "addr": "test_resource.boop", - "implied_provider": "test", - "module": "", - "resource": "test_resource.boop", - "resource_key": nil, - "resource_name": "boop", - "resource_type": "test_resource", - }, - }, - }, // Drift detected: delete { "@level": "info", @@ -745,6 +726,25 @@ func TestOperationJSON_planDrift(t *testing.T) { }, }, }, + // Drift detected: update + { + "@level": "info", + "@message": "test_resource.boop: Drift detected (update)", + "@module": "terraform.ui", + "type": "resource_drift", + "change": map[string]interface{}{ + "action": "update", + "resource": map[string]interface{}{ + "addr": "test_resource.boop", + "implied_provider": "test", + "module": "", + "resource": "test_resource.boop", + "resource_key": nil, + "resource_name": "boop", + "resource_type": "test_resource", + }, + }, + }, // No changes { "@level": "info", From 55ebc7eef41dd7700980eb99d831d6a4e51519cf Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 16 Jul 2021 16:43:12 -0400 Subject: [PATCH 073/107] Add detail to provisioners overview page metadata --- website/docs/language/resources/provisioners/index.html.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/language/resources/provisioners/index.html.md b/website/docs/language/resources/provisioners/index.html.md index b03702066..b094a9c60 100644 --- a/website/docs/language/resources/provisioners/index.html.md +++ b/website/docs/language/resources/provisioners/index.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "Provisioners Overview - Configuration Language" description: |- - An introduction to Terraform provisioners that prepare infrastructure objects for service. + Provisioners model specific actions on a local or remote machine to prepare servers or other infrastructure for service. --- # Provisioners From 6f056af08e5395d89965ac036bc93a51c60df8dd Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 16 Jul 2021 16:46:16 -0400 Subject: [PATCH 074/107] Update null resource page metadata --- .../docs/language/resources/provisioners/null_resource.html.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/language/resources/provisioners/null_resource.html.md b/website/docs/language/resources/provisioners/null_resource.html.md index 49f69bc41..85d7c6173 100644 --- a/website/docs/language/resources/provisioners/null_resource.html.md +++ b/website/docs/language/resources/provisioners/null_resource.html.md @@ -3,7 +3,7 @@ layout: "language" page_title: "Provisioners Without a Resource" sidebar_current: "docs-provisioners-null-resource" description: |- - Using 'null_resource' to configure Terraform provisioners that are not directly associated with a single existing resource. + 'null_resource' allows you to configure Terraform provisioners that are not directly associated with a single existing resource. --- # Provisioners Without a Resource From 77c208d02f0994dc70a6c914b403f6d303788b40 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 16 Jul 2021 16:50:55 -0400 Subject: [PATCH 075/107] Add detail to declare provisioners page metadata --- website/docs/language/resources/provisioners/syntax.html.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/language/resources/provisioners/syntax.html.md b/website/docs/language/resources/provisioners/syntax.html.md index 388f9e01f..54879b278 100644 --- a/website/docs/language/resources/provisioners/syntax.html.md +++ b/website/docs/language/resources/provisioners/syntax.html.md @@ -3,7 +3,7 @@ layout: "language" page_title: "Provisioners" sidebar_current: "docs-provisioners" description: |- - Using provisioners in Terraform to execute scripts on a local or remote machine as part of resource creation or destruction. + Provisioners run scripts on a local or remote machine during resource creation or destruction. Learn how to declare provisioners in a configuration. --- # Provisioners From 80fee567a291322c185ddf115fab3e29a20fc88b Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 16 Jul 2021 16:55:13 -0400 Subject: [PATCH 076/107] Add detail to resource block page metadata --- website/docs/language/resources/syntax.html.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/language/resources/syntax.html.md b/website/docs/language/resources/syntax.html.md index 2c3e14c51..07b915b22 100644 --- a/website/docs/language/resources/syntax.html.md +++ b/website/docs/language/resources/syntax.html.md @@ -3,7 +3,7 @@ layout: "language" page_title: "Resources - Configuration Language" sidebar_current: "docs-config-resources" description: |- - Details about Terraform resources, which correspond to infrastructure objects like virtual networks or compute instances. + Resources correspond to infrastructure objects like virtual networks or compute instances. Learn about resource types, syntax, behavior, and arguments. --- # Resource Blocks From f46974dbb275605ea8c79b04605b0e702eb5b9e4 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 16 Jul 2021 17:01:36 -0400 Subject: [PATCH 077/107] Add detail to settings intro page metadata --- website/docs/language/settings/index.html.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/language/settings/index.html.md b/website/docs/language/settings/index.html.md index 50c5e9cf7..3bf25368e 100644 --- a/website/docs/language/settings/index.html.md +++ b/website/docs/language/settings/index.html.md @@ -3,7 +3,7 @@ layout: "language" page_title: "Terraform Settings - Configuration Language" sidebar_current: "docs-config-terraform" description: |- - Using the `terraform` block type to configure Terraform behavior. + The `terraform` block allows you to configure Terraform behavior, including the Terraform version, backend, and required providers. --- # Terraform Settings From b6b434021462a5a6cc2e499683f39f620f0fd0b2 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 16 Jul 2021 17:08:24 -0400 Subject: [PATCH 078/107] Add detail to backend overview page metadata --- website/docs/language/settings/backends/index.html.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/language/settings/backends/index.html.md b/website/docs/language/settings/backends/index.html.md index ce78a4d2d..5f98954ba 100644 --- a/website/docs/language/settings/backends/index.html.md +++ b/website/docs/language/settings/backends/index.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "Backend Overview - Configuration Language" description: |- - An introduction to Terraform configuration backends. + A backend defines where and how Terraform performs operations, such as where it stores state files. Learn about recommended backends and how backends work. --- # Backends From df6135e4c79cbd0d69d0777a2a62cdb00eebe3ad Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 16 Jul 2021 17:17:39 -0400 Subject: [PATCH 079/107] Update languge syntax overview page metadata --- website/docs/language/syntax/index.html.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/language/syntax/index.html.md b/website/docs/language/syntax/index.html.md index d1bcbf350..e11ecae8d 100644 --- a/website/docs/language/syntax/index.html.md +++ b/website/docs/language/syntax/index.html.md @@ -2,7 +2,7 @@ layout: "language" page_title: "Syntax Overview - Configuration Language" description: |- - An introduction to Terraform language syntax for both the native and JSON variants as well as formatting conventions. + Terraform language syntax for both the native and JSON variants. Also formatting conventions that you can enforce with `terraform fmt`. --- # Syntax From f67e7f6a9fa4a56d413f6e23f273c48cde8cffb4 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 16 Jul 2021 17:21:16 -0400 Subject: [PATCH 080/107] Update json configuration syntax page metadata --- website/docs/language/syntax/json.html.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/language/syntax/json.html.md b/website/docs/language/syntax/json.html.md index 4d80508d5..e6ca652fe 100644 --- a/website/docs/language/syntax/json.html.md +++ b/website/docs/language/syntax/json.html.md @@ -3,7 +3,7 @@ layout: "language" page_title: "JSON Configuration Syntax - Configuration Language" sidebar_current: "docs-config-syntax-json" description: |- - Details about the JSON-compatible Terraform language syntax, including file structure, expression mapping, and blocks. + Details about the JSON-compatible language syntax, including file structure, expression mapping, block mapping, and block-type-specific exceptions. --- # JSON Configuration Syntax From 725c1c2a86271bab92d6913bf587219e99faf70d Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 16 Jul 2021 17:28:13 -0400 Subject: [PATCH 081/107] Update style conventions page metadata --- website/docs/language/syntax/style.html.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/docs/language/syntax/style.html.md b/website/docs/language/syntax/style.html.md index bc9af1f08..f09ef1a31 100644 --- a/website/docs/language/syntax/style.html.md +++ b/website/docs/language/syntax/style.html.md @@ -15,6 +15,8 @@ for consistency between files and modules written by different teams. Automatic source code formatting tools may apply these conventions automatically. +-> **Note**: You can enforce these conventions automatically by running [`terraform fmt`](/docs/cli/commands/fmt.html). + * Indent two spaces for each nesting level. * When multiple arguments with single-line values appear on consecutive lines From 1f1563b8890b9405818c13161c6fb8f3b3fba7d2 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 16 Jul 2021 17:28:40 -0400 Subject: [PATCH 082/107] Fix formatting error on language home page --- website/docs/language/index.html.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/language/index.html.md b/website/docs/language/index.html.md index ca4e2a22c..649429890 100644 --- a/website/docs/language/index.html.md +++ b/website/docs/language/index.html.md @@ -1,8 +1,8 @@ --- layout: "language" page_title: "Overview - Configuration Language" -description: |- -You can use the Terraform language to write configuration files that tell Terraform how to manage a collection of infrastructure. +description: "You can use the Terraform language to write configuration files that tell Terraform how to manage a collection of infrastructure." + --- # Terraform Language Documentation From 603e156bb9a4725579c4c888b188c3d58ba691d3 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 16 Jul 2021 17:32:24 -0400 Subject: [PATCH 083/107] Update input variables page metadata --- website/docs/language/values/variables.html.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/language/values/variables.html.md b/website/docs/language/values/variables.html.md index e48a416af..3362537c6 100644 --- a/website/docs/language/values/variables.html.md +++ b/website/docs/language/values/variables.html.md @@ -3,7 +3,7 @@ layout: "language" page_title: "Input Variables - Configuration Language" sidebar_current: "docs-config-variables" description: |- - Using input variables to customize Terraform configurations, including how to declare, define, and reference variables in root and child modules. + Input variables allow you to customize modules without altering their source code. Learn how to declare, define, and reference variables in configurations. --- # Input Variables From fd3b5a48c7a03807e6c170fe93ecf9fe85956809 Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Fri, 16 Jul 2021 17:35:08 -0400 Subject: [PATCH 084/107] Update provider documentation page metadata --- website/docs/providers/index.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/providers/index.html.markdown b/website/docs/providers/index.html.markdown index 9872df783..07d99f957 100644 --- a/website/docs/providers/index.html.markdown +++ b/website/docs/providers/index.html.markdown @@ -3,7 +3,7 @@ layout: "language" page_title: "Provider Documentation" sidebar_current: "docs-providers" description: |- - Pointers to documentation for Terraform provider plugins, including the Terraform Registry. + Pointers to provider documentation on the Terraform Registry and to information about how to create documentation for your provider. --- # Provider Documentation From a780f625e901430897132438aedeae98dafe09cc Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Mon, 19 Jul 2021 12:11:10 -0400 Subject: [PATCH 085/107] Fix metadata description format on all pages --- website/docs/language/data-sources/index.html.md | 3 +-- website/docs/language/dependency-lock.html.md | 3 +-- website/docs/language/expressions/conditionals.html.md | 3 +-- website/docs/language/expressions/dynamic-blocks.html.md | 3 +-- website/docs/language/expressions/for.html.md | 3 +-- website/docs/language/expressions/function-calls.html.md | 3 +-- website/docs/language/expressions/index.html.md | 3 +-- website/docs/language/expressions/operators.html.md | 3 +-- website/docs/language/expressions/references.html.md | 3 +-- website/docs/language/expressions/splat.html.md | 3 +-- website/docs/language/expressions/strings.html.md | 4 ++-- website/docs/language/expressions/type-constraints.html.md | 3 +-- website/docs/language/expressions/types.html.md | 3 +-- .../docs/language/expressions/version-constraints.html.md | 3 +-- website/docs/language/files/index.html.md | 3 +-- website/docs/language/files/override.html.md | 3 +-- website/docs/language/functions/index.html.md | 3 +-- website/docs/language/meta-arguments/count.html.md | 3 +-- website/docs/language/meta-arguments/depends_on.html.md | 3 +-- website/docs/language/meta-arguments/for_each.html.md | 3 +-- website/docs/language/meta-arguments/lifecycle.html.md | 3 +-- .../docs/language/meta-arguments/module-providers.html.md | 3 +-- .../docs/language/meta-arguments/resource-provider.html.md | 3 +-- website/docs/language/modules/develop/index.html.md | 3 +-- website/docs/language/modules/index.html.md | 3 +-- website/docs/language/modules/sources.html.md | 3 +-- website/docs/language/modules/syntax.html.md | 3 +-- website/docs/language/providers/configuration.html.md | 3 +-- website/docs/language/providers/index.html.md | 3 +-- website/docs/language/providers/requirements.html.md | 3 +-- website/docs/language/resources/behavior.html.md | 3 +-- website/docs/language/resources/index.html.md | 3 +-- .../docs/language/resources/provisioners/connection.html.md | 3 +-- website/docs/language/resources/provisioners/index.html.md | 3 +-- .../language/resources/provisioners/null_resource.html.md | 3 +-- website/docs/language/resources/provisioners/syntax.html.md | 3 +-- website/docs/language/resources/syntax.html.md | 3 +-- website/docs/language/settings/backends/index.html.md | 3 +-- website/docs/language/settings/index.html.md | 3 +-- website/docs/language/state/index.html.md | 3 +-- website/docs/language/syntax/configuration.html.md | 3 +-- website/docs/language/syntax/index.html.md | 3 +-- website/docs/language/syntax/json.html.md | 3 +-- website/docs/language/syntax/style.html.md | 3 +-- website/docs/language/values/index.html.md | 3 +-- website/docs/language/values/locals.html.md | 3 +-- website/docs/language/values/variables.html.md | 3 +-- website/docs/providers/index.html.markdown | 6 ++---- 48 files changed, 50 insertions(+), 98 deletions(-) diff --git a/website/docs/language/data-sources/index.html.md b/website/docs/language/data-sources/index.html.md index 3121c1ed8..1666efbd2 100644 --- a/website/docs/language/data-sources/index.html.md +++ b/website/docs/language/data-sources/index.html.md @@ -2,8 +2,7 @@ layout: "language" page_title: "Data Sources - Configuration Language" sidebar_current: "docs-config-data-sources" -description: |- -Data sources allow Terraform to use external data, function output, and data from other configurations. Terraform accesses them via data resources. +description: "Data sources allow Terraform to use external data, function output, and data from other configurations. Learn data resource arguments, behavior, and lifecycle." --- # Data Sources diff --git a/website/docs/language/dependency-lock.html.md b/website/docs/language/dependency-lock.html.md index d2df7395a..5e3b7042d 100644 --- a/website/docs/language/dependency-lock.html.md +++ b/website/docs/language/dependency-lock.html.md @@ -1,8 +1,7 @@ --- layout: "language" page_title: "Dependency Lock File (.terraform.lock.hcl) - Configuration Language" -description: |- - Terraform uses the dependency lock file `.teraform.lock.hcl` to track and select provider versions. Learn about dependency installation and lock file changes. +description: "Terraform uses the dependency lock file `.teraform.lock.hcl` to track and select provider versions. Learn about dependency installation and lock file changes." --- # Dependency Lock File diff --git a/website/docs/language/expressions/conditionals.html.md b/website/docs/language/expressions/conditionals.html.md index f12d44933..50a50a7b4 100644 --- a/website/docs/language/expressions/conditionals.html.md +++ b/website/docs/language/expressions/conditionals.html.md @@ -1,8 +1,7 @@ --- layout: "language" page_title: "Conditional Expressions - Configuration Language" -description: |- - Conditional expressions in configurations select one of two values. You can use them to define defaults to replace invalid values. +description: "Conditional expressions select one of two values. You can use them to define defaults to replace invalid values." --- # Conditional Expressions diff --git a/website/docs/language/expressions/dynamic-blocks.html.md b/website/docs/language/expressions/dynamic-blocks.html.md index b86f89364..ef16a1c2f 100644 --- a/website/docs/language/expressions/dynamic-blocks.html.md +++ b/website/docs/language/expressions/dynamic-blocks.html.md @@ -1,8 +1,7 @@ --- layout: "language" page_title: "Dynamic Blocks - Configuration Language" -description: |- - `dynamic` blocks dynamically construct multi-level, nested block structures. Learn to configure `dynamic` blocks and understand their behavior. +description: "`dynamic` blocks automatically construct multi-level, nested block structures. Learn to configure `dynamic` blocks and understand their behavior." --- diff --git a/website/docs/language/expressions/for.html.md b/website/docs/language/expressions/for.html.md index 11eb71cd4..d2af57cb8 100644 --- a/website/docs/language/expressions/for.html.md +++ b/website/docs/language/expressions/for.html.md @@ -1,8 +1,7 @@ --- layout: "language" page_title: "For Expressions - Configuration Language" -description: |- - `for` expressions transform complex input values into complex output values. Learn how Terraform orders elements and how to filter inputs and group results. +description: "`for` expressions transform complex input values into complex output values. Learn how to filter inputs and how to group results." --- # `for` Expressions diff --git a/website/docs/language/expressions/function-calls.html.md b/website/docs/language/expressions/function-calls.html.md index 961043439..b55d6a16d 100644 --- a/website/docs/language/expressions/function-calls.html.md +++ b/website/docs/language/expressions/function-calls.html.md @@ -1,8 +1,7 @@ --- layout: "language" page_title: "Function Calls - Configuration Language" -description: |- - Function calls transform and combine values. Learn about Terraform's built-in functions. +description: "Functions transform and combine values. Learn about Terraform's built-in functions." --- # Function Calls diff --git a/website/docs/language/expressions/index.html.md b/website/docs/language/expressions/index.html.md index 9cb666677..80fa8768b 100644 --- a/website/docs/language/expressions/index.html.md +++ b/website/docs/language/expressions/index.html.md @@ -1,8 +1,7 @@ --- layout: "language" page_title: "Expressions - Configuration Language" -description: |- - An overview of expressions you can use to reference or compute values in Terraform configurations, including types, operators, and functions. +description: "An overview of expressions to reference or compute values in Terraform configurations, including types, operators, and functions." --- # Expressions diff --git a/website/docs/language/expressions/operators.html.md b/website/docs/language/expressions/operators.html.md index eb79dcbb6..333e59d24 100644 --- a/website/docs/language/expressions/operators.html.md +++ b/website/docs/language/expressions/operators.html.md @@ -1,8 +1,7 @@ --- layout: "language" page_title: "Operators - Configuration Language" -description: |- - Operators transform or combine expressions. Learn about arithmetic, logical, equality, and comparison operators. +description: "Operators transform or combine expressions. Learn about arithmetic, logical, equality, and comparison operators." --- # Arithmetic and Logical Operators diff --git a/website/docs/language/expressions/references.html.md b/website/docs/language/expressions/references.html.md index 8a877ce61..b7db71398 100644 --- a/website/docs/language/expressions/references.html.md +++ b/website/docs/language/expressions/references.html.md @@ -1,8 +1,7 @@ --- layout: "language" page_title: "References to Values - Configuration Language" -description: |- - Reference named values in configurations, including resources, input variables, local and block-local values, module outputs, data sources, and workspace data. +description: "Reference values in configurations, including resources, input variables, local and block-local values, module outputs, data sources, and workspace data." --- # References to Named Values diff --git a/website/docs/language/expressions/splat.html.md b/website/docs/language/expressions/splat.html.md index 0ea75f58b..668b4540a 100644 --- a/website/docs/language/expressions/splat.html.md +++ b/website/docs/language/expressions/splat.html.md @@ -1,8 +1,7 @@ --- layout: "language" page_title: "Splat Expressions - Configuration Language" -description: |- - Splat expressions concisely express common operations. They also transform single, non-null values into a single-element tuple. +description: "Splat expressions concisely represent common operations. In Terraform, they also transform single, non-null values into a single-element tuple." --- # Splat Expressions diff --git a/website/docs/language/expressions/strings.html.md b/website/docs/language/expressions/strings.html.md index 5c4f2c62b..714134ecb 100644 --- a/website/docs/language/expressions/strings.html.md +++ b/website/docs/language/expressions/strings.html.md @@ -1,8 +1,8 @@ --- layout: "language" page_title: "Strings and Templates - Configuration Language" -description: |- - String literals and template sequences interpolate values and manipulate text. Learn about both quoted and "heredoc" string syntax. +description: "String literals and template sequences interpolate values and manipulate text. Learn about both quoted and heredoc string syntax." + --- # Strings and Templates diff --git a/website/docs/language/expressions/type-constraints.html.md b/website/docs/language/expressions/type-constraints.html.md index ec59f1b9b..9d81ee54b 100644 --- a/website/docs/language/expressions/type-constraints.html.md +++ b/website/docs/language/expressions/type-constraints.html.md @@ -2,8 +2,7 @@ layout: "language" page_title: "Type Constraints - Configuration Language" sidebar_current: "docs-config-types" -description: |- - Learn how to use type constraints to validate user inputs to modules and resources. +description: "Learn how to use type constraints to validate user inputs to modules and resources." --- # Type Constraints diff --git a/website/docs/language/expressions/types.html.md b/website/docs/language/expressions/types.html.md index 1ad317b15..a787a2a86 100644 --- a/website/docs/language/expressions/types.html.md +++ b/website/docs/language/expressions/types.html.md @@ -1,8 +1,7 @@ --- layout: "language" page_title: "Types and Values - Configuration Language" -description: |- - Learn about value types and their syntax, including string, number, bool, list, and map. Also learn about complex types and type conversion. +description: "Learn about value types and syntax, including string, number, bool, list, and map. Also learn about complex types and type conversion." --- # Types and Values diff --git a/website/docs/language/expressions/version-constraints.html.md b/website/docs/language/expressions/version-constraints.html.md index 861773c66..313d5c225 100644 --- a/website/docs/language/expressions/version-constraints.html.md +++ b/website/docs/language/expressions/version-constraints.html.md @@ -1,8 +1,7 @@ --- layout: "language" page_title: "Version Constraints - Configuration Language" -description: |- - Version constraint strings specify a range of acceptable versions for modules, providers, and Terraform itself. Learn version constraint syntax and behavior. +description: "Version constraint strings specify a range of acceptable versions for modules, providers, and Terraform itself. Learn version constraint syntax and behavior." --- # Version Constraints diff --git a/website/docs/language/files/index.html.md b/website/docs/language/files/index.html.md index 72ceb13c8..c8f4436db 100644 --- a/website/docs/language/files/index.html.md +++ b/website/docs/language/files/index.html.md @@ -1,8 +1,7 @@ --- layout: "language" page_title: "Files and Directories - Configuration Language" -description: |- - Learn how to name, organize, and store Terraform configuration files as well as how Terraform evaluates modules. +description: "Learn how to name, organize, and store Terraform configuration files. Also learn how Terraform evaluates modules." --- # Files and Directories diff --git a/website/docs/language/files/override.html.md b/website/docs/language/files/override.html.md index 1d549cbe2..b3dcc220e 100644 --- a/website/docs/language/files/override.html.md +++ b/website/docs/language/files/override.html.md @@ -2,8 +2,7 @@ layout: "language" page_title: "Override Files - Configuration Language" sidebar_current: "docs-config-override" -description: |- - Override files merge additional settings into existing configuration objects. Learn how to use override files and about merging behavior. +description: "Override files merge additional settings into existing configuration objects. Learn how to use override files and about merging behavior." --- # Override Files diff --git a/website/docs/language/functions/index.html.md b/website/docs/language/functions/index.html.md index 2a7af09ff..b51802cea 100644 --- a/website/docs/language/functions/index.html.md +++ b/website/docs/language/functions/index.html.md @@ -2,8 +2,7 @@ layout: "language" page_title: "Functions - Configuration Language" sidebar_current: "docs-config-functions" -description: |- - An introduction to the built-in functions that you can use to transform and combine values in expressions. +description: "An introduction to the built-in functions that you can use to transform and combine values in expressions." --- # Built-in Functions diff --git a/website/docs/language/meta-arguments/count.html.md b/website/docs/language/meta-arguments/count.html.md index 8a2b1a16e..83dcd38f7 100644 --- a/website/docs/language/meta-arguments/count.html.md +++ b/website/docs/language/meta-arguments/count.html.md @@ -1,8 +1,7 @@ --- layout: "language" page_title: "The count Meta-Argument - Configuration Language" -description: |- - The `count` meta-argument helps you efficiently manage nearly identical infrastructure resources without writing a separate block for each one. +description: "`count` helps you efficiently manage nearly identical infrastructure resources without writing a separate block for each one." --- # The `count` Meta-Argument diff --git a/website/docs/language/meta-arguments/depends_on.html.md b/website/docs/language/meta-arguments/depends_on.html.md index c5de7e120..101862671 100644 --- a/website/docs/language/meta-arguments/depends_on.html.md +++ b/website/docs/language/meta-arguments/depends_on.html.md @@ -1,8 +1,7 @@ --- layout: "language" page_title: "The depends_on Meta-Argument - Configuration Language" -description: |- - The `depends_on` meta-argument allows you to handle hidden resource or module dependencies. +description: "`depends_on` allows you to handle hidden resource or module dependencies." --- # The `depends_on` Meta-Argument diff --git a/website/docs/language/meta-arguments/for_each.html.md b/website/docs/language/meta-arguments/for_each.html.md index 46491790a..677767a9a 100644 --- a/website/docs/language/meta-arguments/for_each.html.md +++ b/website/docs/language/meta-arguments/for_each.html.md @@ -1,8 +1,7 @@ --- layout: "language" page_title: "The for_each Meta-Argument - Configuration Language" -description: |- - The `for_each` meta-argument allows you to efficiently manage similar infrastructure resources without writing a separate block for each one. +description: "`for_each` allows you to efficiently manage similar infrastructure resources without writing a separate block for each one." --- # The `for_each` Meta-Argument diff --git a/website/docs/language/meta-arguments/lifecycle.html.md b/website/docs/language/meta-arguments/lifecycle.html.md index 72f78e255..fd84e8c3d 100644 --- a/website/docs/language/meta-arguments/lifecycle.html.md +++ b/website/docs/language/meta-arguments/lifecycle.html.md @@ -1,8 +1,7 @@ --- layout: "language" page_title: "The lifecycle Meta-Argument - Configuration Language" -description: |- - The meta-arguments in a `lifecycle` block allow you to customize resource behavior. For example, preventing Terraform from destroying associated infrastructure. +description: "The meta-arguments in a `lifecycle` block allow you to customize resource behavior. For example, preventing Terraform from destroying associated infrastructure." --- # The `lifecycle` Meta-Argument diff --git a/website/docs/language/meta-arguments/module-providers.html.md b/website/docs/language/meta-arguments/module-providers.html.md index 4c9ff6b16..3869dc203 100644 --- a/website/docs/language/meta-arguments/module-providers.html.md +++ b/website/docs/language/meta-arguments/module-providers.html.md @@ -1,8 +1,7 @@ --- layout: "language" page_title: "The Module providers Meta-Argument - Configuration Language" -description: |- - The `providers` meta-argument specifies which provider configurations from a parent module are available inside a child module. +description: "`providers` specifies which provider configurations from a parent module are available in a child module." --- # The Module `providers` Meta-Argument diff --git a/website/docs/language/meta-arguments/resource-provider.html.md b/website/docs/language/meta-arguments/resource-provider.html.md index e66f66453..9590d3b4d 100644 --- a/website/docs/language/meta-arguments/resource-provider.html.md +++ b/website/docs/language/meta-arguments/resource-provider.html.md @@ -1,8 +1,7 @@ --- layout: "language" page_title: "The Resource provider Meta-Argument - Configuration Language" -description: |- - The `provider` meta-argument specifies which provider configuration Terraform should use for a resource. +description: "`provider` specifies the provider configuration Terraform should use for a resource, overriding Terraform's default behavior." --- # The Resource `provider` Meta-Argument diff --git a/website/docs/language/modules/develop/index.html.md b/website/docs/language/modules/develop/index.html.md index d651ee91e..fccafd069 100644 --- a/website/docs/language/modules/develop/index.html.md +++ b/website/docs/language/modules/develop/index.html.md @@ -2,8 +2,7 @@ layout: "language" page_title: "Creating Modules" sidebar_current: "docs-modules" -description: |- - Modules are containers for multiple resources that are used together in a configuration. Learn when to create modules and about module structure. +description: "Modules are containers for multiple resources that are used together in a configuration. Learn when to create modules and about module structure." --- # Creating Modules diff --git a/website/docs/language/modules/index.html.md b/website/docs/language/modules/index.html.md index 669ad5f44..a1c122768 100644 --- a/website/docs/language/modules/index.html.md +++ b/website/docs/language/modules/index.html.md @@ -1,8 +1,7 @@ --- layout: "language" page_title: "Modules Overview - Configuration Language" -description: |- - Modules are containers for multiple resources that are used together in a configuration. Find resources for using, developing, and publishing modules. +description: "Modules are containers for multiple resources that are used together in a configuration. Find resources for using, developing, and publishing modules." --- # Modules diff --git a/website/docs/language/modules/sources.html.md b/website/docs/language/modules/sources.html.md index 21ee57dfd..931564b55 100644 --- a/website/docs/language/modules/sources.html.md +++ b/website/docs/language/modules/sources.html.md @@ -2,8 +2,7 @@ layout: "language" page_title: "Module Sources" sidebar_current: "docs-modules-sources" -description: |- - The `source` argument tells Terraform where to find child modules in locations like GitHub, the Terraform Registry, Bitbucket, Git, Mercurial, S3, and GCS. +description: "`source` tells Terraform where to find child modules in locations like GitHub, the Terraform Registry, Bitbucket, Git, Mercurial, S3, and GCS." --- # Module Sources diff --git a/website/docs/language/modules/syntax.html.md b/website/docs/language/modules/syntax.html.md index 0010e3056..a0676a127 100644 --- a/website/docs/language/modules/syntax.html.md +++ b/website/docs/language/modules/syntax.html.md @@ -2,8 +2,7 @@ layout: "language" page_title: "Modules - Configuration Language" sidebar_current: "docs-config-modules" -description: |- - Modules are containers for multiple resources that are used together. Learn how to call one module from another in configurations. +description: "Modules are containers for multiple resources that are used together in configurations. Learn how to call one module from another and access module output." --- # Module Blocks diff --git a/website/docs/language/providers/configuration.html.md b/website/docs/language/providers/configuration.html.md index 27f5544a4..ca7c6f8f5 100644 --- a/website/docs/language/providers/configuration.html.md +++ b/website/docs/language/providers/configuration.html.md @@ -2,8 +2,7 @@ layout: "language" page_title: "Provider Configuration - Configuration Language" sidebar_current: "docs-config-providers" -description: |- - Learn how to configure Terraform providers, including how to use the `alias` meta-argument to specify multiple configurations for a single provider. +description: "Learn how to set up providers, including how to use the `alias` meta-argument to specify multiple configurations for a single provider." --- # Provider Configuration diff --git a/website/docs/language/providers/index.html.md b/website/docs/language/providers/index.html.md index f2a7b0a7e..5b7117a66 100644 --- a/website/docs/language/providers/index.html.md +++ b/website/docs/language/providers/index.html.md @@ -1,8 +1,7 @@ --- layout: "language" page_title: "Providers - Configuration Language" -description: |- - An overview of how to install and use providers, Terraform plugins that interact with services, cloud providers, and other APIs. +description: "An overview of how to install and use providers, Terraform plugins that interact with services, cloud providers, and other APIs." --- # Providers diff --git a/website/docs/language/providers/requirements.html.md b/website/docs/language/providers/requirements.html.md index 5a4ccd58d..6e8b995c4 100644 --- a/website/docs/language/providers/requirements.html.md +++ b/website/docs/language/providers/requirements.html.md @@ -1,8 +1,7 @@ --- layout: "language" page_title: "Provider Requirements - Configuration Language" -description: |- - Providers are plugins that allow Terraform to interact with remote systems. Learn how to declare providers in your configuration. +description: "Providers are plugins that allow Terraform to interact with services, cloud providers, and other APIs. Learn how to declare providers in a configuration." --- # Provider Requirements diff --git a/website/docs/language/resources/behavior.html.md b/website/docs/language/resources/behavior.html.md index f0fe4463c..35f3410a2 100644 --- a/website/docs/language/resources/behavior.html.md +++ b/website/docs/language/resources/behavior.html.md @@ -1,8 +1,7 @@ --- layout: "language" page_title: "Resource Behavior - Configuration Language" -description: |- - Learn how Terraform uses `resource` blocks to create infrastructure objects. Also learn about resource dependencies and accessing resource attributes. +description: "Learn how Terraform uses `resource` blocks to create infrastructure objects. Also learn about resource dependencies and how to access resource attributes." --- # Resource Behavior diff --git a/website/docs/language/resources/index.html.md b/website/docs/language/resources/index.html.md index 2e5bd229a..e0cf01c79 100644 --- a/website/docs/language/resources/index.html.md +++ b/website/docs/language/resources/index.html.md @@ -1,8 +1,7 @@ --- layout: "language" page_title: "Resources Overview - Configuration Language" -description: |- - An introduction to the `resources` element that describes infrastructure objects in Terraform configurations. +description: "`resources` describe infrastructure objects in Terraform configurations. Find documentation for resource syntax, behavior, and meta-arguments." --- # Resources diff --git a/website/docs/language/resources/provisioners/connection.html.md b/website/docs/language/resources/provisioners/connection.html.md index c68bd94e1..eca230b66 100644 --- a/website/docs/language/resources/provisioners/connection.html.md +++ b/website/docs/language/resources/provisioners/connection.html.md @@ -2,8 +2,7 @@ layout: "language" page_title: "Provisioner Connection Settings" sidebar_current: "docs-provisioners-connection" -description: |- - The `connection` block allows you to manage provisioner connection defaults for SSH and WinRM. +description: "The `connection` block allows you to manage provisioner connection defaults for SSH and WinRM." --- # Provisioner Connection Settings diff --git a/website/docs/language/resources/provisioners/index.html.md b/website/docs/language/resources/provisioners/index.html.md index b094a9c60..2a22e2dd2 100644 --- a/website/docs/language/resources/provisioners/index.html.md +++ b/website/docs/language/resources/provisioners/index.html.md @@ -1,8 +1,7 @@ --- layout: "language" page_title: "Provisioners Overview - Configuration Language" -description: |- - Provisioners model specific actions on a local or remote machine to prepare servers or other infrastructure for service. +description: "Provisioners model specific actions on a local or remote machine to prepare servers or other infrastructure for service." --- # Provisioners diff --git a/website/docs/language/resources/provisioners/null_resource.html.md b/website/docs/language/resources/provisioners/null_resource.html.md index 85d7c6173..e986e7c6d 100644 --- a/website/docs/language/resources/provisioners/null_resource.html.md +++ b/website/docs/language/resources/provisioners/null_resource.html.md @@ -2,8 +2,7 @@ layout: "language" page_title: "Provisioners Without a Resource" sidebar_current: "docs-provisioners-null-resource" -description: |- - 'null_resource' allows you to configure Terraform provisioners that are not directly associated with a single existing resource. +description: "'null_resource' allows you to configure provisioners that are not directly associated with a single existing resource." --- # Provisioners Without a Resource diff --git a/website/docs/language/resources/provisioners/syntax.html.md b/website/docs/language/resources/provisioners/syntax.html.md index 54879b278..c0f41966b 100644 --- a/website/docs/language/resources/provisioners/syntax.html.md +++ b/website/docs/language/resources/provisioners/syntax.html.md @@ -2,8 +2,7 @@ layout: "language" page_title: "Provisioners" sidebar_current: "docs-provisioners" -description: |- - Provisioners run scripts on a local or remote machine during resource creation or destruction. Learn how to declare provisioners in a configuration. +description: "Provisioners run scripts on a local or remote machine during resource creation or destruction. Learn how to declare provisioners in a configuration." --- # Provisioners diff --git a/website/docs/language/resources/syntax.html.md b/website/docs/language/resources/syntax.html.md index 07b915b22..456e93779 100644 --- a/website/docs/language/resources/syntax.html.md +++ b/website/docs/language/resources/syntax.html.md @@ -2,8 +2,7 @@ layout: "language" page_title: "Resources - Configuration Language" sidebar_current: "docs-config-resources" -description: |- - Resources correspond to infrastructure objects like virtual networks or compute instances. Learn about resource types, syntax, behavior, and arguments. +description: "Resources correspond to infrastructure objects like virtual networks or compute instances. Learn about resource types, syntax, behavior, and arguments." --- # Resource Blocks diff --git a/website/docs/language/settings/backends/index.html.md b/website/docs/language/settings/backends/index.html.md index 5f98954ba..5a8a75359 100644 --- a/website/docs/language/settings/backends/index.html.md +++ b/website/docs/language/settings/backends/index.html.md @@ -1,8 +1,7 @@ --- layout: "language" page_title: "Backend Overview - Configuration Language" -description: |- - A backend defines where and how Terraform performs operations, such as where it stores state files. Learn about recommended backends and how backends work. +description: "A backend defines where and how Terraform performs operations, such as where it stores state files. Learn about recommended backends and how backends work." --- # Backends diff --git a/website/docs/language/settings/index.html.md b/website/docs/language/settings/index.html.md index 3bf25368e..88f5e2109 100644 --- a/website/docs/language/settings/index.html.md +++ b/website/docs/language/settings/index.html.md @@ -2,8 +2,7 @@ layout: "language" page_title: "Terraform Settings - Configuration Language" sidebar_current: "docs-config-terraform" -description: |- - The `terraform` block allows you to configure Terraform behavior, including the Terraform version, backend, and required providers. +description: "The `terraform` block allows you to configure Terraform behavior, including the Terraform version, backend, and required providers." --- # Terraform Settings diff --git a/website/docs/language/state/index.html.md b/website/docs/language/state/index.html.md index 4e225913f..67072eab2 100644 --- a/website/docs/language/state/index.html.md +++ b/website/docs/language/state/index.html.md @@ -2,8 +2,7 @@ layout: "language" page_title: "State" sidebar_current: "docs-state" -description: |- - An introduction to state, information that Terraform uses to map resources to a configuration, track metadata, and improve performance. +description: "An introduction to state, information that Terraform uses to map resources to a configuration, track metadata, and improve performance." --- # State diff --git a/website/docs/language/syntax/configuration.html.md b/website/docs/language/syntax/configuration.html.md index 1fa5fc48d..5dd06b28e 100644 --- a/website/docs/language/syntax/configuration.html.md +++ b/website/docs/language/syntax/configuration.html.md @@ -2,8 +2,7 @@ layout: "language" page_title: "Syntax - Configuration Language" sidebar_current: "docs-config-syntax" -description: |- - Key constructs of the native Terraform language syntax, including identifiers, arguments, blocks, and comments. +description: "Key constructs of the native Terraform language syntax, including identifiers, arguments, blocks, and comments." --- # Configuration Syntax diff --git a/website/docs/language/syntax/index.html.md b/website/docs/language/syntax/index.html.md index e11ecae8d..dca74c78b 100644 --- a/website/docs/language/syntax/index.html.md +++ b/website/docs/language/syntax/index.html.md @@ -1,8 +1,7 @@ --- layout: "language" page_title: "Syntax Overview - Configuration Language" -description: |- - Terraform language syntax for both the native and JSON variants. Also formatting conventions that you can enforce with `terraform fmt`. +description: "Terraform language syntax for both the native and JSON variants. Also learn formatting conventions that you can enforce with `terraform fmt`." --- # Syntax diff --git a/website/docs/language/syntax/json.html.md b/website/docs/language/syntax/json.html.md index e6ca652fe..32a69578e 100644 --- a/website/docs/language/syntax/json.html.md +++ b/website/docs/language/syntax/json.html.md @@ -2,8 +2,7 @@ layout: "language" page_title: "JSON Configuration Syntax - Configuration Language" sidebar_current: "docs-config-syntax-json" -description: |- - Details about the JSON-compatible language syntax, including file structure, expression mapping, block mapping, and block-type-specific exceptions. +description: "Learn about the JSON-compatible language syntax, including file structure, expression mapping, block mapping, and block-type-specific exceptions." --- # JSON Configuration Syntax diff --git a/website/docs/language/syntax/style.html.md b/website/docs/language/syntax/style.html.md index f09ef1a31..bbbf090f7 100644 --- a/website/docs/language/syntax/style.html.md +++ b/website/docs/language/syntax/style.html.md @@ -2,8 +2,7 @@ layout: "language" page_title: "Style Conventions - Configuration Language" sidebar_current: "docs-config-style" -description: |- - Recommended formatting conventions for the Terraform language. +description: "Learn recommended formatting conventions for the Terraform language and a command to automatically enforce them." --- # Style Conventions diff --git a/website/docs/language/values/index.html.md b/website/docs/language/values/index.html.md index a32ef6b39..3074f965c 100644 --- a/website/docs/language/values/index.html.md +++ b/website/docs/language/values/index.html.md @@ -1,8 +1,7 @@ --- layout: "language" page_title: "Variables and Outputs" -description: |- - An overview of input variables, output values, and local values in Terraform language. +description: "An overview of input variables, output values, and local values in Terraform language." --- # Variables and Outputs diff --git a/website/docs/language/values/locals.html.md b/website/docs/language/values/locals.html.md index e4639ae0d..a487698bf 100644 --- a/website/docs/language/values/locals.html.md +++ b/website/docs/language/values/locals.html.md @@ -2,8 +2,7 @@ layout: "language" page_title: "Local Values - Configuration Language" sidebar_current: "docs-config-locals" -description: |- - Local values assign a name to an expression that can be used multiple times within a Terraform module. +description: "Local values assign a name to an expression that can be used multiple times within a Terraform module." --- # Local Values diff --git a/website/docs/language/values/variables.html.md b/website/docs/language/values/variables.html.md index 3362537c6..d770b1bec 100644 --- a/website/docs/language/values/variables.html.md +++ b/website/docs/language/values/variables.html.md @@ -2,8 +2,7 @@ layout: "language" page_title: "Input Variables - Configuration Language" sidebar_current: "docs-config-variables" -description: |- - Input variables allow you to customize modules without altering their source code. Learn how to declare, define, and reference variables in configurations. +description: "Input variables allow you to customize modules without altering their source code. Learn how to declare, define, and reference variables in configurations." --- # Input Variables diff --git a/website/docs/providers/index.html.markdown b/website/docs/providers/index.html.markdown index 07d99f957..07762206a 100644 --- a/website/docs/providers/index.html.markdown +++ b/website/docs/providers/index.html.markdown @@ -2,8 +2,7 @@ layout: "language" page_title: "Provider Documentation" sidebar_current: "docs-providers" -description: |- - Pointers to provider documentation on the Terraform Registry and to information about how to create documentation for your provider. +description: "Find provider documentation on the Terraform Registry and information about creating documentation for your provider." --- # Provider Documentation @@ -12,6 +11,5 @@ description: |- Every Terraform provider has its own documentation on the [Terraform Registry](https://registry.terraform.io/browse/providers) that describes its resource types and their arguments. ## Write Provider Docs -Learn more about writing, generating, and rendering provider documentation -in the [provider publishing documentation](/docs/registry/providers/docs.html). +Learn more about [writing, generating, and rendering provider documentation](/docs/registry/providers/docs.html). From ea077cbd90b3e079ef4df5659a6ac06ecab49d91 Mon Sep 17 00:00:00 2001 From: James Bardin Date: Mon, 19 Jul 2021 14:54:48 -0400 Subject: [PATCH 086/107] handle marks within ignore_changes Up until now marks were not considered by `ignore_changes`, that however means changes to sensitivity within a configuration cannot ignored, even though they are planned as changes. Rather than separating the marks and tracking their paths, we can easily update the processIgnoreChanges routine to handle the marked values directly. Moving the `processIgnoreChanges` call also cleans up some of the variable naming, making it more consistent through the body of the function. --- .../node_resource_abstract_instance.go | 83 ++++++++++++------- internal/terraform/reduce_plan_test.go | 2 +- 2 files changed, 56 insertions(+), 29 deletions(-) diff --git a/internal/terraform/node_resource_abstract_instance.go b/internal/terraform/node_resource_abstract_instance.go index c3c28e2c6..d2279f88f 100644 --- a/internal/terraform/node_resource_abstract_instance.go +++ b/internal/terraform/node_resource_abstract_instance.go @@ -687,26 +687,24 @@ func (n *NodeAbstractResourceInstance) plan( priorVal = cty.NullVal(schema.ImpliedType()) } - // Create an unmarked version of our config val and our prior val. - // Store the paths for the config val to re-markafter - // we've sent things over the wire. - unmarkedConfigVal, unmarkedPaths := origConfigVal.UnmarkDeepWithPaths() - unmarkedPriorVal, priorPaths := priorVal.UnmarkDeepWithPaths() - log.Printf("[TRACE] Re-validating config for %q", n.Addr) - // Allow the provider to validate the final set of values. - // The config was statically validated early on, but there may have been - // unknown values which the provider could not validate at the time. + // Allow the provider to validate the final set of values. The config was + // statically validated early on, but there may have been unknown values + // which the provider could not validate at the time. + // // TODO: It would be more correct to validate the config after // ignore_changes has been applied, but the current implementation cannot // exclude computed-only attributes when given the `all` option. + + // we must unmark and use the original config, since the ignore_changes + // handling below needs access to the marks. + unmarkedConfigVal, _ := origConfigVal.UnmarkDeep() validateResp := provider.ValidateResourceConfig( providers.ValidateResourceConfigRequest{ TypeName: n.Addr.Resource.Resource.Type, Config: unmarkedConfigVal, }, ) - diags = diags.Append(validateResp.Diagnostics.InConfigBody(config.Config, n.Addr.String())) if diags.HasErrors() { return plan, state, diags @@ -717,13 +715,21 @@ func (n *NodeAbstractResourceInstance) plan( // the proposed value, the proposed value itself, and the config presented // to the provider in the PlanResourceChange request all agree on the // starting values. - configValIgnored, ignoreChangeDiags := n.processIgnoreChanges(unmarkedPriorVal, unmarkedConfigVal) + // Here we operate on the marked values, so as to revert any changes to the + // marks as well as the value. + configValIgnored, ignoreChangeDiags := n.processIgnoreChanges(priorVal, origConfigVal) diags = diags.Append(ignoreChangeDiags) if ignoreChangeDiags.HasErrors() { return plan, state, diags } - proposedNewVal := objchange.ProposedNew(schema, unmarkedPriorVal, configValIgnored) + // Create an unmarked version of our config val and our prior val. + // Store the paths for the config val to re-mark after we've sent things + // over the wire. + unmarkedConfigVal, unmarkedPaths := configValIgnored.UnmarkDeepWithPaths() + unmarkedPriorVal, priorPaths := priorVal.UnmarkDeepWithPaths() + + proposedNewVal := objchange.ProposedNew(schema, unmarkedPriorVal, unmarkedConfigVal) // Call pre-diff hook diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) { @@ -735,7 +741,7 @@ func (n *NodeAbstractResourceInstance) plan( resp := provider.PlanResourceChange(providers.PlanResourceChangeRequest{ TypeName: n.Addr.Resource.Resource.Type, - Config: configValIgnored, + Config: unmarkedConfigVal, PriorState: unmarkedPriorVal, ProposedNewState: proposedNewVal, PriorPrivate: priorPrivate, @@ -774,7 +780,7 @@ func (n *NodeAbstractResourceInstance) plan( return plan, state, diags } - if errs := objchange.AssertPlanValid(schema, unmarkedPriorVal, configValIgnored, plannedNewVal); len(errs) > 0 { + if errs := objchange.AssertPlanValid(schema, unmarkedPriorVal, unmarkedConfigVal, plannedNewVal); len(errs) > 0 { if resp.LegacyTypeSystem { // The shimming of the old type system in the legacy SDK is not precise // enough to pass this consistency check, so we'll give it a pass here, @@ -1085,7 +1091,7 @@ func (n *NodeAbstractResource) processIgnoreChanges(prior, config cty.Value) (ct return config, nil } - ignoreChanges := n.Config.Managed.IgnoreChanges + ignoreChanges := traversalsToPaths(n.Config.Managed.IgnoreChanges) ignoreAll := n.Config.Managed.IgnoreAllChanges if len(ignoreChanges) == 0 && !ignoreAll { @@ -1100,14 +1106,16 @@ func (n *NodeAbstractResource) processIgnoreChanges(prior, config cty.Value) (ct return config, nil } - return processIgnoreChangesIndividual(prior, config, ignoreChanges) + ret, diags := processIgnoreChangesIndividual(prior, config, ignoreChanges) + + return ret, diags } -func processIgnoreChangesIndividual(prior, config cty.Value, ignoreChanges []hcl.Traversal) (cty.Value, tfdiags.Diagnostics) { - // When we walk below we will be using cty.Path values for comparison, so - // we'll convert our traversals here so we can compare more easily. - ignoreChangesPath := make([]cty.Path, len(ignoreChanges)) - for i, traversal := range ignoreChanges { +// Convert the hcl.Traversal values we get form the configuration to the +// cty.Path values we need to operate on the cty.Values +func traversalsToPaths(traversals []hcl.Traversal) []cty.Path { + paths := make([]cty.Path, len(traversals)) + for i, traversal := range traversals { path := make(cty.Path, len(traversal)) for si, step := range traversal { switch ts := step.(type) { @@ -1127,9 +1135,12 @@ func processIgnoreChangesIndividual(prior, config cty.Value, ignoreChanges []hcl panic(fmt.Sprintf("unsupported traversal step %#v", step)) } } - ignoreChangesPath[i] = path + paths[i] = path } + return paths +} +func processIgnoreChangesIndividual(prior, config cty.Value, ignoreChangesPath []cty.Path) (cty.Value, tfdiags.Diagnostics) { type ignoreChange struct { // Path is the full path, minus any trailing map index path cty.Path @@ -1175,8 +1186,7 @@ func processIgnoreChangesIndividual(prior, config cty.Value, ignoreChanges []hcl // here even if our ignored key doesn't change. That is OK since it // won't cause any changes in the transformation, but allows us to skip // breaking up the maps and checking for key existence here too. - eq := p.Equals(c) - if !eq.IsKnown() || eq.False() { + if !p.RawEquals(c) { // there a change to ignore at this path, store the prior value ignoredValues = append(ignoredValues, ignoreChange{icPath, p, key}) } @@ -1205,6 +1215,10 @@ func processIgnoreChangesIndividual(prior, config cty.Value, ignoreChanges []hcl return v, nil } + // The map values will remain as cty values, so we only need to store + // the marks from the outer map itself + v, vMarks := v.Unmark() + // The configMap is the current configuration value, which we will // mutate based on the ignored paths and the prior map value. var configMap map[string]cty.Value @@ -1234,11 +1248,17 @@ func processIgnoreChangesIndividual(prior, config cty.Value, ignoreChanges []hcl // return null for a key with a null value and for a non-existent // key. var priorMap map[string]cty.Value + + // We need to drop the marks from the ignored map for handling. We + // don't need to store these, as we now know the ignored value is + // only within the map, not the map itself. + ignoredVal, _ := ignored.value.Unmark() + switch { - case ignored.value.IsNull() || ignored.value.LengthInt() == 0: + case ignored.value.IsNull() || ignoredVal.LengthInt() == 0: priorMap = map[string]cty.Value{} default: - priorMap = ignored.value.AsValueMap() + priorMap = ignoredVal.AsValueMap() } key := ignored.key.AsString() @@ -1254,11 +1274,18 @@ func processIgnoreChangesIndividual(prior, config cty.Value, ignoreChanges []hcl } } + var newVal cty.Value if len(configMap) == 0 { - return cty.MapValEmpty(v.Type().ElementType()), nil + newVal = cty.MapValEmpty(v.Type().ElementType()) + } else { + newVal = cty.MapVal(configMap) } - return cty.MapVal(configMap), nil + if len(vMarks) > 0 { + newVal = v.WithMarks(vMarks) + } + + return newVal, nil }) return ret, nil } diff --git a/internal/terraform/reduce_plan_test.go b/internal/terraform/reduce_plan_test.go index 30d819aad..2d134d2c2 100644 --- a/internal/terraform/reduce_plan_test.go +++ b/internal/terraform/reduce_plan_test.go @@ -382,7 +382,7 @@ func TestProcessIgnoreChangesIndividual(t *testing.T) { ignore[i] = trav } - ret, diags := processIgnoreChangesIndividual(test.Old, test.New, ignore) + ret, diags := processIgnoreChangesIndividual(test.Old, test.New, traversalsToPaths(ignore)) if diags.HasErrors() { t.Fatal(diags.Err()) } From e574f73f61ba604f9de2761cfdc51852e7818b35 Mon Sep 17 00:00:00 2001 From: James Bardin Date: Mon, 19 Jul 2021 15:33:28 -0400 Subject: [PATCH 087/107] test with marked, unknown, planned values --- internal/terraform/context_apply2_test.go | 56 +++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/internal/terraform/context_apply2_test.go b/internal/terraform/context_apply2_test.go index 5d90e8f09..e172b4dd2 100644 --- a/internal/terraform/context_apply2_test.go +++ b/internal/terraform/context_apply2_test.go @@ -508,3 +508,59 @@ output "out" { } } } + +func TestContext2Apply_ignoreImpureFunctionChanges(t *testing.T) { + // Ensure we're not trying to double-mark values decoded from state + m := testModuleInline(t, map[string]string{ + "main.tf": ` +variable "pw" { + sensitive = true + default = "foo" +} + +resource "test_object" "x" { + test_map = { + string = "X${bcrypt(var.pw)}" + } + lifecycle { + ignore_changes = [ test_map["string"] ] + } +} + +`, + }) + + p := simpleMockProvider() + + ctx := testContext2(t, &ContextOpts{ + Config: m, + Providers: map[addrs.Provider]providers.Factory{ + addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), + }, + }) + + _, diags := ctx.Plan() + if diags.HasErrors() { + t.Fatal(diags.ErrWithWarnings()) + } + + _, diags = ctx.Apply() + if diags.HasErrors() { + t.Fatal(diags.ErrWithWarnings()) + } + + // FINAL PLAN: + plan, diags := ctx.Plan() + if diags.HasErrors() { + t.Fatal(diags.ErrWithWarnings()) + } + + // make sure the same marks are compared in the next plan as well + for _, c := range plan.Changes.Resources { + if c.Action != plans.NoOp { + t.Logf("marks before: %#v", c.BeforeValMarks) + t.Logf("marks after: %#v", c.AfterValMarks) + t.Errorf("Unexpcetd %s change for %s", c.Action, c.Addr) + } + } +} From 66a5950acbec653aff0e91cc41c7c84932e73f0b Mon Sep 17 00:00:00 2001 From: James Bardin Date: Mon, 19 Jul 2021 15:33:38 -0400 Subject: [PATCH 088/107] ignored value in this test should not be marked --- internal/terraform/context_plan_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/terraform/context_plan_test.go b/internal/terraform/context_plan_test.go index 4efc2f136..8a5bc9e6f 100644 --- a/internal/terraform/context_plan_test.go +++ b/internal/terraform/context_plan_test.go @@ -4794,7 +4794,7 @@ func TestContext2Plan_ignoreChangesSensitive(t *testing.T) { checkVals(t, objectVal(t, schema, map[string]cty.Value{ "id": cty.StringVal("bar"), - "ami": cty.StringVal("ami-abcd1234").Mark(marks.Sensitive), + "ami": cty.StringVal("ami-abcd1234"), "type": cty.StringVal("aws_instance"), }), ric.After) } From 9c20ed61852dfcf8ef469aa85615ea91b2fe5137 Mon Sep 17 00:00:00 2001 From: James Bardin Date: Wed, 17 Mar 2021 14:44:16 -0400 Subject: [PATCH 089/107] StateMgr must be able to return with locked state The current usage of internal remote state backends requires that `StateMgr` be able to return an instance of `statemgr.Full` even if the state is currently locked. --- .../remote-state/etcdv3/backend_state.go | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/internal/backend/remote-state/etcdv3/backend_state.go b/internal/backend/remote-state/etcdv3/backend_state.go index b9bd3839d..b1a931460 100644 --- a/internal/backend/remote-state/etcdv3/backend_state.go +++ b/internal/backend/remote-state/etcdv3/backend_state.go @@ -58,16 +58,8 @@ func (b *Backend) StateMgr(name string) (statemgr.Full, error) { lockInfo := statemgr.NewLockInfo() lockInfo.Operation = "init" - lockId, err := stateMgr.Lock(lockInfo) - if err != nil { - return nil, fmt.Errorf("Failed to lock state in etcd: %s.", err) - } - lockUnlock := func(parent error) error { - if err := stateMgr.Unlock(lockId); err != nil { - return fmt.Errorf(strings.TrimSpace(errStateUnlock), lockId, err) - } - return parent + return nil } if err := stateMgr.RefreshState(); err != nil { @@ -76,6 +68,18 @@ func (b *Backend) StateMgr(name string) (statemgr.Full, error) { } if v := stateMgr.State(); v == nil { + lockId, err := stateMgr.Lock(lockInfo) + if err != nil { + return nil, fmt.Errorf("Failed to lock state in etcd: %s.", err) + } + + lockUnlock = func(parent error) error { + if err := stateMgr.Unlock(lockId); err != nil { + return fmt.Errorf(strings.TrimSpace(errStateUnlock), lockId, err) + } + return parent + } + if err := stateMgr.WriteState(states.NewState()); err != nil { err = lockUnlock(err) return nil, err From c047958b5708e4f500fe61000a662c169d048fff Mon Sep 17 00:00:00 2001 From: Kevin Burke Date: Wed, 27 Jan 2021 14:04:52 -0800 Subject: [PATCH 090/107] go.mod,backend: update coreos/etcd dependency to release-3.4 branch etcd rewrote its import path from coreos/etcd to go.etcd.io/etcd. Changed the imports path in this commit, which also updates the code version. This lets us remove the github.com/ugorji/go/codec dependency, which was pinned to a fairly old version. The net change is a loss of 30,000 lines of code in the vendor directory. (I first noticed this problem because the outdated go/codec dependency was causing a dependency failure when I tried to put Terraform and another project in the same vendor directory.) Note the version shows up funkily in go.mod, but I verified visually it's the same commit as the "release-3.4" tag in github.com/coreos/etcd. The etcd team plans to fix the release version tagging in v3.5, which should be released soon. --- go.mod | 20 +---- go.sum | 77 +++++++++++-------- .../backend/remote-state/etcdv2/backend.go | 2 +- .../backend/remote-state/etcdv2/client.go | 2 +- .../backend/remote-state/etcdv3/backend.go | 4 +- .../remote-state/etcdv3/backend_state.go | 2 +- .../remote-state/etcdv3/backend_test.go | 2 +- .../backend/remote-state/etcdv3/client.go | 4 +- internal/logging/logging.go | 5 ++ 9 files changed, 61 insertions(+), 57 deletions(-) diff --git a/go.mod b/go.mod index 3c4747fba..0e4f1872a 100644 --- a/go.mod +++ b/go.mod @@ -23,13 +23,9 @@ require ( github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect github.com/bgentry/speakeasy v0.1.0 github.com/bmatcuk/doublestar v1.1.5 - github.com/boltdb/bolt v1.3.1 // indirect github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e - github.com/coreos/bbolt v1.3.0 // indirect - github.com/coreos/etcd v3.3.10+incompatible - github.com/coreos/go-semver v0.2.0 // indirect github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d // indirect - github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect + github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f github.com/davecgh/go-spew v1.1.1 github.com/dylanmei/iso8601 v0.1.0 // indirect github.com/dylanmei/winrmtest v0.0.0-20190225150635-99b7fe2fddf1 @@ -42,10 +38,6 @@ require ( github.com/gophercloud/gophercloud v0.10.1-0.20200424014253-c3bfe50899e5 github.com/gophercloud/utils v0.0.0-20200423144003-7c72efc7435d github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 // indirect - github.com/gorilla/websocket v1.4.0 // indirect - github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 // indirect - github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect - github.com/grpc-ecosystem/grpc-gateway v1.8.5 // indirect github.com/hashicorp/aws-sdk-go-base v0.6.0 github.com/hashicorp/consul v0.0.0-20171026175957-610f3c86a089 github.com/hashicorp/errwrap v1.1.0 @@ -72,7 +64,6 @@ require ( github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734 github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d // indirect github.com/jmespath/go-jmespath v0.4.0 - github.com/jonboulle/clockwork v0.1.0 // indirect github.com/joyent/triton-go v0.0.0-20180313100802-d8f9c0314926 github.com/jtolds/gls v4.2.1+incompatible // indirect github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 @@ -100,26 +91,19 @@ require ( github.com/pkg/browser v0.0.0-20201207095918-0426ae3fba23 github.com/pkg/errors v0.9.1 github.com/posener/complete v1.2.1 - github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829 // indirect github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d // indirect github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a // indirect - github.com/soheilhy/cmux v0.1.4 // indirect github.com/spf13/afero v1.2.2 github.com/tencentcloud/tencentcloud-sdk-go v3.0.82+incompatible github.com/tencentyun/cos-go-sdk-v5 v0.0.0-20190808065407-f07404cefc8c - github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6 // indirect github.com/tombuildsstuff/giovanni v0.15.1 - github.com/ugorji/go v0.0.0-20180813092308-00b869d2f4a5 // indirect github.com/xanzy/ssh-agent v0.2.1 - github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18 // indirect github.com/xlab/treeprint v0.0.0-20161029104018-1d6e34225557 github.com/zclconf/go-cty v1.9.0 github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b github.com/zclconf/go-cty-yaml v1.0.2 - go.uber.org/atomic v1.3.2 // indirect - go.uber.org/multierr v1.1.0 // indirect - go.uber.org/zap v1.9.1 // indirect + go.etcd.io/etcd v0.5.0-alpha.5.0.20210428180535-15715dcf1ace golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 golang.org/x/mod v0.4.2 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 diff --git a/go.sum b/go.sum index c3d16dcd8..3af90043b 100644 --- a/go.sum +++ b/go.sum @@ -134,16 +134,15 @@ github.com/aws/aws-sdk-go v1.37.0 h1:GzFnhOIsrGyQ69s7VgqtrG2BG8v7X7vwB3Xpbd/DBBk github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f h1:ZNv7On9kyUzm7fvRZumSyy/IUiSC7AzL0I1jKKtwooA= github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bmatcuk/doublestar v1.1.5 h1:2bNwBOmhyFEFcoB3tGvTD5xanq+4kyOZlB8wFYbMjkk= github.com/bmatcuk/doublestar v1.1.5/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE= -github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4= -github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= @@ -156,16 +155,17 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/coreos/bbolt v1.3.0 h1:HIgH5xUWXT914HCI671AxuTTqjj64UOFr7pHn48LUTI= -github.com/coreos/bbolt v1.3.0/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa h1:OaNxuTZr7kxeODyLWsRMC+OD03aFUH+mW6r2d+MWa5Y= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/coreos/go-semver v0.2.0 h1:3Jm3tLmsgAYcjC+4Up7hJrFBPr+n7rAqYeSw/SZazuY= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d h1:t5Wuyh53qYyg9eqn4BbnlIT+vmhyww0TatL+zT3uWgI= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -177,6 +177,8 @@ github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQ github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U= github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4 h1:qk/FSDDxo05wdJH28W+p5yivv7LuLYLRXPPD8KQCtZs= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dylanmei/iso8601 v0.1.0 h1:812NGQDBcqquTfH5Yeo7lwR0nzx/cKdsmf3qMjPURUI= github.com/dylanmei/iso8601 v0.1.0/go.mod h1:w9KhXSgIyROl1DefbMYIE7UVSIvELTbMrCfx+QkYnoQ= github.com/dylanmei/winrmtest v0.0.0-20190225150635-99b7fe2fddf1 h1:r1oACdS2XYiAWcfF8BJXkoU8l1J71KehGR+d99yWEDA= @@ -197,7 +199,6 @@ github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTg github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -219,6 +220,7 @@ github.com/gofrs/uuid v3.3.0+incompatible h1:8K4tyRfvU1CYPgJsveYFQMhpFd/wXNM7iK6 github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v0.0.0-20171007142547-342cbe0a0415/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= @@ -310,15 +312,15 @@ github.com/gophercloud/utils v0.0.0-20200423144003-7c72efc7435d h1:fduaPzWwIfvOM github.com/gophercloud/utils v0.0.0-20200423144003-7c72efc7435d/go.mod h1:ehWUbLQJPqS0Ep+CxeD559hsm9pthPXadJNKwZkp43w= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 h1:Iju5GlWwrvL6UBg4zJJt3btmonfrMlCDdsejg4CZE7c= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4 h1:z53tR0945TRRQO/fLEVPI6SMv7ZflF0TEaTAoU7tOzg= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.8.5 h1:2+KSC78XiO6Qy0hIjfc1OD9H+hsaJdJlb8Kqsd41CTE= -github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.5 h1:UImYN5qQ8tuGpGE16ZmjvcTtTw24zw1QAp/SlnNrZhI= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/hashicorp/aws-sdk-go-base v0.6.0 h1:qmUbzM36msbBF59YctwuO5w0M2oNXjlilgKpnEhx1uw= github.com/hashicorp/aws-sdk-go-base v0.6.0/go.mod h1:2fRjWDv3jJBeN6mVWFHV6hFTNeFBx2gpDLQaZNxUVAY= github.com/hashicorp/consul v0.0.0-20171026175957-610f3c86a089 h1:1eDpXAxTh0iPv+1kc9/gfSI2pxRERDsTk/lNGolwHn8= @@ -397,6 +399,7 @@ github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1: github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= @@ -411,6 +414,7 @@ github.com/joyent/triton-go v0.0.0-20180313100802-d8f9c0314926 h1:kie3qOosvRKqwi github.com/joyent/triton-go v0.0.0-20180313100802-d8f9c0314926/go.mod h1:U+RSyWxWd04xTqnuOQxnai7XGS2PrPY2cfGoDKtMHjA= github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= @@ -421,6 +425,7 @@ github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVY github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.11.2 h1:MiK62aErc3gIiVEtyzKfeOHgW7atJb5g/KNX5m3c2nQ= @@ -463,6 +468,7 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-shellwords v1.0.4 h1:xmZZyxuP+bYKAKkA9ABYXVNJ+G/Wf3R8d8vAP3LDJJk= github.com/mattn/go-shellwords v1.0.4/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= @@ -514,6 +520,7 @@ github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/ github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -537,17 +544,17 @@ github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndr github.com/posener/complete v1.2.1 h1:LrvDIY//XNo65Lq84G/akBuMGlawHvGBABv8f/ZN6DI= github.com/posener/complete v1.2.1/go.mod h1:6gapUrK/U1TAN7ciCoNRIdVC5sbdBTUh1DKN0g6uH7E= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829 h1:D+CiwcpGTW6pL6bv6KI3KbyEyCKyS+1JWS2h8PNDnGA= -github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= +github.com/prometheus/client_golang v1.0.0 h1:vrDKnkGzuGvhNAL56c7DBz29ZL+KxnoR0x7enabFceM= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.2.0 h1:kUZDBDTdBVBYBj5Tmh2NZLlF60mfjA27rM34b+cVwNU= -github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1 h1:/K3IL0Z1quvmJ7X0A1AwNEK7CRkVK3YwfOU/QAL4WGg= -github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2 h1:6LJUbpNm42llc4HRCuvApCSWB/WfhuNo9K98Q9sNGfs= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= @@ -556,8 +563,9 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUt github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a h1:JSvGDIbmil4Ui/dDdFBExb7/cmkNjyX5F97oglmvCDo= @@ -566,6 +574,7 @@ github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -584,14 +593,13 @@ github.com/tencentcloud/tencentcloud-sdk-go v3.0.82+incompatible h1:5Td2b0yfaOvw github.com/tencentcloud/tencentcloud-sdk-go v3.0.82+incompatible/go.mod h1:0PfYow01SHPMhKY31xa+EFz2RStxIqj6JFAJS+IkCi4= github.com/tencentyun/cos-go-sdk-v5 v0.0.0-20190808065407-f07404cefc8c h1:iRD1CqtWUjgEVEmjwTMbP1DMzz1HRytOsgx/rlw/vNs= github.com/tencentyun/cos-go-sdk-v5 v0.0.0-20190808065407-f07404cefc8c/go.mod h1:wk2XFUg6egk4tSDNZtXeKfe2G6690UVyt163PuUxBZk= -github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6 h1:lYIiVDtZnyTWlNwiAxLj0bbpTcx1BWCFhXjfsvmPdNc= -github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20200427203606-3cfed13b9966 h1:j6JEOq5QWFker+d7mFQYOhjTZonQ7YkLTHm56dbn+yM= +github.com/tmc/grpc-websocket-proxy v0.0.0-20200427203606-3cfed13b9966/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tombuildsstuff/giovanni v0.15.1 h1:CVRaLOJ7C/eercCrKIsarfJ4SZoGMdBL9Q2deFDUXco= github.com/tombuildsstuff/giovanni v0.15.1/go.mod h1:0TZugJPEtqzPlMpuJHYfXY6Dq2uLPrXf98D2XQSxNbA= -github.com/ugorji/go v0.0.0-20180813092308-00b869d2f4a5 h1:cMjKdf4PxEBN9K5HaD9UMW8gkTbM0kMzkTa9SJe0WNQ= -github.com/ugorji/go v0.0.0-20180813092308-00b869d2f4a5/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= github.com/ulikunitz/xz v0.5.8 h1:ERv8V6GKqVi23rgu5cj9pVfVzJbOqAY2Ntl88O6c2nQ= github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/vmihailenco/msgpack v3.3.3+incompatible h1:wapg9xDUZDzGCNFlwc5SqI1rvcciqcxEHac4CYj89xI= github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= github.com/vmihailenco/msgpack/v4 v4.3.12 h1:07s4sz9IReOgdikxLTKNbBdqDMLsjPKXwvCazn8G65U= @@ -600,8 +608,8 @@ github.com/vmihailenco/tagparser v0.1.1 h1:quXMXlA39OCbd2wAdTsGDlK9RkOk6Wuw+x37w github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70= github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= -github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18 h1:MPPkRncZLN9Kh4MEFmbnK4h3BD7AUmskWv2+EeZJCCs= -github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/treeprint v0.0.0-20161029104018-1d6e34225557 h1:Jpn2j6wHkC9wJv5iMfJhKqrZJx3TahFx+7sbZ7zQdxs= github.com/xlab/treeprint v0.0.0-20161029104018-1d6e34225557/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -618,6 +626,10 @@ github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b h1:FosyBZYxY3 github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8= github.com/zclconf/go-cty-yaml v1.0.2 h1:dNyg4QLTrv2IfJpm7Wtxi55ed5gLGOlPrZ6kMd51hY0= github.com/zclconf/go-cty-yaml v1.0.2/go.mod h1:IP3Ylp0wQpYm50IHK8OZWKMu6sPJIUgKa8XhiVHura0= +go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd v0.5.0-alpha.5.0.20210428180535-15715dcf1ace h1:wOZR+AfzmQYNRqx1F+LL9TX8vBVzSbndRoc0tr/Bp4k= +go.etcd.io/etcd v0.5.0-alpha.5.0.20210428180535-15715dcf1ace/go.mod h1:q+i20RPAmay+xq8LJ3VMOhXCNk4YCk3V7QP91meFavw= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -630,8 +642,8 @@ go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o= -go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -694,7 +706,6 @@ golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190206173232-65e2d4e15006/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -764,6 +775,7 @@ golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -818,10 +830,12 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20161028155119-f51c12702a4d/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -981,6 +995,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= diff --git a/internal/backend/remote-state/etcdv2/backend.go b/internal/backend/remote-state/etcdv2/backend.go index 58ecc3b20..e6d3cf8ce 100644 --- a/internal/backend/remote-state/etcdv2/backend.go +++ b/internal/backend/remote-state/etcdv2/backend.go @@ -6,11 +6,11 @@ import ( "context" "strings" - etcdapi "github.com/coreos/etcd/client" "github.com/hashicorp/terraform/internal/backend" "github.com/hashicorp/terraform/internal/legacy/helper/schema" "github.com/hashicorp/terraform/internal/states/remote" "github.com/hashicorp/terraform/internal/states/statemgr" + etcdapi "go.etcd.io/etcd/client" ) func New() backend.Backend { diff --git a/internal/backend/remote-state/etcdv2/client.go b/internal/backend/remote-state/etcdv2/client.go index eab2b1978..97e44f41b 100644 --- a/internal/backend/remote-state/etcdv2/client.go +++ b/internal/backend/remote-state/etcdv2/client.go @@ -5,8 +5,8 @@ import ( "crypto/md5" "fmt" - etcdapi "github.com/coreos/etcd/client" "github.com/hashicorp/terraform/internal/states/remote" + etcdapi "go.etcd.io/etcd/client" ) // EtcdClient is a remote client that stores data in etcd. diff --git a/internal/backend/remote-state/etcdv3/backend.go b/internal/backend/remote-state/etcdv3/backend.go index 91b8082b5..598f31583 100644 --- a/internal/backend/remote-state/etcdv3/backend.go +++ b/internal/backend/remote-state/etcdv3/backend.go @@ -3,10 +3,10 @@ package etcd import ( "context" - etcdv3 "github.com/coreos/etcd/clientv3" - "github.com/coreos/etcd/pkg/transport" "github.com/hashicorp/terraform/internal/backend" "github.com/hashicorp/terraform/internal/legacy/helper/schema" + etcdv3 "go.etcd.io/etcd/clientv3" + "go.etcd.io/etcd/pkg/transport" ) const ( diff --git a/internal/backend/remote-state/etcdv3/backend_state.go b/internal/backend/remote-state/etcdv3/backend_state.go index b9bd3839d..e4d83affb 100644 --- a/internal/backend/remote-state/etcdv3/backend_state.go +++ b/internal/backend/remote-state/etcdv3/backend_state.go @@ -6,7 +6,7 @@ import ( "sort" "strings" - etcdv3 "github.com/coreos/etcd/clientv3" + etcdv3 "go.etcd.io/etcd/clientv3" "github.com/hashicorp/terraform/internal/backend" "github.com/hashicorp/terraform/internal/states" diff --git a/internal/backend/remote-state/etcdv3/backend_test.go b/internal/backend/remote-state/etcdv3/backend_test.go index 2b4d312a7..8b4039cfc 100644 --- a/internal/backend/remote-state/etcdv3/backend_test.go +++ b/internal/backend/remote-state/etcdv3/backend_test.go @@ -9,8 +9,8 @@ import ( "testing" "time" - etcdv3 "github.com/coreos/etcd/clientv3" "github.com/hashicorp/terraform/internal/backend" + etcdv3 "go.etcd.io/etcd/clientv3" ) var ( diff --git a/internal/backend/remote-state/etcdv3/client.go b/internal/backend/remote-state/etcdv3/client.go index 42823e37a..3761f149f 100644 --- a/internal/backend/remote-state/etcdv3/client.go +++ b/internal/backend/remote-state/etcdv3/client.go @@ -8,11 +8,11 @@ import ( "sync" "time" - etcdv3 "github.com/coreos/etcd/clientv3" - etcdv3sync "github.com/coreos/etcd/clientv3/concurrency" "github.com/hashicorp/go-multierror" "github.com/hashicorp/terraform/internal/states/remote" "github.com/hashicorp/terraform/internal/states/statemgr" + etcdv3 "go.etcd.io/etcd/clientv3" + etcdv3sync "go.etcd.io/etcd/clientv3/concurrency" ) const ( diff --git a/internal/logging/logging.go b/internal/logging/logging.go index e25aa64f3..972f7cfae 100644 --- a/internal/logging/logging.go +++ b/internal/logging/logging.go @@ -8,6 +8,11 @@ import ( "strings" "syscall" + // go.etcd.io/etcd imports capnslog, which calls log.SetOutput in its + // init() function, so importing it here means that our log.SetOutput + // wins. this is fixed in coreos v3.5, which is not released yet. See + // https://github.com/etcd-io/etcd/issues/12498 for more information. + _ "github.com/coreos/pkg/capnslog" "github.com/hashicorp/go-hclog" ) From f418b9cd5293660c614750feb6e91313e67f20de Mon Sep 17 00:00:00 2001 From: James Bardin Date: Tue, 20 Jul 2021 13:59:08 -0400 Subject: [PATCH 091/107] etcdv3 backend is unmaintained There have been no responses from the codeowner for this backend, so moving to Unmaintained status. --- CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index 01a05b435..bb6272e61 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -7,7 +7,7 @@ /internal/backend/remote-state/consul @hashicorp/consul @remilapeyre /internal/backend/remote-state/cos @likexian /internal/backend/remote-state/etcdv2 Unmaintained -/internal/backend/remote-state/etcdv3 @bmcustodio +/internal/backend/remote-state/etcdv3 Unmaintained /internal/backend/remote-state/gcs @hashicorp/terraform-google /internal/backend/remote-state/http @hashicorp/terraform-core /internal/backend/remote-state/manta Unmaintained From d1608d7a7f3483f45146d7e14d000d8f97186cac Mon Sep 17 00:00:00 2001 From: Jason Smith Date: Fri, 12 Mar 2021 17:38:58 -0600 Subject: [PATCH 092/107] Expose etcd client MaxCallSendMsgSize config The etcdv3 client has a default request send limit of 2.0 MiB. This change exposes the configuration option to increase that limit enabling larger state using the etcdv3 backend. This also requires that the corresponding --max-request-bytes flag be increased on the server side. The default there is 1.5 MiB. Fixes https://github.com/hashicorp/terraform/issues/25745 --- internal/backend/remote-state/etcdv3/backend.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/internal/backend/remote-state/etcdv3/backend.go b/internal/backend/remote-state/etcdv3/backend.go index 598f31583..7285bda96 100644 --- a/internal/backend/remote-state/etcdv3/backend.go +++ b/internal/backend/remote-state/etcdv3/backend.go @@ -15,6 +15,7 @@ const ( usernameEnvVarName = "ETCDV3_USERNAME" passwordKey = "password" passwordEnvVarName = "ETCDV3_PASSWORD" + maxRequestBytesKey = "max_request_bytes" prefixKey = "prefix" lockKey = "lock" cacertPathKey = "cacert_path" @@ -49,6 +50,13 @@ func New() backend.Backend { DefaultFunc: schema.EnvDefaultFunc(passwordEnvVarName, ""), }, + maxRequestBytesKey: &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Description: "The max request size to send to etcd.", + Default: 0, + }, + prefixKey: &schema.Schema{ Type: schema.TypeString, Optional: true, @@ -128,6 +136,9 @@ func (b *Backend) rawClient() (*etcdv3.Client, error) { if v, ok := b.data.GetOk(passwordKey); ok && v.(string) != "" { config.Password = v.(string) } + if v, ok := b.data.GetOk(maxRequestBytesKey); ok && v.(int) != 0 { + config.MaxCallSendMsgSize = v.(int) + } if v, ok := b.data.GetOk(cacertPathKey); ok && v.(string) != "" { tlsInfo.TrustedCAFile = v.(string) } From 162f853841b25797fe6c54c9a29269776ef66158 Mon Sep 17 00:00:00 2001 From: Jason Smith Date: Sat, 13 Mar 2021 11:35:30 -0600 Subject: [PATCH 093/107] Document max_request_bytes config --- website/docs/language/settings/backends/etcdv3.html.md | 1 + 1 file changed, 1 insertion(+) diff --git a/website/docs/language/settings/backends/etcdv3.html.md b/website/docs/language/settings/backends/etcdv3.html.md index 7c31d5125..8f406b53d 100644 --- a/website/docs/language/settings/backends/etcdv3.html.md +++ b/website/docs/language/settings/backends/etcdv3.html.md @@ -54,3 +54,4 @@ The following configuration options / environment variables are supported: * `cacert_path` - (Optional) The path to a PEM-encoded CA bundle with which to verify certificates of TLS-enabled etcd servers. * `cert_path` - (Optional) The path to a PEM-encoded certificate to provide to etcd for secure client identification. * `key_path` - (Optional) The path to a PEM-encoded key to provide to etcd for secure client identification. + * `max_request_bytes` - (Optional) The max request size to send to etcd. This can be increased to enable storage of larger state. You must set the corresponding server-side flag [--max-request-bytes](https://etcd.io/docs/current/dev-guide/limit/#request-size-limit) as well and the value should be less than the client setting. Defaults to `2097152` (2.0 MiB). **Please Note:** Increasing etcd's request size limit may negatively impact overall latency. From 5ff9b7626b6f063caf3ed5e6a368dab125c8039a Mon Sep 17 00:00:00 2001 From: Jason Smith Date: Sat, 13 Mar 2021 18:43:24 -0600 Subject: [PATCH 094/107] Fix broken link Fix website-link-check failing as https://coreos.com/etcd/ 301's to https://etcd.io/. Updated link to https://etcd.io/. --- website/docs/language/settings/backends/etcdv3.html.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/language/settings/backends/etcdv3.html.md b/website/docs/language/settings/backends/etcdv3.html.md index 8f406b53d..318a7b405 100644 --- a/website/docs/language/settings/backends/etcdv3.html.md +++ b/website/docs/language/settings/backends/etcdv3.html.md @@ -10,7 +10,7 @@ description: |- **Kind: Standard (with locking)** -Stores the state in the [etcd](https://coreos.com/etcd/) KV store with a given prefix. +Stores the state in the [etcd](https://etcd.io/) KV store with a given prefix. This backend supports [state locking](/docs/language/state/locking.html). From 07ee689eff36e193c54374048566a68361878a34 Mon Sep 17 00:00:00 2001 From: James Bardin Date: Tue, 20 Jul 2021 16:09:46 -0400 Subject: [PATCH 095/107] update comment and extend test --- internal/terraform/context_apply2_test.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/internal/terraform/context_apply2_test.go b/internal/terraform/context_apply2_test.go index e172b4dd2..681595959 100644 --- a/internal/terraform/context_apply2_test.go +++ b/internal/terraform/context_apply2_test.go @@ -510,7 +510,8 @@ output "out" { } func TestContext2Apply_ignoreImpureFunctionChanges(t *testing.T) { - // Ensure we're not trying to double-mark values decoded from state + // The impure function call should not cause a planned change with + // ignore_changes m := testModuleInline(t, map[string]string{ "main.tf": ` variable "pw" { @@ -527,6 +528,15 @@ resource "test_object" "x" { } } +resource "test_object" "y" { + test_map = { + string = "X${bcrypt(var.pw)}" + } + lifecycle { + ignore_changes = [ test_map ] + } +} + `, }) From 0b827ab6b6dec282b351dbd89b96595407f5dd33 Mon Sep 17 00:00:00 2001 From: Kristin Laemmert Date: Wed, 21 Jul 2021 08:51:35 -0400 Subject: [PATCH 096/107] format/diff: fix panic with null map in NestedType attrs (#29206) --- internal/command/format/diff.go | 6 ++++ internal/command/format/diff_test.go | 47 ++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/internal/command/format/diff.go b/internal/command/format/diff.go index da47b8f7c..b87b11c18 100644 --- a/internal/command/format/diff.go +++ b/internal/command/format/diff.go @@ -660,6 +660,12 @@ func (p *blockBodyDiffPrinter) writeNestedAttrDiff( p.buf.WriteString("]") case configschema.NestingMap: + // For the sake of handling nested blocks, we'll treat a null map + // the same as an empty map since the config language doesn't + // distinguish these anyway. + old = ctyNullBlockMapAsEmpty(old) + new = ctyNullBlockMapAsEmpty(new) + oldItems := old.AsValueMap() newItems := new.AsValueMap() diff --git a/internal/command/format/diff_test.go b/internal/command/format/diff_test.go index 1ab864b2a..2b4ece8d2 100644 --- a/internal/command/format/diff_test.go +++ b/internal/command/format/diff_test.go @@ -2869,6 +2869,53 @@ func TestResourceChange_nestedSet(t *testing.T) { func TestResourceChange_nestedMap(t *testing.T) { testCases := map[string]testCase{ + "creation from null": { + Action: plans.Update, + Mode: addrs.ManagedResourceMode, + Before: cty.ObjectVal(map[string]cty.Value{ + "id": cty.NullVal(cty.String), + "ami": cty.NullVal(cty.String), + "disks": cty.NullVal(cty.Map(cty.Object(map[string]cty.Type{ + "mount_point": cty.String, + "size": cty.String, + }))), + "root_block_device": cty.NullVal(cty.Map(cty.Object(map[string]cty.Type{ + "volume_type": cty.String, + }))), + }), + After: cty.ObjectVal(map[string]cty.Value{ + "id": cty.StringVal("i-02ae66f368e8518a9"), + "ami": cty.StringVal("ami-AFTER"), + "disks": cty.MapVal(map[string]cty.Value{ + "disk_a": cty.ObjectVal(map[string]cty.Value{ + "mount_point": cty.StringVal("/var/diska"), + "size": cty.NullVal(cty.String), + }), + }), + "root_block_device": cty.MapVal(map[string]cty.Value{ + "a": cty.ObjectVal(map[string]cty.Value{ + "volume_type": cty.StringVal("gp2"), + }), + }), + }), + RequiredReplace: cty.NewPathSet(), + Schema: testSchema(configschema.NestingMap), + ExpectedOutput: ` # test_instance.example will be updated in-place + ~ resource "test_instance" "example" { + + ami = "ami-AFTER" + + disks = { + + "disk_a" = { + + mount_point = "/var/diska" + }, + } + + id = "i-02ae66f368e8518a9" + + + root_block_device "a" { + + volume_type = "gp2" + } + } +`, + }, "in-place update - creation": { Action: plans.Update, Mode: addrs.ManagedResourceMode, From dfbacdc7341797e6d9a70c77c04e143c3139959b Mon Sep 17 00:00:00 2001 From: James Bardin Date: Wed, 21 Jul 2021 08:59:37 -0400 Subject: [PATCH 097/107] update hcl v2.10.1 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 0e4f1872a..da7655f69 100644 --- a/go.mod +++ b/go.mod @@ -57,7 +57,7 @@ require ( github.com/hashicorp/go-uuid v1.0.1 github.com/hashicorp/go-version v1.2.1 github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f - github.com/hashicorp/hcl/v2 v2.10.0 + github.com/hashicorp/hcl/v2 v2.10.1 github.com/hashicorp/memberlist v0.1.0 // indirect github.com/hashicorp/serf v0.0.0-20160124182025-e4ec8cc423bb // indirect github.com/hashicorp/terraform-config-inspect v0.0.0-20210209133302-4fd17a0faac2 diff --git a/go.sum b/go.sum index 3af90043b..25a9ffd23 100644 --- a/go.sum +++ b/go.sum @@ -376,8 +376,8 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f h1:UdxlrJz4JOnY8W+DbLISwf2B8WXEolNRA8BGCwI9jws= github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w= github.com/hashicorp/hcl/v2 v2.0.0/go.mod h1:oVVDG71tEinNGYCxinCYadcmKU9bglqW9pV3txagJ90= -github.com/hashicorp/hcl/v2 v2.10.0 h1:1S1UnuhDGlv3gRFV4+0EdwB+znNP5HmcGbIqwnSCByg= -github.com/hashicorp/hcl/v2 v2.10.0/go.mod h1:FwWsfWEjyV/CMj8s/gqAuiviY72rJ1/oayI9WftqcKg= +github.com/hashicorp/hcl/v2 v2.10.1 h1:h4Xx4fsrRE26ohAk/1iGF/JBqRQbyUqu5Lvj60U54ys= +github.com/hashicorp/hcl/v2 v2.10.1/go.mod h1:FwWsfWEjyV/CMj8s/gqAuiviY72rJ1/oayI9WftqcKg= github.com/hashicorp/jsonapi v0.0.0-20210518035559-1e50d74c8db3 h1:mzwkutymYIXR5oQT9YnfbLuuw7LZmksiHKRPUTN5ijo= github.com/hashicorp/jsonapi v0.0.0-20210518035559-1e50d74c8db3/go.mod h1:Yog5+CPEM3c99L1CL2CFCYoSzgWm5vTU58idbRUaLik= github.com/hashicorp/memberlist v0.1.0 h1:qSsCiC0WYD39lbSitKNt40e30uorm2Ss/d4JGU1hzH8= From aaf03d325101adc3903b3a37fb960c43f0795014 Mon Sep 17 00:00:00 2001 From: James Bardin Date: Wed, 21 Jul 2021 09:09:30 -0400 Subject: [PATCH 098/107] update test error for hclv2.10.1 --- internal/configs/configschema/validate_traversal_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/configs/configschema/validate_traversal_test.go b/internal/configs/configschema/validate_traversal_test.go index 242ab7202..2000d2e75 100644 --- a/internal/configs/configschema/validate_traversal_test.go +++ b/internal/configs/configschema/validate_traversal_test.go @@ -58,7 +58,7 @@ func TestStaticValidateTraversal(t *testing.T) { }, { `obj.str.nonexist`, - `Unsupported attribute: This value does not have any attributes.`, + `Unsupported attribute: Can't access attributes on a primitive-typed value (string).`, }, { `obj.list`, From 0729e9fdd7fa843ebeef8c5c14cab9754c3377c5 Mon Sep 17 00:00:00 2001 From: Kristin Laemmert Date: Thu, 22 Jul 2021 09:45:33 -0400 Subject: [PATCH 099/107] configs/configschema: extend block.AttributeByPath to descend into Objects (#29222) * configs/configschema: extend block.AttributeByPath to descend into Objects This commit adds a recursive Object.AttributeByPath function which will step through Attributes with NestedTypes. If an Attribute without a NestedType is encountered while there is still more to the path, it will return nil. --- internal/configs/configschema/path.go | 30 +++++- internal/configs/configschema/path_test.go | 108 +++++++++++++++++++++ 2 files changed, 136 insertions(+), 2 deletions(-) diff --git a/internal/configs/configschema/path.go b/internal/configs/configschema/path.go index 4c48c1a04..d3584d3a2 100644 --- a/internal/configs/configschema/path.go +++ b/internal/configs/configschema/path.go @@ -7,13 +7,19 @@ import ( // AttributeByPath looks up the Attribute schema which corresponds to the given // cty.Path. A nil value is returned if the given path does not correspond to a // specific attribute. -// TODO: this will need to be updated for nested attributes func (b *Block) AttributeByPath(path cty.Path) *Attribute { block := b - for _, step := range path { + for i, step := range path { switch step := step.(type) { case cty.GetAttrStep: if attr := block.Attributes[step.Name]; attr != nil { + // If the Attribute is defined with a NestedType and there's + // more to the path, descend into the NestedType + if attr.NestedType != nil && i < len(path)-1 { + return attr.NestedType.AttributeByPath(path[i+1:]) + } else if i < len(path)-1 { // There's more to the path, but not more to this Attribute. + return nil + } return attr } @@ -27,3 +33,23 @@ func (b *Block) AttributeByPath(path cty.Path) *Attribute { } return nil } + +// AttributeByPath recurses through a NestedType to look up the Attribute scheme +// which corresponds to the given cty.Path. A nil value is returned if the given +// path does not correspond to a specific attribute. +func (o *Object) AttributeByPath(path cty.Path) *Attribute { + for i, step := range path { + switch step := step.(type) { + case cty.GetAttrStep: + if attr := o.Attributes[step.Name]; attr != nil { + if attr.NestedType != nil && i < len(path)-1 { + return attr.NestedType.AttributeByPath(path[i+1:]) + } else if i < len(path)-1 { // There's more to the path, but not more to this Attribute. + return nil + } + return attr + } + } + } + return nil +} diff --git a/internal/configs/configschema/path_test.go b/internal/configs/configschema/path_test.go index c4f673bad..1ca7cb41a 100644 --- a/internal/configs/configschema/path_test.go +++ b/internal/configs/configschema/path_test.go @@ -11,6 +11,24 @@ func TestAttributeByPath(t *testing.T) { Attributes: map[string]*Attribute{ "a1": {Description: "a1"}, "a2": {Description: "a2"}, + "a3": { + Description: "a3", + NestedType: &Object{ + Nesting: NestingList, + Attributes: map[string]*Attribute{ + "nt1": {Description: "nt1"}, + "nt2": { + Description: "nt2", + NestedType: &Object{ + Nesting: NestingSingle, + Attributes: map[string]*Attribute{ + "deeply_nested": {Description: "deeply_nested"}, + }, + }, + }, + }, + }, + }, }, BlockTypes: map[string]*NestedBlock{ "b1": { @@ -66,6 +84,16 @@ func TestAttributeByPath(t *testing.T) { "a2", true, }, + { + cty.GetAttrPath("a3").IndexInt(1).GetAttr("nt2"), + "nt2", + true, + }, + { + cty.GetAttrPath("a3").IndexInt(1).GetAttr("b2").IndexString("foo").GetAttr("no"), + "missing", + false, + }, { cty.GetAttrPath("b1"), "block", @@ -119,3 +147,83 @@ func TestAttributeByPath(t *testing.T) { }) } } + +func TestObject_AttributeByPath(t *testing.T) { + obj := &Object{ + Nesting: NestingList, + Attributes: map[string]*Attribute{ + "a1": {Description: "a1"}, + "a2": { + Description: "a2", + NestedType: &Object{ + Nesting: NestingSingle, + Attributes: map[string]*Attribute{ + "n1": {Description: "n1"}, + "n2": { + Description: "n2", + NestedType: &Object{ + Attributes: map[string]*Attribute{ + "dn1": {Description: "dn1"}, + }, + }, + }, + }, + }, + }, + }, + } + + tests := []struct { + path cty.Path + attrDescription string + exists bool + }{ + { + cty.GetAttrPath("a2"), + "a2", + true, + }, + { + cty.GetAttrPath("a3"), + "missing", + false, + }, + { + cty.GetAttrPath("a2").IndexString("foo").GetAttr("n1"), + "n1", + true, + }, + { + cty.GetAttrPath("a2").IndexString("foo").GetAttr("n2").IndexInt(11).GetAttr("dn1"), + "dn1", + true, + }, + { + cty.GetAttrPath("a2").IndexString("foo").GetAttr("n2").IndexInt(11).GetAttr("dn1").IndexString("hello").GetAttr("nope"), + "missing_nested", + false, + }, + } + + for _, tc := range tests { + t.Run(tc.attrDescription, func(t *testing.T) { + attr := obj.AttributeByPath(tc.path) + if !tc.exists && attr == nil { + return + } + + if !tc.exists && attr != nil { + t.Fatalf("found Attribute, expected nil from path %#v\n", tc.path) + } + + if attr == nil { + t.Fatalf("missing attribute from path %#v\n", tc.path) + } + + if attr.Description != tc.attrDescription { + t.Fatalf("expected Attribute for %q, got %#v\n", tc.attrDescription, attr) + } + }) + } + +} From 2b3d6f992931d6fa5e834b90fb6bbcb279d66d62 Mon Sep 17 00:00:00 2001 From: Neeraj Kumar Date: Fri, 23 Jul 2021 08:13:39 +0530 Subject: [PATCH 100/107] Minor typo in apt.html.md As part of this PR, just wanted to have this typo fixed to have a better sense of the sentence. `apt-add-repository` usually automatically runs `apt update` as part of its work in order to fetch the new package indices, but if it does not, then you will need to do so manually before the packages will be available. Also, I wanted to rephrase the sentence as below(less wording and more clarity- let me know if this is okay and I can raise a new pull request): `apt-add-repository` usually automatically runs `apt update` as part of its work to fetch the new package indices, but if it does not, you will need to manually do so before the packages will be available. --- website/docs/cli/install/apt.html.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/cli/install/apt.html.md b/website/docs/cli/install/apt.html.md index d55effb48..3995b2cf4 100644 --- a/website/docs/cli/install/apt.html.md +++ b/website/docs/cli/install/apt.html.md @@ -52,7 +52,7 @@ The above command line uses the following sub-shell commands: `apt-add-repository` usually automatically runs `apt update` as part of its work in order to fetch the new package indices, but if it does not then you -will need to so manually before the packages will be available. +will need to do so manually before the packages will be available. To install Terraform from the new repository: From 21136cf2fe9f33ca87afd7eff5b71ff618e3b810 Mon Sep 17 00:00:00 2001 From: Neeraj Kumar Date: Sat, 24 Jul 2021 06:54:44 +0530 Subject: [PATCH 101/107] Conciseness and fixed some typos in apt.html.md As discussed with Laura, submitting this PR. --- website/docs/cli/install/apt.html.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/website/docs/cli/install/apt.html.md b/website/docs/cli/install/apt.html.md index 3995b2cf4..5fbbe1da1 100644 --- a/website/docs/cli/install/apt.html.md +++ b/website/docs/cli/install/apt.html.md @@ -21,7 +21,7 @@ might prefer to [install Terraform from our Yum repositories](yum.html). -> **Note:** The APT repositories discussed on this page are generic HashiCorp repositories that contain packages for a variety of different HashiCorp products, rather than just Terraform. Adding these repositories to your -system will, by default, therefore make a number of other non-Terraform +system will, by default, therefore make several other non-Terraform packages available for installation. That might then mask some packages that are available for some HashiCorp products in the main Debian and Ubuntu package repositories. @@ -50,9 +50,8 @@ The above command line uses the following sub-shell commands: * `lsb_release -cs` to find the distribution release codename for your current system, such as `buster`, `groovy`, or `sid`. -`apt-add-repository` usually automatically runs `apt update` as part of its -work in order to fetch the new package indices, but if it does not then you -will need to do so manually before the packages will be available. +`apt-add-repository` usually automatically runs `apt update` as part of its work to fetch the new package indices, +but if it does not, you will need to manually do so before the packages will be available. To install Terraform from the new repository: @@ -83,7 +82,7 @@ following distribution releases: * Ubuntu 20.04 (`focal`) * Ubuntu 20.10 (`groovy`) -No repositories are available for other Debian or Ubuntu versions or for +No repositories are available for other Debian or Ubuntu versions or any other APT-based Linux distributions. If you add the repository using the above commands on other systems then `apt update` will report the repository index as missing. @@ -116,7 +115,7 @@ apt policy terraform There may be multiple package releases for a particular Terraform version if we need to publish an updated package for any reason. In that case, the subsequent releases will have an additional suffix, like `0.13.4-2`. In these -cases the Terraform executable inside the package should be unchanged, but its +cases, the Terraform executable inside the package should be unchanged, but its metadata and other contents may be different. You can select a specific version to install by including it in the From 6b0be752bf94cd07450fb76a6254fdae09bed041 Mon Sep 17 00:00:00 2001 From: Neeraj Kumar Date: Sat, 24 Jul 2021 06:58:04 +0530 Subject: [PATCH 102/107] Updated line width --- website/docs/cli/install/apt.html.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/website/docs/cli/install/apt.html.md b/website/docs/cli/install/apt.html.md index 5fbbe1da1..5b88b9613 100644 --- a/website/docs/cli/install/apt.html.md +++ b/website/docs/cli/install/apt.html.md @@ -50,8 +50,9 @@ The above command line uses the following sub-shell commands: * `lsb_release -cs` to find the distribution release codename for your current system, such as `buster`, `groovy`, or `sid`. -`apt-add-repository` usually automatically runs `apt update` as part of its work to fetch the new package indices, -but if it does not, you will need to manually do so before the packages will be available. +`apt-add-repository` usually automatically runs `apt update` as part of its +work to fetch the new package indices, but if it does not, you will need to +manually do so before the packages will be available. To install Terraform from the new repository: From 59dd7f8f51f45eda18cc9cb04823b56fbdd93f2e Mon Sep 17 00:00:00 2001 From: Daniel Schmidt Date: Mon, 26 Jul 2021 09:41:51 +0200 Subject: [PATCH 103/107] terraform-workspace should be terraform.workspace Closes #28881 by @abidmunirmalik --- website/docs/language/expressions/references.html.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/language/expressions/references.html.md b/website/docs/language/expressions/references.html.md index b7db71398..8f874641c 100644 --- a/website/docs/language/expressions/references.html.md +++ b/website/docs/language/expressions/references.html.md @@ -152,7 +152,7 @@ or some other value if not: module "example" { # ... - name_prefix = "app-${terraform-workspace}" + name_prefix = "app-${terraform.workspace}" } ``` From a14272d02279406b28c1b671810cf30ae06b648e Mon Sep 17 00:00:00 2001 From: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> Date: Mon, 26 Jul 2021 14:52:44 -0400 Subject: [PATCH 104/107] Update extending link to "plugin development" --- website/docs/language/providers/index.html.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/language/providers/index.html.md b/website/docs/language/providers/index.html.md index 890889fab..fd95e66e5 100644 --- a/website/docs/language/providers/index.html.md +++ b/website/docs/language/providers/index.html.md @@ -1,7 +1,7 @@ --- layout: "language" page_title: "Providers - Configuration Language" -description: "An overview of how to install and use providers, Terraform plugins that interact with services, cloud providers, and other APIs." +description: "An overview of how to install and use providers, Terraform plugins that interact with services, cloud providers, and other APIs." --- # Providers @@ -136,6 +136,6 @@ develops and maintains a given provider. Providers are written in Go, using the Terraform Plugin SDK. For more information on developing providers, see: -- The [Extending Terraform](/docs/extend/index.html) documentation +- The [Plugin Development](/docs/extend/index.html) documentation - The [Call APIs with Terraform Providers](https://learn.hashicorp.com/collections/terraform/providers?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) collection on HashiCorp Learn From c449148d8cb195b27b4d3cf07745be163e2f8728 Mon Sep 17 00:00:00 2001 From: James Bardin Date: Tue, 27 Jul 2021 10:44:17 -0400 Subject: [PATCH 105/107] update GH issue template Change generic provider link to the registry, since the majority of providers are no longer under the terraform-provider org. Remove example link to an individual user's repo. --- .github/ISSUE_TEMPLATE/bug_report.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index d0b51b78e..c8ad02922 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -11,14 +11,14 @@ Hi there, Thank you for opening an issue. Please note that we try to keep the Terraform issue tracker reserved for bug reports and feature requests. For general usage questions, please see: https://www.terraform.io/community.html. If your issue relates to Terraform Cloud/Enterprise, please contact tf-cloud@hashicorp.support. -If your issue relates to a specific Terraform provider, please open it in the provider's own repository. The index of providers is at https://github.com/terraform-providers. +If your issue relates to a specific Terraform provider, please open it in the provider's own repository. The index of providers is at https://registry.terraform.io/browse/providers. To fix problems, we need clear reproduction cases - we need to be able to see it happen locally. A reproduction case is ideally something a Terraform Core engineer can git-clone or copy-paste and run immediately, without inventing any details or context. * A short example can be directly copy-pasteable; longer examples should be in separate git repositories, especially if multiple files are needed * Please include all needed context. For example, if you figured out that an expression can cause a crash, put the expression in a variable definition or a resource * Set defaults on (or omit) any variables. The person reproducing it should not need to invent variable settings -* If multiple steps are required, such as running terraform twice, consider scripting it in a simple shell script. For example, see [this case](https://github.com/danieldreier/terraform-issue-reproductions/tree/master/25719). Providing a script can be easier than explaining what changes to make to the config between runs. +* If multiple steps are required, such as running terraform twice, consider scripting it in a simple shell script. Providing a script can be easier than explaining what changes to make to the config between runs. * Omit any unneeded complexity: remove variables, conditional statements, functions, modules, providers, and resources that are not needed to trigger the bug * When possible, use the [null resource](https://www.terraform.io/docs/providers/null/resource.html) provider rather than a real provider in order to minimize external dependencies. We know this isn't always feasible. The Terraform Core team doesn't have deep domain knowledge in every provider, or access to every cloud platform for reproduction cases. From 4d733b4d2dc16cd5461905da06e00db95bb09698 Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Mon, 26 Jul 2021 16:05:05 -0700 Subject: [PATCH 106/107] addrs: Implement ModuleInstance.MoveDestination This method encapsulates the move-processing rules for applying move statements to ModuleInstance addresses. It honors both module call moves and module instance moves by trying to find a subsequence of the input that matches the "from" endpoint and then, if found, replacing it with the "to" endpoint while preserving the prefix and suffix around the match, if any. --- internal/addrs/move_endpoint_module.go | 85 +++++- internal/addrs/move_endpoint_module_test.go | 305 ++++++++++++++++++++ 2 files changed, 389 insertions(+), 1 deletion(-) create mode 100644 internal/addrs/move_endpoint_module_test.go diff --git a/internal/addrs/move_endpoint_module.go b/internal/addrs/move_endpoint_module.go index 0b6461bd9..2c7ad2276 100644 --- a/internal/addrs/move_endpoint_module.go +++ b/internal/addrs/move_endpoint_module.go @@ -157,7 +157,90 @@ func (e *MoveEndpointInModule) NestedWithin(other *MoveEndpointInModule) bool { // Both of the given endpoints must be from the same move statement and thus // must have matching object types. If not, MoveDestination will panic. func (m ModuleInstance) MoveDestination(fromMatch, toMatch *MoveEndpointInModule) (ModuleInstance, bool) { - return nil, false + // NOTE: This implementation assumes the invariant that fromMatch and + // toMatch both belong to the same configuration statement, and thus they + // will both have the same address type and the same declaration module. + + // The root module instance is not itself moveable. + if m.IsRoot() { + return nil, false + } + + // The two endpoints must either be module call or module instance + // addresses, or else this statement can never match. + if fromMatch.ObjectKind() != MoveEndpointModule { + return nil, false + } + + // The given module instance must have a prefix that matches the + // declaration module of the two endpoints. + if len(fromMatch.module) > len(m) { + return nil, false // too short to possibly match + } + for i := range fromMatch.module { + if fromMatch.module[i] != m[i].Name { + return nil, false // this step doesn't match + } + } + + // The rest of our work will be against the part of the reciever that's + // relative to the declaration module. mRel is a weird abuse of + // ModuleInstance that represents a relative module address, similar to + // what we do for MoveEndpointInModule.relSubject. + mPrefix, mRel := m[:len(fromMatch.module)], m[len(fromMatch.module):] + + // Our next goal is to split mRel into two parts: the match (if any) and + // the suffix. Our result will then replace the match with the replacement + // in toMatch while preserving the prefix and suffix. + var mSuffix, mNewMatch ModuleInstance + + switch relSubject := fromMatch.relSubject.(type) { + case ModuleInstance: + if len(relSubject) > len(mRel) { + return nil, false // too short to possibly match + } + for i := range relSubject { + if relSubject[i] != mRel[i] { + return nil, false // this step doesn't match + } + } + // If we get to here then we've found a match. Since the statement + // addresses are already themselves ModuleInstance fragments we can + // just slice out the relevant parts. + mNewMatch = toMatch.relSubject.(ModuleInstance) + mSuffix = mRel[len(relSubject):] + case AbsModuleCall: + // The module instance part of relSubject must be a prefix of + // mRel, and mRel must be at least one step longer to account for + // the call step itself. + if len(relSubject.Module) > len(mRel)-1 { + return nil, false + } + for i := range relSubject.Module { + if relSubject.Module[i] != mRel[i] { + return nil, false // this step doesn't match + } + } + // The call name must also match the next step of mRel, after + // the relSubject.Module prefix. + callStep := mRel[len(relSubject.Module)] + if callStep.Name != relSubject.Call.Name { + return nil, false + } + // If we get to here then we've found a match. We need to construct + // a new mNewMatch that's an instance of the "new" relSubject with + // the same key as our call. + mNewMatch = toMatch.relSubject.(AbsModuleCall).Instance(callStep.InstanceKey) + mSuffix = mRel[len(relSubject.Module)+1:] + default: + panic("invalid address type for module-kind move endpoint") + } + + ret := make(ModuleInstance, 0, len(mPrefix)+len(mNewMatch)+len(mSuffix)) + ret = append(ret, mPrefix...) + ret = append(ret, mNewMatch...) + ret = append(ret, mSuffix...) + return ret, true } // MoveDestination considers a an address representing a resource diff --git a/internal/addrs/move_endpoint_module_test.go b/internal/addrs/move_endpoint_module_test.go new file mode 100644 index 000000000..981c50ee5 --- /dev/null +++ b/internal/addrs/move_endpoint_module_test.go @@ -0,0 +1,305 @@ +package addrs + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/hcl/v2" + "github.com/hashicorp/hcl/v2/hclsyntax" + "github.com/hashicorp/terraform/internal/tfdiags" +) + +func TestModuleInstanceMoveDestination(t *testing.T) { + tests := []struct { + DeclModule string + StmtFrom, StmtTo string + Reciever string + WantMatch bool + WantResult string + }{ + { + ``, + `module.foo`, + `module.bar`, + `module.foo`, + true, + `module.bar`, + }, + { + ``, + `module.foo`, + `module.bar`, + `module.foo[1]`, + true, + `module.bar[1]`, + }, + { + ``, + `module.foo`, + `module.bar`, + `module.foo["a"]`, + true, + `module.bar["a"]`, + }, + { + ``, + `module.foo`, + `module.bar.module.foo`, + `module.foo`, + true, + `module.bar.module.foo`, + }, + { + ``, + `module.foo.module.bar`, + `module.bar`, + `module.foo.module.bar`, + true, + `module.bar`, + }, + { + ``, + `module.foo[1]`, + `module.foo[2]`, + `module.foo[1]`, + true, + `module.foo[2]`, + }, + { + ``, + `module.foo[1]`, + `module.foo`, + `module.foo[1]`, + true, + `module.foo`, + }, + { + ``, + `module.foo`, + `module.foo[1]`, + `module.foo`, + true, + `module.foo[1]`, + }, + { + ``, + `module.foo`, + `module.foo[1]`, + `module.foo.module.bar`, + true, + `module.foo[1].module.bar`, + }, + { + ``, + `module.foo`, + `module.foo[1]`, + `module.foo.module.bar[0]`, + true, + `module.foo[1].module.bar[0]`, + }, + { + ``, + `module.foo`, + `module.bar.module.foo`, + `module.foo[0]`, + true, + `module.bar.module.foo[0]`, + }, + { + ``, + `module.foo.module.bar`, + `module.bar`, + `module.foo.module.bar[0]`, + true, + `module.bar[0]`, + }, + { + `foo`, + `module.bar`, + `module.baz`, + `module.foo.module.bar`, + true, + `module.foo.module.baz`, + }, + { + `foo`, + `module.bar`, + `module.baz`, + `module.foo[1].module.bar`, + true, + `module.foo[1].module.baz`, + }, + { + `foo`, + `module.bar`, + `module.bar[1]`, + `module.foo[1].module.bar`, + true, + `module.foo[1].module.bar[1]`, + }, + { + ``, + `module.foo[1]`, + `module.foo[2]`, + `module.foo`, + false, // the receiver has a non-matching instance key (NoKey) + ``, + }, + { + ``, + `module.foo[1]`, + `module.foo[2]`, + `module.foo[2]`, + false, // the receiver is already the "to" address + ``, + }, + { + ``, + `module.foo`, + `module.bar`, + ``, + false, // the root module can never be moved + ``, + }, + { + `foo`, + `module.bar`, + `module.bar[1]`, + `module.boz`, + false, // the receiver is outside the declaration module + ``, + }, + { + `foo.bar`, + `module.bar`, + `module.bar[1]`, + `module.boz`, + false, // the receiver is outside the declaration module + ``, + }, + { + `foo.bar`, + `module.a`, + `module.b`, + `module.boz`, + false, // the receiver is outside the declaration module + ``, + }, + { + ``, + `module.a1.module.a2`, + `module.b1.module.b2`, + `module.c`, + false, // the receiver is outside the declaration module + ``, + }, + { + ``, + `module.a1.module.a2[0]`, + `module.b1.module.b2[1]`, + `module.c`, + false, // the receiver is outside the declaration module + ``, + }, + { + ``, + `module.a1.module.a2`, + `module.b1.module.b2`, + `module.a1.module.b2`, + false, // the receiver is outside the declaration module + ``, + }, + { + ``, + `module.a1.module.a2`, + `module.b1.module.b2`, + `module.b1.module.a2`, + false, // the receiver is outside the declaration module + ``, + }, + { + ``, + `module.a1.module.a2[0]`, + `module.b1.module.b2[1]`, + `module.a1.module.b2[0]`, + false, // the receiver is outside the declaration module + ``, + }, + { + ``, + `foo_instance.bar`, + `foo_instance.baz`, + `module.foo`, + false, // a resource address can never match a module instance + ``, + }, + } + + for _, test := range tests { + t.Run( + fmt.Sprintf( + "%s: %s to %s with %s", + test.DeclModule, + test.StmtFrom, test.StmtTo, + test.Reciever, + ), + func(t *testing.T) { + + parseStmtEP := func(t *testing.T, input string) *MoveEndpoint { + t.Helper() + + traversal, hclDiags := hclsyntax.ParseTraversalAbs([]byte(input), "", hcl.InitialPos) + if hclDiags.HasErrors() { + // We're not trying to test the HCL parser here, so any + // failures at this point are likely to be bugs in the + // test case itself. + t.Fatalf("syntax error: %s", hclDiags.Error()) + } + + moveEp, diags := ParseMoveEndpoint(traversal) + if diags.HasErrors() { + t.Fatalf("unexpected error: %s", diags.Err().Error()) + } + return moveEp + } + + fromEPLocal := parseStmtEP(t, test.StmtFrom) + toEPLocal := parseStmtEP(t, test.StmtTo) + + declModule := RootModule + if test.DeclModule != "" { + declModule = strings.Split(test.DeclModule, ".") + } + fromEP, toEP := UnifyMoveEndpoints(declModule, fromEPLocal, toEPLocal) + if fromEP == nil || toEP == nil { + t.Fatalf("invalid test case: non-unifyable endpoints\nfrom: %s\nto: %s", fromEPLocal, toEPLocal) + } + + receiverAddr := RootModuleInstance + if test.Reciever != "" { + var diags tfdiags.Diagnostics + receiverAddr, diags = ParseModuleInstanceStr(test.Reciever) + if diags.HasErrors() { + t.Fatalf("invalid reciever address: %s", diags.Err().Error()) + } + } + gotAddr, gotMatch := receiverAddr.MoveDestination(fromEP, toEP) + if !test.WantMatch { + if gotMatch { + t.Errorf("unexpected match\nreciever: %s\nfrom: %s\nto: %s\nresult: %s", test.Reciever, fromEP, toEP, gotAddr) + } + return + } + + if !gotMatch { + t.Errorf("unexpected non-match\nreciever: %s\nfrom: %s\nto: %s", test.Reciever, fromEP, toEP) + } + + if gotStr, wantStr := gotAddr.String(), test.WantResult; gotStr != wantStr { + t.Errorf("wrong result\ngot: %s\nwant: %s", gotStr, wantStr) + } + }, + ) + } +} From 994ee23c06e21932cf9339c04d9ae3fabda0d26e Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Mon, 26 Jul 2021 17:33:19 -0700 Subject: [PATCH 107/107] addrs: Module move support for AbsResource and AbsResourceInstance This is a subset of the MoveDestination behavior for AbsResource and AbsResourceInstance which deals with source and destination addresses that refer to module calls or module instances. They both work by delegating to ModuleInstance.MoveDestination and then applying the same resource or resource instance address to the newly-chosen module instance address, thus ensuring that when we move a module we also move all of the resources inside that module in the same way. This doesn't yet include support for moving between specific resource or resource instance addresses; that'll follow later. This commit should have enough logic to support moving between module names and module instance keys, including any module calls or resources nested within. --- internal/addrs/move_endpoint_module.go | 49 +- internal/addrs/move_endpoint_module_test.go | 572 ++++++++++++++++++++ 2 files changed, 619 insertions(+), 2 deletions(-) diff --git a/internal/addrs/move_endpoint_module.go b/internal/addrs/move_endpoint_module.go index 2c7ad2276..f1de3b861 100644 --- a/internal/addrs/move_endpoint_module.go +++ b/internal/addrs/move_endpoint_module.go @@ -255,7 +255,24 @@ func (m ModuleInstance) MoveDestination(fromMatch, toMatch *MoveEndpointInModule // Both of the given endpoints must be from the same move statement and thus // must have matching object types. If not, MoveDestination will panic. func (r AbsResource) MoveDestination(fromMatch, toMatch *MoveEndpointInModule) (AbsResource, bool) { - return AbsResource{}, false + switch fromMatch.ObjectKind() { + case MoveEndpointModule: + // If we've moving a module then any resource inside that module + // moves too. + fromMod := r.Module + toMod, match := fromMod.MoveDestination(fromMatch, toMatch) + if !match { + return AbsResource{}, false + } + return r.Resource.Absolute(toMod), true + + case MoveEndpointResource: + // TODO: Implement + return AbsResource{}, false + + default: + panic("unexpected object kind") + } } // MoveDestination considers a an address representing a resource @@ -270,5 +287,33 @@ func (r AbsResource) MoveDestination(fromMatch, toMatch *MoveEndpointInModule) ( // Both of the given endpoints must be from the same move statement and thus // must have matching object types. If not, MoveDestination will panic. func (r AbsResourceInstance) MoveDestination(fromMatch, toMatch *MoveEndpointInModule) (AbsResourceInstance, bool) { - return AbsResourceInstance{}, false + switch fromMatch.ObjectKind() { + case MoveEndpointModule: + // If we've moving a module then any resource inside that module + // moves too. + fromMod := r.Module + toMod, match := fromMod.MoveDestination(fromMatch, toMatch) + if !match { + return AbsResourceInstance{}, false + } + return r.Resource.Absolute(toMod), true + + case MoveEndpointResource: + switch fromMatch.relSubject.(type) { + case AbsResource: + oldResource := r.ContainingResource() + newResource, match := oldResource.MoveDestination(fromMatch, toMatch) + if !match { + return AbsResourceInstance{}, false + } + return newResource.Instance(r.Resource.Key), true + case AbsResourceInstance: + // TODO: Implement + return AbsResourceInstance{}, false + default: + panic("invalid address type for resource-kind move endpoint") + } + default: + panic("unexpected object kind") + } } diff --git a/internal/addrs/move_endpoint_module_test.go b/internal/addrs/move_endpoint_module_test.go index 981c50ee5..60f804436 100644 --- a/internal/addrs/move_endpoint_module_test.go +++ b/internal/addrs/move_endpoint_module_test.go @@ -303,3 +303,575 @@ func TestModuleInstanceMoveDestination(t *testing.T) { ) } } + +func TestAbsResourceInstanceMoveDestination(t *testing.T) { + tests := []struct { + DeclModule string + StmtFrom, StmtTo string + Reciever string + WantMatch bool + WantResult string + }{ + { + ``, + `module.foo`, + `module.bar`, + `module.foo.test_object.beep`, + true, + `module.bar.test_object.beep`, + }, + { + ``, + `module.foo`, + `module.bar`, + `module.foo[1].test_object.beep`, + true, + `module.bar[1].test_object.beep`, + }, + { + ``, + `module.foo`, + `module.bar`, + `module.foo["a"].test_object.beep`, + true, + `module.bar["a"].test_object.beep`, + }, + { + ``, + `module.foo`, + `module.bar.module.foo`, + `module.foo.test_object.beep`, + true, + `module.bar.module.foo.test_object.beep`, + }, + { + ``, + `module.foo.module.bar`, + `module.bar`, + `module.foo.module.bar.test_object.beep`, + true, + `module.bar.test_object.beep`, + }, + { + ``, + `module.foo[1]`, + `module.foo[2]`, + `module.foo[1].test_object.beep`, + true, + `module.foo[2].test_object.beep`, + }, + { + ``, + `module.foo[1]`, + `module.foo`, + `module.foo[1].test_object.beep`, + true, + `module.foo.test_object.beep`, + }, + { + ``, + `module.foo`, + `module.foo[1]`, + `module.foo.test_object.beep`, + true, + `module.foo[1].test_object.beep`, + }, + { + ``, + `module.foo`, + `module.foo[1]`, + `module.foo.module.bar.test_object.beep`, + true, + `module.foo[1].module.bar.test_object.beep`, + }, + { + ``, + `module.foo`, + `module.foo[1]`, + `module.foo.module.bar[0].test_object.beep`, + true, + `module.foo[1].module.bar[0].test_object.beep`, + }, + { + ``, + `module.foo`, + `module.bar.module.foo`, + `module.foo[0].test_object.beep`, + true, + `module.bar.module.foo[0].test_object.beep`, + }, + { + ``, + `module.foo.module.bar`, + `module.bar`, + `module.foo.module.bar[0].test_object.beep`, + true, + `module.bar[0].test_object.beep`, + }, + { + `foo`, + `module.bar`, + `module.baz`, + `module.foo.module.bar.test_object.beep`, + true, + `module.foo.module.baz.test_object.beep`, + }, + { + `foo`, + `module.bar`, + `module.baz`, + `module.foo[1].module.bar.test_object.beep`, + true, + `module.foo[1].module.baz.test_object.beep`, + }, + { + `foo`, + `module.bar`, + `module.bar[1]`, + `module.foo[1].module.bar.test_object.beep`, + true, + `module.foo[1].module.bar[1].test_object.beep`, + }, + { + ``, + `module.foo[1]`, + `module.foo[2]`, + `module.foo.test_object.beep`, + false, // the receiver module has a non-matching instance key (NoKey) + ``, + }, + { + ``, + `module.foo[1]`, + `module.foo[2]`, + `module.foo[2].test_object.beep`, + false, // the receiver is already at the "to" address + ``, + }, + { + `foo`, + `module.bar`, + `module.bar[1]`, + `module.boz.test_object.beep`, + false, // the receiver module is outside the declaration module + ``, + }, + { + `foo.bar`, + `module.bar`, + `module.bar[1]`, + `module.boz.test_object.beep`, + false, // the receiver module is outside the declaration module + ``, + }, + { + `foo.bar`, + `module.a`, + `module.b`, + `module.boz.test_object.beep`, + false, // the receiver module is outside the declaration module + ``, + }, + { + ``, + `module.a1.module.a2`, + `module.b1.module.b2`, + `module.c.test_object.beep`, + false, // the receiver module is outside the declaration module + ``, + }, + { + ``, + `module.a1.module.a2[0]`, + `module.b1.module.b2[1]`, + `module.c.test_object.beep`, + false, // the receiver module is outside the declaration module + ``, + }, + { + ``, + `module.a1.module.a2`, + `module.b1.module.b2`, + `module.a1.module.b2.test_object.beep`, + false, // the receiver module is outside the declaration module + ``, + }, + { + ``, + `module.a1.module.a2`, + `module.b1.module.b2`, + `module.b1.module.a2.test_object.beep`, + false, // the receiver module is outside the declaration module + ``, + }, + { + ``, + `module.a1.module.a2[0]`, + `module.b1.module.b2[1]`, + `module.a1.module.b2[0].test_object.beep`, + false, // the receiver module is outside the declaration module + ``, + }, + { + ``, + `foo_instance.bar`, + `foo_instance.baz`, + `module.foo.test_object.beep`, + false, // the resource address is unrelated to the move statements + ``, + }, + } + + for _, test := range tests { + t.Run( + fmt.Sprintf( + "%s: %s to %s with %s", + test.DeclModule, + test.StmtFrom, test.StmtTo, + test.Reciever, + ), + func(t *testing.T) { + + parseStmtEP := func(t *testing.T, input string) *MoveEndpoint { + t.Helper() + + traversal, hclDiags := hclsyntax.ParseTraversalAbs([]byte(input), "", hcl.InitialPos) + if hclDiags.HasErrors() { + // We're not trying to test the HCL parser here, so any + // failures at this point are likely to be bugs in the + // test case itself. + t.Fatalf("syntax error: %s", hclDiags.Error()) + } + + moveEp, diags := ParseMoveEndpoint(traversal) + if diags.HasErrors() { + t.Fatalf("unexpected error: %s", diags.Err().Error()) + } + return moveEp + } + + fromEPLocal := parseStmtEP(t, test.StmtFrom) + toEPLocal := parseStmtEP(t, test.StmtTo) + + declModule := RootModule + if test.DeclModule != "" { + declModule = strings.Split(test.DeclModule, ".") + } + fromEP, toEP := UnifyMoveEndpoints(declModule, fromEPLocal, toEPLocal) + if fromEP == nil || toEP == nil { + t.Fatalf("invalid test case: non-unifyable endpoints\nfrom: %s\nto: %s", fromEPLocal, toEPLocal) + } + + receiverAddr, diags := ParseAbsResourceInstanceStr(test.Reciever) + if diags.HasErrors() { + t.Fatalf("invalid reciever address: %s", diags.Err().Error()) + } + gotAddr, gotMatch := receiverAddr.MoveDestination(fromEP, toEP) + if !test.WantMatch { + if gotMatch { + t.Errorf("unexpected match\nreciever: %s\nfrom: %s\nto: %s\nresult: %s", test.Reciever, fromEP, toEP, gotAddr) + } + return + } + + if !gotMatch { + t.Errorf("unexpected non-match\nreciever: %s\nfrom: %s\nto: %s", test.Reciever, fromEP, toEP) + } + + if gotStr, wantStr := gotAddr.String(), test.WantResult; gotStr != wantStr { + t.Errorf("wrong result\ngot: %s\nwant: %s", gotStr, wantStr) + } + }, + ) + } +} + +func TestAbsResourceMoveDestination(t *testing.T) { + tests := []struct { + DeclModule string + StmtFrom, StmtTo string + Reciever string + WantMatch bool + WantResult string + }{ + { + ``, + `module.foo`, + `module.bar`, + `module.foo.test_object.beep`, + true, + `module.bar.test_object.beep`, + }, + { + ``, + `module.foo`, + `module.bar`, + `module.foo[1].test_object.beep`, + true, + `module.bar[1].test_object.beep`, + }, + { + ``, + `module.foo`, + `module.bar`, + `module.foo["a"].test_object.beep`, + true, + `module.bar["a"].test_object.beep`, + }, + { + ``, + `module.foo`, + `module.bar.module.foo`, + `module.foo.test_object.beep`, + true, + `module.bar.module.foo.test_object.beep`, + }, + { + ``, + `module.foo.module.bar`, + `module.bar`, + `module.foo.module.bar.test_object.beep`, + true, + `module.bar.test_object.beep`, + }, + { + ``, + `module.foo[1]`, + `module.foo[2]`, + `module.foo[1].test_object.beep`, + true, + `module.foo[2].test_object.beep`, + }, + { + ``, + `module.foo[1]`, + `module.foo`, + `module.foo[1].test_object.beep`, + true, + `module.foo.test_object.beep`, + }, + { + ``, + `module.foo`, + `module.foo[1]`, + `module.foo.test_object.beep`, + true, + `module.foo[1].test_object.beep`, + }, + { + ``, + `module.foo`, + `module.foo[1]`, + `module.foo.module.bar.test_object.beep`, + true, + `module.foo[1].module.bar.test_object.beep`, + }, + { + ``, + `module.foo`, + `module.foo[1]`, + `module.foo.module.bar[0].test_object.beep`, + true, + `module.foo[1].module.bar[0].test_object.beep`, + }, + { + ``, + `module.foo`, + `module.bar.module.foo`, + `module.foo[0].test_object.beep`, + true, + `module.bar.module.foo[0].test_object.beep`, + }, + { + ``, + `module.foo.module.bar`, + `module.bar`, + `module.foo.module.bar[0].test_object.beep`, + true, + `module.bar[0].test_object.beep`, + }, + { + `foo`, + `module.bar`, + `module.baz`, + `module.foo.module.bar.test_object.beep`, + true, + `module.foo.module.baz.test_object.beep`, + }, + { + `foo`, + `module.bar`, + `module.baz`, + `module.foo[1].module.bar.test_object.beep`, + true, + `module.foo[1].module.baz.test_object.beep`, + }, + { + `foo`, + `module.bar`, + `module.bar[1]`, + `module.foo[1].module.bar.test_object.beep`, + true, + `module.foo[1].module.bar[1].test_object.beep`, + }, + { + ``, + `module.foo[1]`, + `module.foo[2]`, + `module.foo.test_object.beep`, + false, // the receiver module has a non-matching instance key (NoKey) + ``, + }, + { + ``, + `module.foo[1]`, + `module.foo[2]`, + `module.foo[2].test_object.beep`, + false, // the receiver is already at the "to" address + ``, + }, + { + `foo`, + `module.bar`, + `module.bar[1]`, + `module.boz.test_object.beep`, + false, // the receiver module is outside the declaration module + ``, + }, + { + `foo.bar`, + `module.bar`, + `module.bar[1]`, + `module.boz.test_object.beep`, + false, // the receiver module is outside the declaration module + ``, + }, + { + `foo.bar`, + `module.a`, + `module.b`, + `module.boz.test_object.beep`, + false, // the receiver module is outside the declaration module + ``, + }, + { + ``, + `module.a1.module.a2`, + `module.b1.module.b2`, + `module.c.test_object.beep`, + false, // the receiver module is outside the declaration module + ``, + }, + { + ``, + `module.a1.module.a2[0]`, + `module.b1.module.b2[1]`, + `module.c.test_object.beep`, + false, // the receiver module is outside the declaration module + ``, + }, + { + ``, + `module.a1.module.a2`, + `module.b1.module.b2`, + `module.a1.module.b2.test_object.beep`, + false, // the receiver module is outside the declaration module + ``, + }, + { + ``, + `module.a1.module.a2`, + `module.b1.module.b2`, + `module.b1.module.a2.test_object.beep`, + false, // the receiver module is outside the declaration module + ``, + }, + { + ``, + `module.a1.module.a2[0]`, + `module.b1.module.b2[1]`, + `module.a1.module.b2[0].test_object.beep`, + false, // the receiver module is outside the declaration module + ``, + }, + { + ``, + `foo_instance.bar`, + `foo_instance.baz`, + `module.foo.test_object.beep`, + false, // the resource address is unrelated to the move statements + ``, + }, + } + + for _, test := range tests { + t.Run( + fmt.Sprintf( + "%s: %s to %s with %s", + test.DeclModule, + test.StmtFrom, test.StmtTo, + test.Reciever, + ), + func(t *testing.T) { + + parseStmtEP := func(t *testing.T, input string) *MoveEndpoint { + t.Helper() + + traversal, hclDiags := hclsyntax.ParseTraversalAbs([]byte(input), "", hcl.InitialPos) + if hclDiags.HasErrors() { + // We're not trying to test the HCL parser here, so any + // failures at this point are likely to be bugs in the + // test case itself. + t.Fatalf("syntax error: %s", hclDiags.Error()) + } + + moveEp, diags := ParseMoveEndpoint(traversal) + if diags.HasErrors() { + t.Fatalf("unexpected error: %s", diags.Err().Error()) + } + return moveEp + } + + fromEPLocal := parseStmtEP(t, test.StmtFrom) + toEPLocal := parseStmtEP(t, test.StmtTo) + + declModule := RootModule + if test.DeclModule != "" { + declModule = strings.Split(test.DeclModule, ".") + } + fromEP, toEP := UnifyMoveEndpoints(declModule, fromEPLocal, toEPLocal) + if fromEP == nil || toEP == nil { + t.Fatalf("invalid test case: non-unifyable endpoints\nfrom: %s\nto: %s", fromEPLocal, toEPLocal) + } + + // We only have an AbsResourceInstance parser, not an + // AbsResourceParser, and so we'll just cheat and parse this + // as a resource instance but fail if it includes an instance + // key. + receiverInstanceAddr, diags := ParseAbsResourceInstanceStr(test.Reciever) + if diags.HasErrors() { + t.Fatalf("invalid reciever address: %s", diags.Err().Error()) + } + if receiverInstanceAddr.Resource.Key != NoKey { + t.Fatalf("invalid reciever address: must be a resource, not a resource instance") + } + receiverAddr := receiverInstanceAddr.ContainingResource() + gotAddr, gotMatch := receiverAddr.MoveDestination(fromEP, toEP) + if !test.WantMatch { + if gotMatch { + t.Errorf("unexpected match\nreciever: %s\nfrom: %s\nto: %s\nresult: %s", test.Reciever, fromEP, toEP, gotAddr) + } + return + } + + if !gotMatch { + t.Errorf("unexpected non-match\nreciever: %s\nfrom: %s\nto: %s", test.Reciever, fromEP, toEP) + } + + if gotStr, wantStr := gotAddr.String(), test.WantResult; gotStr != wantStr { + t.Errorf("wrong result\ngot: %s\nwant: %s", gotStr, wantStr) + } + }, + ) + } +}