Skip to content

Commit

Permalink
Merge branch 'main' into b/fix-retry-messages-in-cloud-backend-json
Browse files Browse the repository at this point in the history
  • Loading branch information
bschaatsbergen authored Nov 5, 2024
2 parents ad1f3e0 + f0b00c4 commit 558aa18
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 47 deletions.
25 changes: 3 additions & 22 deletions internal/command/views/hook_json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ func TestJSONHook_EphemeralOp_progress(t *testing.T) {
action, err := hook.PreEphemeralOp(testJSONHookResourceID(addr), plans.Open)
testHookReturnValues(t, action, err)

time.Sleep(3100 * time.Millisecond)
time.Sleep(2005 * time.Millisecond)

action, err = hook.PostEphemeralOp(testJSONHookResourceID(addr), plans.Open, nil)
testHookReturnValues(t, action, err)
Expand Down Expand Up @@ -478,31 +478,12 @@ func TestJSONHook_EphemeralOp_progress(t *testing.T) {
},
{
"@level": "info",
"@message": "test_instance.boop: Still opening... [3s elapsed]",
"@module": "terraform.ui",
"type": "ephemeral_op_progress",
"hook": map[string]interface{}{
"action": string("open"),
"elapsed_seconds": float64(3),
"resource": map[string]interface{}{
"addr": string("test_instance.boop"),
"implied_provider": string("test"),
"module": string(""),
"resource": string("test_instance.boop"),
"resource_key": nil,
"resource_name": string("boop"),
"resource_type": string("test_instance"),
},
},
},
{
"@level": "info",
"@message": "test_instance.boop: Opening complete after 3s",
"@message": "test_instance.boop: Opening complete after 2s",
"@module": "terraform.ui",
"type": "ephemeral_op_complete",
"hook": map[string]interface{}{
"action": string("open"),
"elapsed_seconds": float64(3),
"elapsed_seconds": float64(2),
"resource": map[string]interface{}{
"addr": string("test_instance.boop"),
"implied_provider": string("test"),
Expand Down
11 changes: 10 additions & 1 deletion internal/lang/checks.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"strings"

"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/terraform/internal/addrs"
"github.com/hashicorp/terraform/internal/lang/marks"
"github.com/hashicorp/terraform/internal/tfdiags"
"github.com/zclconf/go-cty/cty"
Expand All @@ -21,7 +22,7 @@ import (
// It will either return a non-empty message string or it'll return diagnostics
// with either errors or warnings that explain why the given expression isn't
// acceptable.
func EvalCheckErrorMessage(expr hcl.Expression, hclCtx *hcl.EvalContext) (string, tfdiags.Diagnostics) {
func EvalCheckErrorMessage(expr hcl.Expression, hclCtx *hcl.EvalContext, ruleAddr *addrs.CheckRule) (string, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics

val, hclDiags := expr.Value(hclCtx)
Expand Down Expand Up @@ -73,13 +74,21 @@ You can correct this by removing references to sensitive values, or by carefully
}

if _, ephemeral := valMarks[marks.Ephemeral]; ephemeral {
var extra interface{}
if ruleAddr != nil {
extra = &addrs.CheckRuleDiagnosticExtra{
CheckRule: *ruleAddr,
}
}

diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagWarning,
Summary: "Error message refers to ephemeral values",
Detail: `The error expression used to explain this condition refers to ephemeral values, so Terraform will not display the resulting message.
You can correct this by removing references to ephemeral values, or by using the ephemeralasnull() function on the references to not reveal ephemeral data.`,
Subject: expr.Range().Ptr(),
Extra: extra,
})
return "", diags
}
Expand Down
2 changes: 1 addition & 1 deletion internal/moduletest/eval_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ func (ec *EvalContext) Evaluate() (Status, cty.Value, tfdiags.Diagnostics) {
continue
}

errorMessage, moreDiags := lang.EvalCheckErrorMessage(rule.ErrorMessage, hclCtx)
errorMessage, moreDiags := lang.EvalCheckErrorMessage(rule.ErrorMessage, hclCtx, nil)
ruleDiags = ruleDiags.Append(moreDiags)

runVal, hclDiags := rule.Condition.Value(hclCtx)
Expand Down
57 changes: 50 additions & 7 deletions internal/terraform/context_plan_ephemeral_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"fmt"
"testing"

"github.com/google/go-cmp/cmp"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/terraform/internal/addrs"
"github.com/hashicorp/terraform/internal/configs"
Expand Down Expand Up @@ -332,15 +333,18 @@ module "child" {
},

"check blocks": {
toBeImplemented: true,
module: map[string]string{
"main.tf": `
ephemeral "ephem_resource" "data" {}
check "check_using_ephemeral_value" {
assert {
condition = ephemeral.ephem_resource.data.bool
error_message = "This should not fail"
condition = ephemeral.ephem_resource.data.bool == false
error_message = "Fine to persist"
}
assert {
condition = ephemeral.ephem_resource.data.bool == false
error_message = "Shall not be persisted ${ephemeral.ephem_resource.data.bool}"
}
}
`,
Expand All @@ -350,10 +354,49 @@ check "check_using_ephemeral_value" {
expectCloseEphemeralResourceCalled: true,

assertPlan: func(t *testing.T, p *plans.Plan) {
// Checks using ephemeral values should not be included in the plan
if p.Checks.ConfigResults.Len() > 0 {
t.Fatalf("Expected no checks to be included in the plan, but got %d", p.Checks.ConfigResults.Len())
key := addrs.ConfigCheck{
Module: addrs.RootModule,
Check: addrs.Check{
Name: "check_using_ephemeral_value",
},
}
result, ok := p.Checks.ConfigResults.GetOk(key)
if !ok {
t.Fatalf("expected to find check result for %q", key)
}
objKey := addrs.AbsCheck{
Module: addrs.RootModuleInstance,
Check: addrs.Check{
Name: "check_using_ephemeral_value",
},
}
obj, ok := result.ObjectResults.GetOk(objKey)
if !ok {
t.Fatalf("expected to find object for %q", objKey)
}
expectedMessages := []string{"Fine to persist"}
if diff := cmp.Diff(expectedMessages, obj.FailureMessages); diff != "" {
t.Fatalf("unexpected messages: %s", diff)
}
},
expectPlanDiagnostics: func(m *configs.Config) (diags tfdiags.Diagnostics) {
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagWarning,
Summary: "Check block assertion failed",
Detail: "Fine to persist",
})
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagWarning,
Summary: "Check block assertion failed",
Detail: "This check failed, but has an invalid error message as described in the other accompanying messages.",
})
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagWarning,
Summary: "Error message refers to ephemeral values",
Detail: "The error expression used to explain this condition refers to ephemeral values, so Terraform will not display the resulting message." +
"\n\nYou can correct this by removing references to ephemeral values, or by using the ephemeralasnull() function on the references to not reveal ephemeral data.",
})
return diags
},
},

Expand Down Expand Up @@ -510,7 +553,7 @@ ephemeral "ephem_resource" "data" {
},
},
Functions: map[string]providers.FunctionDecl{
"either": providers.FunctionDecl{
"either": {
Parameters: []providers.FunctionParam{
{
Name: "a",
Expand Down
2 changes: 1 addition & 1 deletion internal/terraform/eval_conditions.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ func validateCheckRule(addr addrs.CheckRule, rule *configs.CheckRule, ctx EvalCo
hclCtx, moreDiags := scope.EvalContext(refs)
diags = diags.Append(moreDiags)

errorMessage, moreDiags := lang.EvalCheckErrorMessage(rule.ErrorMessage, hclCtx)
errorMessage, moreDiags := lang.EvalCheckErrorMessage(rule.ErrorMessage, hclCtx, &addr)
diags = diags.Append(moreDiags)

return errorMessage, hclCtx, diags
Expand Down
19 changes: 12 additions & 7 deletions website/docs/cli/cloud/settings.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ Add a `cloud` block to your Terraform configuration and configure the connection
Specify the following settings in the `cloud` block:

- `organization`: Specifies the name of an HCP Terraform organization to connect to.
- `workspaces.tags`: Specifies a list of single-value string tags. Terraform links the working directory to existing workspaces in the organization that have matching tags. If there are no existing workspaces with matching tags, the Terraform CLI prompts you to create a new workspace that inherits the tags you specify in this field when you initialize the configuration.
- `workspaces.tags`: Specifies either a map of tag strings or a list of key-only string tags (legacy style). Terraform links the working directory to existing workspaces in the organization that have matching tags. If there are no existing workspaces with matching tags, the Terraform CLI prompts you to create a new workspace that applies the tags you specify in this field when you initialize the configuration.
- `workspaces.name`: You can specify the name of an existing workspace to associate with the Terraform configuration instead of using tags. If you configure the `name`, you cannot use the `tags` configuration.
- `workspaces.project`: You can specify the name of an existing project. Terraform associates the configuration with workspaces in the project that match the `name` or `tags`.
- `workspaces.project`: You can specify the name of an existing project. Terraform associates the configuration with workspaces in the project that match the `name` or `tags`.

Refer to the [`cloud` block reference](/terraform/language/terraform#terraform-cloud) for details about configuring the `cloud` block.

Expand All @@ -57,7 +57,11 @@ terraform {
workspaces {
project = "networking-development"
tags = ["networking", "source:cli"]
tags = {
layer = "networking"
source = "cli"
}
}
}
}
Expand Down Expand Up @@ -110,9 +114,9 @@ terraform {
}
```

If the `terraform` block or `terraform.tf` file uses the `prefix` argument to connect to multiple workspaces, you can specify a list of single-value string tags in the `tags` argument instead of using the `name` argument. During `terraform plan` or `terraform apply` operations, Terraform associates the configuration with workspaces that match the specified tags.
If the `terraform` block or `terraform.tf` file uses the `prefix` argument to connect to multiple workspaces, you can specify a list of key-value string tags in the `tags` argument instead of using the `name` argument. During `terraform plan` or `terraform apply` operations, Terraform associates the configuration with workspaces that match the specified tags.

The following example replaces the `my-app-` prefix with the `app:mine` tag:
The following example replaces the `my-app-` prefix with the `app=mine` tag:

```hcl
terraform {
Expand All @@ -122,7 +126,9 @@ terraform {
workspaces {
- prefix = "my-app-"
+ tags = ["app:mine"]
+ tags = {
+ app = "mine"
+ }
}
}
}
Expand Down Expand Up @@ -150,4 +156,3 @@ The rules for defining `.terraformignore` are based on
- Negate a pattern by starting it with an exclamation point `!`. When ignoring large directories, negation patterns can impact performance. Place negation rules as early as possible within `.terraformignore` or avoid using them if possible.

Terraform parses the `.terraformignore` at the root of the configuration directory.

9 changes: 8 additions & 1 deletion website/docs/intro/core-workflow.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,14 @@ terraform {
hostname = "app.terraform.io" # Optional; defaults to app.terraform.io
workspaces {
tags = ["networking", "source:cli"]
tags = {
layer = "networking"
source = "cli"
}
# For terraform versions below 1.10, you must specify key-only tags
# using a list of strings. Example:
# tags = ["networking", "source:cli"]
}
}
}
Expand Down
16 changes: 9 additions & 7 deletions website/docs/language/terraform.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ The following list outlines attribute hierarchy, data types, and requirements in
- [`cloud`](#terraform-cloud): map
- [`organization`](#terraform-cloud-organization): string | required when connecting to HCP Terraform
- [`workspaces`](#terraform-cloud-workspaces): map | required when connecting to HCP Terraform
- [`tags`](#terraform-cloud-workspaces): list of strings
- [`tags`](#terraform-cloud-workspaces): list of strings or map of strings
- [`name`](#terraform-cloud-workspaces): string
- [`project`](#terraform-cloud-workspaces): string
- [`hostname`](#terraform-cloud-workspaces): string | `app.terraform.io`
Expand Down Expand Up @@ -95,9 +95,9 @@ Specifies metadata for matching workspaces in HCP Terraform. Terraform associate

| Attribute | Description | Data type |
| --- | --- | --- |
| `tags` | Specifies a list of flat single-value tags. Terraform associates the configuration with workspaces that have all matching flat single-value tags. New workspaces created from the working directory inherit the tags. This attribute does not support key-value tags. You cannot set this attribute and the `name` attribute in the same configuration. | Array of strings |
| `tags` | Specifies either a map of strings as key/value tags or a list of single-value, key-only tags. Terraform associates the configuration with workspaces that have all matching tags. New workspaces created from the working directory inherit the tags. You cannot set this attribute and the `name` attribute in the same configuration. Using a map type with both keys and values requires Terraform 1.10+. | Array of strings or Map of strings |
| `name` | Specifies an HCP Terraform workspace name to associate the Terraform configuration with. You can only use the working directory with the workspace named in the configuration. You cannot manage the workspace from the Terraform CLI. You cannot set this attribute and the `tags` attribute in the same configuration. <p>Instead of hardcoding a single workspace as a string, you can alternatively use the [`TF_WORKSPACE`](#tf_workspace) environment variable. </p> | String |
| `project` | Specifies the name of an HCP Terraform project. Terraform creates all workspaces that use this configuration in the project. Using the [`terraform workspace list` command](/terraform/cli/commands/workspace/list) in the working directory returns only workspaces in the specified project. <p>Instead of hardcoding the project as a string, you can alternatively use the [`TF_CLOUD_PROJECT`](#tf_cloud_project) environment variable.</p>| String |
| `project` | Specifies the name of an HCP Terraform project. Terraform creates all workspaces that use this configuration in the project. Using the [`terraform workspace list` command](/terraform/cli/commands/workspace/list) in the working directory returns only workspaces in the specified project. <p>Instead of hardcoding the project as a string, you can alternatively use the [`TF_CLOUD_PROJECT`](#tf_cloud_project) environment variable.</p> | String |

- Data type: Map
- Required when connecting to HCP Terraform
Expand Down Expand Up @@ -169,22 +169,24 @@ terraform {

### Connect to HCP Terraform

In the following example, the configuration links the working directory to workspaces in the `example_corp` organization that contain the `app` tag:
In the following example, the configuration links the working directory to workspaces in the `example_corp` organization that contain the `layer=app` tag:

```hcl
terraform {
cloud {
organization = "example_corp"
workspaces {
tags = ["app"]
tags = {
layer = "app"
}
}
}
}
```

### Connect to Terraform Enterprise

In the following example, the configuration links the working directory to workspaces in the `example_corp` organization that contain the `app` tag. The `hostname` field is required in the configuration unless you use the `TF_CLOUD_HOSTNAME` environment variable:
In the following example, the configuration links the working directory to workspaces in the `example_corp` organization that contain the `app` key-only tag. Key-only tags must be used with versions of Terraform Enterprise prior to v202411-1 or versions of Terraform prior to v1.10. The `hostname` field is required in the configuration unless you use the `TF_CLOUD_HOSTNAME` environment variable:

```hcl
terraform {
Expand All @@ -210,4 +212,4 @@ terraform {
}
}
}
```
```

0 comments on commit 558aa18

Please sign in to comment.