From e3b5e7ebcb0eb0ad02094b0a10ee1b2d6f2df1b3 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Tue, 6 Jun 2023 16:18:13 -0400 Subject: [PATCH] resource/schema: Revert prevent UseStateForUnknown data misalignment by raising implementation error when under a list or set Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/709 Reference: https://github.com/hashicorp/terraform-plugin-framework/pull/711 This unblocks the v1.3.0 release by reverting the `UseStateForUnknown` implementation errors introduced as an interim solution to the originally reported data alignment issue with the plan modifier. Leaving the half state of the `UseStateForUnknown` implementation error would leave provider developers in an unfortunately much worse situation where existing implementations would break without a straightforward path to fixing their schema implementations. The framework needs additional reworking of plan data (potentially reimplementing some of the Terraform core logic in this regard) as a fuller solution for the issue, rather than trying to shoe-horn a solution only for framework-defined plan modifiers. This changeset reverts a lot of the prior code changes that were part of the interim implementation error logic, however it does notably leave the additional unit testing that highlights the current (sometimes unfortunate) behavior of the `UseStateForUnknown` plan modifier so that future efforts can show the expected behavior changes of updating the framework planning logic. --- .../unreleased/BUG FIXES-20230406-112757.yaml | 6 - .../attribute_plan_modification_test.go | 95 +++------ .../fwserver/block_plan_modification_test.go | 97 ++------- .../fwserver/schema_plan_modification_test.go | 22 +- internal/parentpath/doc.go | 12 -- internal/parentpath/has_list_or_set.go | 23 --- internal/parentpath/has_list_or_set_test.go | 190 ------------------ internal/planmodifierdiag/doc.go | 6 - .../planmodifierdiag/use_state_for_unknown.go | 26 --- .../use_state_for_unknown_test.go | 50 ----- .../boolplanmodifier/use_state_for_unknown.go | 20 -- .../use_state_for_unknown_test.go | 30 --- .../use_state_for_unknown.go | 20 -- .../use_state_for_unknown_test.go | 30 --- .../use_state_for_unknown.go | 20 -- .../use_state_for_unknown_test.go | 30 --- .../listplanmodifier/use_state_for_unknown.go | 20 -- .../use_state_for_unknown_test.go | 30 --- .../mapplanmodifier/use_state_for_unknown.go | 20 -- .../use_state_for_unknown_test.go | 30 --- .../use_state_for_unknown.go | 20 -- .../use_state_for_unknown_test.go | 30 --- .../use_state_for_unknown.go | 20 -- .../use_state_for_unknown_test.go | 30 --- .../setplanmodifier/use_state_for_unknown.go | 20 -- .../use_state_for_unknown_test.go | 30 --- .../use_state_for_unknown.go | 20 -- .../use_state_for_unknown_test.go | 30 --- 28 files changed, 49 insertions(+), 928 deletions(-) delete mode 100644 .changes/unreleased/BUG FIXES-20230406-112757.yaml delete mode 100644 internal/parentpath/doc.go delete mode 100644 internal/parentpath/has_list_or_set.go delete mode 100644 internal/parentpath/has_list_or_set_test.go delete mode 100644 internal/planmodifierdiag/doc.go delete mode 100644 internal/planmodifierdiag/use_state_for_unknown.go delete mode 100644 internal/planmodifierdiag/use_state_for_unknown_test.go diff --git a/.changes/unreleased/BUG FIXES-20230406-112757.yaml b/.changes/unreleased/BUG FIXES-20230406-112757.yaml deleted file mode 100644 index c9d322e7a..000000000 --- a/.changes/unreleased/BUG FIXES-20230406-112757.yaml +++ /dev/null @@ -1,6 +0,0 @@ -kind: BUG FIXES -body: 'resource/schema: Prevent `UseStateForUnknown` plan modifier data misalignment - and Terraform errors by raising implementation error when defined under a list or set' -time: 2023-04-06T11:27:57.549597-04:00 -custom: - Issue: "711" diff --git a/internal/fwserver/attribute_plan_modification_test.go b/internal/fwserver/attribute_plan_modification_test.go index 26141919f..45c7d0a9e 100644 --- a/internal/fwserver/attribute_plan_modification_test.go +++ b/internal/fwserver/attribute_plan_modification_test.go @@ -17,7 +17,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwschema/fwxschema" - "github.com/hashicorp/terraform-plugin-framework/internal/planmodifierdiag" "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" "github.com/hashicorp/terraform-plugin-framework/internal/testing/planmodifiers" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testplanmodifier" @@ -358,7 +357,9 @@ func TestAttributeModifyPlan(t *testing.T) { "nested_required": types.StringType, }, map[string]attr.Value{ - "nested_computed": types.StringUnknown(), + // TODO: Rework list/set element alignment during plan + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/709 + "nested_computed": types.StringValue("statevalue1"), "nested_required": types.StringValue("testvalue2"), }, ), @@ -368,7 +369,9 @@ func TestAttributeModifyPlan(t *testing.T) { "nested_required": types.StringType, }, map[string]attr.Value{ - "nested_computed": types.StringUnknown(), + // TODO: Rework list/set element alignment during plan + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/709 + "nested_computed": types.StringValue("statevalue2"), "nested_required": types.StringValue("testvalue1"), }, ), @@ -420,7 +423,9 @@ func TestAttributeModifyPlan(t *testing.T) { "nested_required": types.StringType, }, map[string]attr.Value{ - "nested_computed": types.StringUnknown(), + // TODO: Rework list/set element alignment during plan + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/709 + "nested_computed": types.StringValue("statevalue1"), "nested_required": types.StringValue("testvalue2"), }, ), @@ -430,17 +435,14 @@ func TestAttributeModifyPlan(t *testing.T) { "nested_required": types.StringType, }, map[string]attr.Value{ - "nested_computed": types.StringUnknown(), + // TODO: Rework list/set element alignment during plan + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/709 + "nested_computed": types.StringValue("statevalue2"), "nested_required": types.StringValue("testvalue1"), }, ), }, ), - Diagnostics: diag.Diagnostics{ - planmodifierdiag.UseStateForUnknownUnderListOrSet( - path.Root("test").AtListIndex(0).AtName("nested_computed"), - ), - }, }, }, "attribute-list-nested-nested-usestateforunknown-elements-removed": { @@ -550,17 +552,14 @@ func TestAttributeModifyPlan(t *testing.T) { "nested_required": types.StringType, }, map[string]attr.Value{ - "nested_computed": types.StringUnknown(), + // TODO: Rework list/set element alignment during plan + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/709 + "nested_computed": types.StringValue("statevalue1"), "nested_required": types.StringValue("testvalue2"), }, ), }, ), - Diagnostics: diag.Diagnostics{ - planmodifierdiag.UseStateForUnknownUnderListOrSet( - path.Root("test").AtListIndex(0).AtName("nested_computed"), - ), - }, }, }, "attribute-set-nested-private": { @@ -852,7 +851,7 @@ func TestAttributeModifyPlan(t *testing.T) { "nested_required": types.StringType, }, map[string]attr.Value{ - "nested_computed": types.StringUnknown(), + "nested_computed": types.StringValue("statevalue1"), "nested_required": types.StringValue("testvalue1"), }, ), @@ -862,28 +861,12 @@ func TestAttributeModifyPlan(t *testing.T) { "nested_required": types.StringType, }, map[string]attr.Value{ - "nested_computed": types.StringUnknown(), + "nested_computed": types.StringValue("statevalue2"), "nested_required": types.StringValue("testvalue2"), }, ), }, ), - Diagnostics: diag.Diagnostics{ - planmodifierdiag.UseStateForUnknownUnderListOrSet( - path.Root("test").AtSetValue( - types.ObjectValueMust( - map[string]attr.Type{ - "nested_computed": types.StringType, - "nested_required": types.StringType, - }, - map[string]attr.Value{ - "nested_computed": types.StringUnknown(), - "nested_required": types.StringValue("testvalue1"), - }, - ), - ).AtName("nested_computed"), - ), - }, }, }, "attribute-set-nested-nested-usestateforunknown-elements-rearranged": { @@ -1013,7 +996,9 @@ func TestAttributeModifyPlan(t *testing.T) { "nested_required": types.StringType, }, map[string]attr.Value{ - "nested_computed": types.StringUnknown(), + // TODO: Rework list/set element alignment during plan + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/709 + "nested_computed": types.StringValue("statevalue1"), "nested_required": types.StringValue("testvalue2"), }, ), @@ -1023,28 +1008,14 @@ func TestAttributeModifyPlan(t *testing.T) { "nested_required": types.StringType, }, map[string]attr.Value{ - "nested_computed": types.StringUnknown(), + // TODO: Rework list/set element alignment during plan + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/709 + "nested_computed": types.StringValue("statevalue2"), "nested_required": types.StringValue("testvalue1"), }, ), }, ), - Diagnostics: diag.Diagnostics{ - planmodifierdiag.UseStateForUnknownUnderListOrSet( - path.Root("test").AtSetValue( - types.ObjectValueMust( - map[string]attr.Type{ - "nested_computed": types.StringType, - "nested_required": types.StringType, - }, - map[string]attr.Value{ - "nested_computed": types.StringUnknown(), - "nested_required": types.StringValue("testvalue2"), - }, - ), - ).AtName("nested_computed"), - ), - }, }, }, "attribute-set-nested-nested-usestateforunknown-elements-removed": { @@ -1154,28 +1125,14 @@ func TestAttributeModifyPlan(t *testing.T) { "nested_required": types.StringType, }, map[string]attr.Value{ - "nested_computed": types.StringUnknown(), + // TODO: Rework list/set element alignment during plan + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/709 + "nested_computed": types.StringValue("statevalue1"), "nested_required": types.StringValue("testvalue2"), }, ), }, ), - Diagnostics: diag.Diagnostics{ - planmodifierdiag.UseStateForUnknownUnderListOrSet( - path.Root("test").AtSetValue( - types.ObjectValueMust( - map[string]attr.Type{ - "nested_computed": types.StringType, - "nested_required": types.StringType, - }, - map[string]attr.Value{ - "nested_computed": types.StringUnknown(), - "nested_required": types.StringValue("testvalue2"), - }, - ), - ).AtName("nested_computed"), - ), - }, }, }, "attribute-map-nested-private": { diff --git a/internal/fwserver/block_plan_modification_test.go b/internal/fwserver/block_plan_modification_test.go index 9c2e8fe27..b44b943a8 100644 --- a/internal/fwserver/block_plan_modification_test.go +++ b/internal/fwserver/block_plan_modification_test.go @@ -15,7 +15,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwschema/fwxschema" - "github.com/hashicorp/terraform-plugin-framework/internal/planmodifierdiag" "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" "github.com/hashicorp/terraform-plugin-framework/internal/testing/planmodifiers" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testplanmodifier" @@ -1131,7 +1130,7 @@ func TestBlockModifyPlan(t *testing.T) { "nested_required": types.StringType, }, map[string]attr.Value{ - "nested_computed": types.StringUnknown(), + "nested_computed": types.StringValue("statevalue"), "nested_required": types.StringValue("configvalue"), }, ), @@ -1141,14 +1140,6 @@ func TestBlockModifyPlan(t *testing.T) { ), }, ), - Diagnostics: diag.Diagnostics{ - planmodifierdiag.UseStateForUnknownUnderListOrSet( - path.Root("test").AtListIndex(0).AtName("id"), - ), - planmodifierdiag.UseStateForUnknownUnderListOrSet( - path.Root("test").AtListIndex(0).AtName("list").AtListIndex(0).AtName("nested_computed"), - ), - }, }, }, "block-list-nested-usestateforunknown-elements-rearranged": { @@ -1278,7 +1269,9 @@ func TestBlockModifyPlan(t *testing.T) { "nested_required": types.StringType, }, map[string]attr.Value{ - "nested_computed": types.StringUnknown(), + // TODO: Rework list/set element alignment during plan + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/709 + "nested_computed": types.StringValue("statevalue1"), "nested_required": types.StringValue("testvalue2"), }, ), @@ -1288,17 +1281,14 @@ func TestBlockModifyPlan(t *testing.T) { "nested_required": types.StringType, }, map[string]attr.Value{ - "nested_computed": types.StringUnknown(), + // TODO: Rework list/set element alignment during plan + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/709 + "nested_computed": types.StringValue("statevalue2"), "nested_required": types.StringValue("testvalue1"), }, ), }, ), - Diagnostics: diag.Diagnostics{ - planmodifierdiag.UseStateForUnknownUnderListOrSet( - path.Root("test").AtListIndex(0).AtName("nested_computed"), - ), - }, }, }, "block-list-nested-usestateforunknown-elements-removed": { @@ -1408,17 +1398,14 @@ func TestBlockModifyPlan(t *testing.T) { "nested_required": types.StringType, }, map[string]attr.Value{ - "nested_computed": types.StringUnknown(), + // TODO: Rework list/set element alignment during plan + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/709 + "nested_computed": types.StringValue("statevalue1"), "nested_required": types.StringValue("testvalue2"), }, ), }, ), - Diagnostics: diag.Diagnostics{ - planmodifierdiag.UseStateForUnknownUnderListOrSet( - path.Root("test").AtListIndex(0).AtName("nested_computed"), - ), - }, }, }, "block-set-nested-usestateforunknown": { @@ -1548,7 +1535,7 @@ func TestBlockModifyPlan(t *testing.T) { "nested_required": types.StringType, }, map[string]attr.Value{ - "nested_computed": types.StringUnknown(), + "nested_computed": types.StringValue("statevalue1"), "nested_required": types.StringValue("testvalue1"), }, ), @@ -1558,28 +1545,12 @@ func TestBlockModifyPlan(t *testing.T) { "nested_required": types.StringType, }, map[string]attr.Value{ - "nested_computed": types.StringUnknown(), + "nested_computed": types.StringValue("statevalue2"), "nested_required": types.StringValue("testvalue2"), }, ), }, ), - Diagnostics: diag.Diagnostics{ - planmodifierdiag.UseStateForUnknownUnderListOrSet( - path.Root("test").AtSetValue( - types.ObjectValueMust( - map[string]attr.Type{ - "nested_computed": types.StringType, - "nested_required": types.StringType, - }, - map[string]attr.Value{ - "nested_computed": types.StringUnknown(), - "nested_required": types.StringValue("testvalue1"), - }, - ), - ).AtName("nested_computed"), - ), - }, }, }, "block-set-nested-usestateforunknown-elements-rearranged": { @@ -1709,7 +1680,9 @@ func TestBlockModifyPlan(t *testing.T) { "nested_required": types.StringType, }, map[string]attr.Value{ - "nested_computed": types.StringUnknown(), + // TODO: Rework list/set element alignment during plan + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/709 + "nested_computed": types.StringValue("statevalue1"), "nested_required": types.StringValue("testvalue2"), }, ), @@ -1719,28 +1692,14 @@ func TestBlockModifyPlan(t *testing.T) { "nested_required": types.StringType, }, map[string]attr.Value{ - "nested_computed": types.StringUnknown(), + // TODO: Rework list/set element alignment during plan + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/709 + "nested_computed": types.StringValue("statevalue2"), "nested_required": types.StringValue("testvalue1"), }, ), }, ), - Diagnostics: diag.Diagnostics{ - planmodifierdiag.UseStateForUnknownUnderListOrSet( - path.Root("test").AtSetValue( - types.ObjectValueMust( - map[string]attr.Type{ - "nested_computed": types.StringType, - "nested_required": types.StringType, - }, - map[string]attr.Value{ - "nested_computed": types.StringUnknown(), - "nested_required": types.StringValue("testvalue2"), - }, - ), - ).AtName("nested_computed"), - ), - }, }, }, "block-set-nested-usestateforunknown-elements-removed": { @@ -1850,28 +1809,14 @@ func TestBlockModifyPlan(t *testing.T) { "nested_required": types.StringType, }, map[string]attr.Value{ - "nested_computed": types.StringUnknown(), + // TODO: Rework list/set element alignment during plan + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/709 + "nested_computed": types.StringValue("statevalue1"), "nested_required": types.StringValue("testvalue2"), }, ), }, ), - Diagnostics: diag.Diagnostics{ - planmodifierdiag.UseStateForUnknownUnderListOrSet( - path.Root("test").AtSetValue( - types.ObjectValueMust( - map[string]attr.Type{ - "nested_computed": types.StringType, - "nested_required": types.StringType, - }, - map[string]attr.Value{ - "nested_computed": types.StringUnknown(), - "nested_required": types.StringValue("testvalue2"), - }, - ), - ).AtName("nested_computed"), - ), - }, }, }, "block-set-usestateforunknown": { diff --git a/internal/fwserver/schema_plan_modification_test.go b/internal/fwserver/schema_plan_modification_test.go index 71d2cb28f..de022a196 100644 --- a/internal/fwserver/schema_plan_modification_test.go +++ b/internal/fwserver/schema_plan_modification_test.go @@ -10,10 +10,8 @@ import ( "github.com/google/go-cmp/cmp" "github.com/hashicorp/terraform-plugin-go/tftypes" - "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" - "github.com/hashicorp/terraform-plugin-framework/internal/planmodifierdiag" "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" "github.com/hashicorp/terraform-plugin-framework/internal/testing/planmodifiers" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testplanmodifier" @@ -1405,7 +1403,7 @@ func TestSchemaModifyPlan(t *testing.T) { }, }, map[string]tftypes.Value{ - "nested_computed": tftypes.NewValue(tftypes.String, tftypes.UnknownValue), + "nested_computed": tftypes.NewValue(tftypes.String, "statevalue1"), "nested_required": tftypes.NewValue(tftypes.String, "testvalue1"), }, ), @@ -1417,7 +1415,7 @@ func TestSchemaModifyPlan(t *testing.T) { }, }, map[string]tftypes.Value{ - "nested_computed": tftypes.NewValue(tftypes.String, tftypes.UnknownValue), + "nested_computed": tftypes.NewValue(tftypes.String, "statevalue2"), "nested_required": tftypes.NewValue(tftypes.String, "testvalue2"), }, ), @@ -1448,22 +1446,6 @@ func TestSchemaModifyPlan(t *testing.T) { }, }, }, - Diagnostics: diag.Diagnostics{ - planmodifierdiag.UseStateForUnknownUnderListOrSet( - path.Root("test").AtSetValue( - types.ObjectValueMust( - map[string]attr.Type{ - "nested_computed": types.StringType, - "nested_required": types.StringType, - }, - map[string]attr.Value{ - "nested_computed": types.StringUnknown(), - "nested_required": types.StringValue("testvalue1"), - }, - ), - ).AtName("nested_computed"), - ), - }, }, }, "attribute-map-nested-private": { diff --git a/internal/parentpath/doc.go b/internal/parentpath/doc.go deleted file mode 100644 index 06a865781..000000000 --- a/internal/parentpath/doc.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -// Package parentpath contains path functionality intended for previous steps -// of a given Path or Expression. -// -// This functionality is not included in the exported path package because -// its external utility is unknown and being unexported means the functionality -// can be modified without violating compatibility promises. If provider -// developers are interested in any of this functionality, relevant parts can -// be migrated to the path package or by creating a path/parentpath package. -package parentpath diff --git a/internal/parentpath/has_list_or_set.go b/internal/parentpath/has_list_or_set.go deleted file mode 100644 index 654ccc42d..000000000 --- a/internal/parentpath/has_list_or_set.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package parentpath - -import "github.com/hashicorp/terraform-plugin-framework/path" - -// HasListOrSet returns true if any step of given path is a list or set. This -// cannot detect if the last step is a list or set. -// -// This functionality could also theoretically be a method on the path.Path -// type, e.g. ParentHasListOrSet(), rather than a separate parentpath function. -func HasListOrSet(p path.Path) bool { - for _, pathStep := range p.Steps() { - switch pathStep.(type) { - case path.PathStepElementKeyInt, path.PathStepElementKeyValue: - // This type of step is after a list or set attribute - return true - } - } - - return false -} diff --git a/internal/parentpath/has_list_or_set_test.go b/internal/parentpath/has_list_or_set_test.go deleted file mode 100644 index 6b758b129..000000000 --- a/internal/parentpath/has_list_or_set_test.go +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package parentpath_test - -import ( - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform-plugin-framework/attr" - "github.com/hashicorp/terraform-plugin-framework/internal/parentpath" - "github.com/hashicorp/terraform-plugin-framework/path" - "github.com/hashicorp/terraform-plugin-framework/types" -) - -func TestHasListOrSet(t *testing.T) { - t.Parallel() - - testCases := map[string]struct { - path path.Path - expected bool - }{ - "empty": { - path: path.Empty(), - expected: false, - }, - "AttributeName": { - path: path.Root("test"), - expected: false, - }, - "AttributeName-AttributeName": { - path: path.Root("test").AtName("nested_test"), - expected: false, - }, - "AttributeName-AttributeName-ElementKeyInt": { - path: path.Root("test").AtName("nested_test").AtListIndex(0), - expected: true, - }, - "AttributeName-AttributeName-ElementKeyInt-AttributeName": { - path: path.Root("test").AtName("nested_test").AtListIndex(0).AtName("nested_nested_test"), - expected: true, - }, - "AttributeName-AttributeName-ElementKeyString": { - path: path.Root("test").AtMapKey("testkey"), - expected: false, - }, - "AttributeName-AttributeName-ElementKeyValue": { - path: path.Root("test").AtSetValue( - types.SetValueMust( - types.StringType, - []attr.Value{types.StringValue("testvalue")}, - ), - ), - expected: true, - }, - "AttributeName-ElementKeyInt": { - path: path.Root("test").AtListIndex(0), - expected: true, - }, - "AttributeName-ElementKeyInt-AttributeName": { - path: path.Root("test").AtListIndex(0).AtName("nested_test"), - expected: true, - }, - "AttributeName-ElementKeyInt-ElementKeyInt": { - path: path.Root("test").AtListIndex(0).AtListIndex(0), - expected: true, - }, - "AttributeName-ElementKeyInt-ElementKeyString": { - path: path.Root("test").AtListIndex(0).AtMapKey("testkey"), - expected: true, - }, - "AttributeName-ElementKeyInt-ElementKeyValue": { - path: path.Root("test").AtSetValue( - types.SetValueMust( - types.StringType, - []attr.Value{types.StringValue("testvalue")}, - ), - ), - expected: true, - }, - "AttributeName-ElementKeyString": { - path: path.Root("test").AtMapKey("testkey"), - expected: false, - }, - "AttributeName-ElementKeyString-AttributeName": { - path: path.Root("test").AtMapKey("testkey").AtName("nested_test"), - expected: false, - }, - "AttributeName-ElementKeyString-AttributeName-ElementKeyInt": { - path: path.Root("test").AtMapKey("testkey").AtName("nested_test").AtListIndex(0), - expected: true, - }, - "AttributeName-ElementKeyString-AttributeName-ElementKeyInt-AttributeName": { - path: path.Root("test").AtMapKey("testkey").AtName("nested_test").AtListIndex(0).AtName("nested_nested_test"), - expected: true, - }, - "AttributeName-ElementKeyString-ElementKeyInt": { - path: path.Root("test").AtMapKey("testkey").AtListIndex(0), - expected: true, - }, - "AttributeName-ElementKeyString-ElementKeyInt-AttributeName": { - path: path.Root("test").AtMapKey("testkey").AtListIndex(0).AtName("nested_test"), - expected: true, - }, - "AttributeName-ElementKeyString-ElementKeyString": { - path: path.Root("test").AtMapKey("testkey").AtMapKey("nested_testkey"), - expected: false, - }, - "AttributeName-ElementKeyString-ElementKeyValue": { - path: path.Root("test").AtMapKey("testkey").AtSetValue( - types.SetValueMust( - types.StringType, - []attr.Value{types.StringValue("testvalue")}, - ), - ), - expected: true, - }, - "AttributeName-ElementKeyValue": { - path: path.Root("test").AtSetValue( - types.SetValueMust( - types.StringType, - []attr.Value{types.StringValue("testvalue")}, - ), - ), - expected: true, - }, - "AttributeName-ElementKeyValue-AttributeName": { - path: path.Root("test").AtSetValue( - types.SetValueMust( - types.StringType, - []attr.Value{types.StringValue("testvalue")}, - ), - ).AtName("nested_test"), - expected: true, - }, - "AttributeName-ElementKeyValue-ElementKeyInt": { - path: path.Root("test").AtSetValue( - types.SetValueMust( - types.StringType, - []attr.Value{types.StringValue("testvalue")}, - ), - ).AtListIndex(0), - expected: true, - }, - "AttributeName-ElementKeyValue-ElementKeyString": { - path: path.Root("test").AtSetValue( - types.SetValueMust( - types.StringType, - []attr.Value{types.StringValue("testvalue")}, - ), - ).AtMapKey("testkey"), - expected: true, - }, - "AttributeName-ElementKeyValue-ElementKeyValue": { - path: path.Root("test").AtSetValue( - types.SetValueMust( - types.SetType{ - ElemType: types.StringType, - }, - []attr.Value{ - types.SetValueMust( - types.StringType, - []attr.Value{types.StringValue("testvalue")}, - ), - }, - ), - ).AtSetValue( - types.SetValueMust( - types.StringType, - []attr.Value{types.StringValue("testvalue")}, - ), - ), - expected: true, - }, - } - - for name, testCase := range testCases { - name, testCase := name, testCase - - t.Run(name, func(t *testing.T) { - t.Parallel() - - got := parentpath.HasListOrSet(testCase.path) - - if diff := cmp.Diff(got, testCase.expected); diff != "" { - t.Errorf("unexpected difference: %s", diff) - } - }) - } -} diff --git a/internal/planmodifierdiag/doc.go b/internal/planmodifierdiag/doc.go deleted file mode 100644 index ce05a5595..000000000 --- a/internal/planmodifierdiag/doc.go +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -// Package planmodifierdiag contains shared diag.Diagnostic for -// framework-defined schema plan modifiers. -package planmodifierdiag diff --git a/internal/planmodifierdiag/use_state_for_unknown.go b/internal/planmodifierdiag/use_state_for_unknown.go deleted file mode 100644 index 1e17569e5..000000000 --- a/internal/planmodifierdiag/use_state_for_unknown.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package planmodifierdiag - -import ( - "fmt" - - "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/path" -) - -// UseStateForUnknownUnderListOrSet returns an error diagnostic intended for -// when the UseStateForUnknown schema plan modifier is under a list or set. -func UseStateForUnknownUnderListOrSet(p path.Path) diag.Diagnostic { - return diag.NewAttributeErrorDiagnostic( - p, - "Invalid Attribute Schema", - "Attributes under a list or set cannot use the UseStateForUnknown() plan modifier. "+ - // TODO: Implement MatchElementStateForUnknown plan modifiers. - // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/717 - // "Use the MatchElementStateForUnknown() plan modifier instead. "+ - "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ - fmt.Sprintf("Path: %s\n", p), - ) -} diff --git a/internal/planmodifierdiag/use_state_for_unknown_test.go b/internal/planmodifierdiag/use_state_for_unknown_test.go deleted file mode 100644 index e03eba2d5..000000000 --- a/internal/planmodifierdiag/use_state_for_unknown_test.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package planmodifierdiag_test - -import ( - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/internal/planmodifierdiag" - "github.com/hashicorp/terraform-plugin-framework/path" -) - -func TestUseStateForUnknownUnderListOrSet(t *testing.T) { - t.Parallel() - - testCases := map[string]struct { - path path.Path - expected diag.Diagnostic - }{ - "test": { - path: path.Root("test"), - expected: diag.NewAttributeErrorDiagnostic( - path.Root("test"), - "Invalid Attribute Schema", - "Attributes under a list or set cannot use the UseStateForUnknown() plan modifier. "+ - // TODO: Implement MatchElementStateForUnknown plan modifiers. - // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/717 - // "Use the MatchElementStateForUnknown() plan modifier instead. "+ - "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ - "Path: test\n", - ), - }, - } - - for name, testCase := range testCases { - name, testCase := name, testCase - - t.Run(name, func(t *testing.T) { - t.Parallel() - - got := planmodifierdiag.UseStateForUnknownUnderListOrSet(testCase.path) - - if diff := cmp.Diff(got, testCase.expected); diff != "" { - t.Errorf("unexpected difference: %s", diff) - } - }) - } -} diff --git a/resource/schema/boolplanmodifier/use_state_for_unknown.go b/resource/schema/boolplanmodifier/use_state_for_unknown.go index 8030436ba..efab19637 100644 --- a/resource/schema/boolplanmodifier/use_state_for_unknown.go +++ b/resource/schema/boolplanmodifier/use_state_for_unknown.go @@ -6,8 +6,6 @@ package boolplanmodifier import ( "context" - "github.com/hashicorp/terraform-plugin-framework/internal/parentpath" - "github.com/hashicorp/terraform-plugin-framework/internal/planmodifierdiag" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" ) @@ -19,11 +17,6 @@ import ( // and Computed attributes to an unknown value "(known after apply)" on update. // Using this plan modifier will instead display the prior state value in the // plan, unless a prior plan modifier adjusts the value. -// -// To prevent data issues and Terraform errors, this plan modifier cannot be -// implemented on attribute values beneath lists or sets. An implementation -// error diagnostic is raised if the plan modifier logic detects a list or set -// in the request path. func UseStateForUnknown() planmodifier.Bool { return useStateForUnknownModifier{} } @@ -43,19 +36,6 @@ func (m useStateForUnknownModifier) MarkdownDescription(_ context.Context) strin // PlanModifyBool implements the plan modification logic. func (m useStateForUnknownModifier) PlanModifyBool(_ context.Context, req planmodifier.BoolRequest, resp *planmodifier.BoolResponse) { - // Verify this plan modifier is not being used beneath a list or set. - // Lists and sets do not have a generic methodology to identify/track - // an element if rearranged, especially within an object with multiple - // computed attribute values. Only the provider can determine which - // underlying values in an element are significant to realign a prior - // state value during updates. - // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/709 - if parentpath.HasListOrSet(req.Path) { - resp.Diagnostics.Append(planmodifierdiag.UseStateForUnknownUnderListOrSet(req.Path)) - - return - } - // Do nothing if there is no state value. if req.StateValue.IsNull() { return diff --git a/resource/schema/boolplanmodifier/use_state_for_unknown_test.go b/resource/schema/boolplanmodifier/use_state_for_unknown_test.go index 3d2c21491..cad1f649e 100644 --- a/resource/schema/boolplanmodifier/use_state_for_unknown_test.go +++ b/resource/schema/boolplanmodifier/use_state_for_unknown_test.go @@ -9,8 +9,6 @@ import ( "github.com/google/go-cmp/cmp" "github.com/hashicorp/terraform-plugin-framework/attr" - "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/internal/planmodifierdiag" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" @@ -88,11 +86,6 @@ func TestUseStateForUnknownModifierPlanModifyBool(t *testing.T) { StateValue: types.BoolNull(), }, expected: &planmodifier.BoolResponse{ - Diagnostics: diag.Diagnostics{ - planmodifierdiag.UseStateForUnknownUnderListOrSet( - path.Root("test").AtListIndex(0).AtName("nested_test"), - ), - }, PlanValue: types.BoolUnknown(), }, }, @@ -122,29 +115,6 @@ func TestUseStateForUnknownModifierPlanModifyBool(t *testing.T) { StateValue: types.BoolNull(), }, expected: &planmodifier.BoolResponse{ - Diagnostics: diag.Diagnostics{ - planmodifierdiag.UseStateForUnknownUnderListOrSet( - path.Root("test").AtSetValue( - types.SetValueMust( - types.ObjectType{ - AttrTypes: map[string]attr.Type{ - "nested_test": types.BoolType, - }, - }, - []attr.Value{ - types.ObjectValueMust( - map[string]attr.Type{ - "nested_test": types.BoolType, - }, - map[string]attr.Value{ - "nested_test": types.BoolUnknown(), - }, - ), - }, - ), - ).AtName("nested_test"), - ), - }, PlanValue: types.BoolUnknown(), }, }, diff --git a/resource/schema/float64planmodifier/use_state_for_unknown.go b/resource/schema/float64planmodifier/use_state_for_unknown.go index 098f372b7..923bd34bd 100644 --- a/resource/schema/float64planmodifier/use_state_for_unknown.go +++ b/resource/schema/float64planmodifier/use_state_for_unknown.go @@ -6,8 +6,6 @@ package float64planmodifier import ( "context" - "github.com/hashicorp/terraform-plugin-framework/internal/parentpath" - "github.com/hashicorp/terraform-plugin-framework/internal/planmodifierdiag" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" ) @@ -19,11 +17,6 @@ import ( // and Computed attributes to an unknown value "(known after apply)" on update. // Using this plan modifier will instead display the prior state value in the // plan, unless a prior plan modifier adjusts the value. -// -// To prevent data issues and Terraform errors, this plan modifier cannot be -// implemented on attribute values beneath lists or sets. An implementation -// error diagnostic is raised if the plan modifier logic detects a list or set -// in the request path. func UseStateForUnknown() planmodifier.Float64 { return useStateForUnknownModifier{} } @@ -43,19 +36,6 @@ func (m useStateForUnknownModifier) MarkdownDescription(_ context.Context) strin // PlanModifyFloat64 implements the plan modification logic. func (m useStateForUnknownModifier) PlanModifyFloat64(_ context.Context, req planmodifier.Float64Request, resp *planmodifier.Float64Response) { - // Verify this plan modifier is not being used beneath a list or set. - // Lists and sets do not have a generic methodology to identify/track - // an element if rearranged, especially within an object with multiple - // computed attribute values. Only the provider can determine which - // underlying values in an element are significant to realign a prior - // state value during updates. - // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/709 - if parentpath.HasListOrSet(req.Path) { - resp.Diagnostics.Append(planmodifierdiag.UseStateForUnknownUnderListOrSet(req.Path)) - - return - } - // Do nothing if there is no state value. if req.StateValue.IsNull() { return diff --git a/resource/schema/float64planmodifier/use_state_for_unknown_test.go b/resource/schema/float64planmodifier/use_state_for_unknown_test.go index 05f3f190a..d8d9168c5 100644 --- a/resource/schema/float64planmodifier/use_state_for_unknown_test.go +++ b/resource/schema/float64planmodifier/use_state_for_unknown_test.go @@ -9,8 +9,6 @@ import ( "github.com/google/go-cmp/cmp" "github.com/hashicorp/terraform-plugin-framework/attr" - "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/internal/planmodifierdiag" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource/schema/float64planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" @@ -88,11 +86,6 @@ func TestUseStateForUnknownModifierPlanModifyFloat64(t *testing.T) { StateValue: types.Float64Null(), }, expected: &planmodifier.Float64Response{ - Diagnostics: diag.Diagnostics{ - planmodifierdiag.UseStateForUnknownUnderListOrSet( - path.Root("test").AtListIndex(0).AtName("nested_test"), - ), - }, PlanValue: types.Float64Unknown(), }, }, @@ -122,29 +115,6 @@ func TestUseStateForUnknownModifierPlanModifyFloat64(t *testing.T) { StateValue: types.Float64Null(), }, expected: &planmodifier.Float64Response{ - Diagnostics: diag.Diagnostics{ - planmodifierdiag.UseStateForUnknownUnderListOrSet( - path.Root("test").AtSetValue( - types.SetValueMust( - types.ObjectType{ - AttrTypes: map[string]attr.Type{ - "nested_test": types.Float64Type, - }, - }, - []attr.Value{ - types.ObjectValueMust( - map[string]attr.Type{ - "nested_test": types.Float64Type, - }, - map[string]attr.Value{ - "nested_test": types.Float64Unknown(), - }, - ), - }, - ), - ).AtName("nested_test"), - ), - }, PlanValue: types.Float64Unknown(), }, }, diff --git a/resource/schema/int64planmodifier/use_state_for_unknown.go b/resource/schema/int64planmodifier/use_state_for_unknown.go index 762aea70e..dbee8a08a 100644 --- a/resource/schema/int64planmodifier/use_state_for_unknown.go +++ b/resource/schema/int64planmodifier/use_state_for_unknown.go @@ -6,8 +6,6 @@ package int64planmodifier import ( "context" - "github.com/hashicorp/terraform-plugin-framework/internal/parentpath" - "github.com/hashicorp/terraform-plugin-framework/internal/planmodifierdiag" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" ) @@ -19,11 +17,6 @@ import ( // and Computed attributes to an unknown value "(known after apply)" on update. // Using this plan modifier will instead display the prior state value in the // plan, unless a prior plan modifier adjusts the value. -// -// To prevent data issues and Terraform errors, this plan modifier cannot be -// implemented on attribute values beneath lists or sets. An implementation -// error diagnostic is raised if the plan modifier logic detects a list or set -// in the request path. func UseStateForUnknown() planmodifier.Int64 { return useStateForUnknownModifier{} } @@ -43,19 +36,6 @@ func (m useStateForUnknownModifier) MarkdownDescription(_ context.Context) strin // PlanModifyInt64 implements the plan modification logic. func (m useStateForUnknownModifier) PlanModifyInt64(_ context.Context, req planmodifier.Int64Request, resp *planmodifier.Int64Response) { - // Verify this plan modifier is not being used beneath a list or set. - // Lists and sets do not have a generic methodology to identify/track - // an element if rearranged, especially within an object with multiple - // computed attribute values. Only the provider can determine which - // underlying values in an element are significant to realign a prior - // state value during updates. - // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/709 - if parentpath.HasListOrSet(req.Path) { - resp.Diagnostics.Append(planmodifierdiag.UseStateForUnknownUnderListOrSet(req.Path)) - - return - } - // Do nothing if there is no state value. if req.StateValue.IsNull() { return diff --git a/resource/schema/int64planmodifier/use_state_for_unknown_test.go b/resource/schema/int64planmodifier/use_state_for_unknown_test.go index 6344e004e..bd7e9279a 100644 --- a/resource/schema/int64planmodifier/use_state_for_unknown_test.go +++ b/resource/schema/int64planmodifier/use_state_for_unknown_test.go @@ -9,8 +9,6 @@ import ( "github.com/google/go-cmp/cmp" "github.com/hashicorp/terraform-plugin-framework/attr" - "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/internal/planmodifierdiag" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" @@ -88,11 +86,6 @@ func TestUseStateForUnknownModifierPlanModifyInt64(t *testing.T) { StateValue: types.Int64Null(), }, expected: &planmodifier.Int64Response{ - Diagnostics: diag.Diagnostics{ - planmodifierdiag.UseStateForUnknownUnderListOrSet( - path.Root("test").AtListIndex(0).AtName("nested_test"), - ), - }, PlanValue: types.Int64Unknown(), }, }, @@ -122,29 +115,6 @@ func TestUseStateForUnknownModifierPlanModifyInt64(t *testing.T) { StateValue: types.Int64Null(), }, expected: &planmodifier.Int64Response{ - Diagnostics: diag.Diagnostics{ - planmodifierdiag.UseStateForUnknownUnderListOrSet( - path.Root("test").AtSetValue( - types.SetValueMust( - types.ObjectType{ - AttrTypes: map[string]attr.Type{ - "nested_test": types.Int64Type, - }, - }, - []attr.Value{ - types.ObjectValueMust( - map[string]attr.Type{ - "nested_test": types.Int64Type, - }, - map[string]attr.Value{ - "nested_test": types.Int64Unknown(), - }, - ), - }, - ), - ).AtName("nested_test"), - ), - }, PlanValue: types.Int64Unknown(), }, }, diff --git a/resource/schema/listplanmodifier/use_state_for_unknown.go b/resource/schema/listplanmodifier/use_state_for_unknown.go index dfd57c5a9..c8b2f3bf5 100644 --- a/resource/schema/listplanmodifier/use_state_for_unknown.go +++ b/resource/schema/listplanmodifier/use_state_for_unknown.go @@ -6,8 +6,6 @@ package listplanmodifier import ( "context" - "github.com/hashicorp/terraform-plugin-framework/internal/parentpath" - "github.com/hashicorp/terraform-plugin-framework/internal/planmodifierdiag" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" ) @@ -19,11 +17,6 @@ import ( // and Computed attributes to an unknown value "(known after apply)" on update. // Using this plan modifier will instead display the prior state value in the // plan, unless a prior plan modifier adjusts the value. -// -// To prevent data issues and Terraform errors, this plan modifier cannot be -// implemented on attribute values beneath lists or sets. An implementation -// error diagnostic is raised if the plan modifier logic detects a list or set -// in the request path. func UseStateForUnknown() planmodifier.List { return useStateForUnknownModifier{} } @@ -43,19 +36,6 @@ func (m useStateForUnknownModifier) MarkdownDescription(_ context.Context) strin // PlanModifyList implements the plan modification logic. func (m useStateForUnknownModifier) PlanModifyList(_ context.Context, req planmodifier.ListRequest, resp *planmodifier.ListResponse) { - // Verify this plan modifier is not being used beneath a list or set. - // Lists and sets do not have a generic methodology to identify/track - // an element if rearranged, especially within an object with multiple - // computed attribute values. Only the provider can determine which - // underlying values in an element are significant to realign a prior - // state value during updates. - // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/709 - if parentpath.HasListOrSet(req.Path) { - resp.Diagnostics.Append(planmodifierdiag.UseStateForUnknownUnderListOrSet(req.Path)) - - return - } - // Do nothing if there is no state value. if req.StateValue.IsNull() { return diff --git a/resource/schema/listplanmodifier/use_state_for_unknown_test.go b/resource/schema/listplanmodifier/use_state_for_unknown_test.go index 0e26cd13f..6a38f8221 100644 --- a/resource/schema/listplanmodifier/use_state_for_unknown_test.go +++ b/resource/schema/listplanmodifier/use_state_for_unknown_test.go @@ -9,8 +9,6 @@ import ( "github.com/google/go-cmp/cmp" "github.com/hashicorp/terraform-plugin-framework/attr" - "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/internal/planmodifierdiag" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" @@ -88,11 +86,6 @@ func TestUseStateForUnknownModifierPlanModifyList(t *testing.T) { StateValue: types.ListNull(types.StringType), }, expected: &planmodifier.ListResponse{ - Diagnostics: diag.Diagnostics{ - planmodifierdiag.UseStateForUnknownUnderListOrSet( - path.Root("test").AtListIndex(0).AtName("nested_test"), - ), - }, PlanValue: types.ListUnknown(types.StringType), }, }, @@ -122,29 +115,6 @@ func TestUseStateForUnknownModifierPlanModifyList(t *testing.T) { StateValue: types.ListNull(types.StringType), }, expected: &planmodifier.ListResponse{ - Diagnostics: diag.Diagnostics{ - planmodifierdiag.UseStateForUnknownUnderListOrSet( - path.Root("test").AtSetValue( - types.SetValueMust( - types.ObjectType{ - AttrTypes: map[string]attr.Type{ - "nested_test": types.ListType{ElemType: types.StringType}, - }, - }, - []attr.Value{ - types.ObjectValueMust( - map[string]attr.Type{ - "nested_test": types.ListType{ElemType: types.StringType}, - }, - map[string]attr.Value{ - "nested_test": types.ListUnknown(types.StringType), - }, - ), - }, - ), - ).AtName("nested_test"), - ), - }, PlanValue: types.ListUnknown(types.StringType), }, }, diff --git a/resource/schema/mapplanmodifier/use_state_for_unknown.go b/resource/schema/mapplanmodifier/use_state_for_unknown.go index a6b6ce609..748353583 100644 --- a/resource/schema/mapplanmodifier/use_state_for_unknown.go +++ b/resource/schema/mapplanmodifier/use_state_for_unknown.go @@ -6,8 +6,6 @@ package mapplanmodifier import ( "context" - "github.com/hashicorp/terraform-plugin-framework/internal/parentpath" - "github.com/hashicorp/terraform-plugin-framework/internal/planmodifierdiag" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" ) @@ -19,11 +17,6 @@ import ( // and Computed attributes to an unknown value "(known after apply)" on update. // Using this plan modifier will instead display the prior state value in the // plan, unless a prior plan modifier adjusts the value. -// -// To prevent data issues and Terraform errors, this plan modifier cannot be -// implemented on attribute values beneath lists or sets. An implementation -// error diagnostic is raised if the plan modifier logic detects a list or set -// in the request path. func UseStateForUnknown() planmodifier.Map { return useStateForUnknownModifier{} } @@ -43,19 +36,6 @@ func (m useStateForUnknownModifier) MarkdownDescription(_ context.Context) strin // PlanModifyMap implements the plan modification logic. func (m useStateForUnknownModifier) PlanModifyMap(_ context.Context, req planmodifier.MapRequest, resp *planmodifier.MapResponse) { - // Verify this plan modifier is not being used beneath a list or set. - // Lists and sets do not have a generic methodology to identify/track - // an element if rearranged, especially within an object with multiple - // computed attribute values. Only the provider can determine which - // underlying values in an element are significant to realign a prior - // state value during updates. - // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/709 - if parentpath.HasListOrSet(req.Path) { - resp.Diagnostics.Append(planmodifierdiag.UseStateForUnknownUnderListOrSet(req.Path)) - - return - } - // Do nothing if there is no state value. if req.StateValue.IsNull() { return diff --git a/resource/schema/mapplanmodifier/use_state_for_unknown_test.go b/resource/schema/mapplanmodifier/use_state_for_unknown_test.go index af8a9989e..3b4bf72eb 100644 --- a/resource/schema/mapplanmodifier/use_state_for_unknown_test.go +++ b/resource/schema/mapplanmodifier/use_state_for_unknown_test.go @@ -9,8 +9,6 @@ import ( "github.com/google/go-cmp/cmp" "github.com/hashicorp/terraform-plugin-framework/attr" - "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/internal/planmodifierdiag" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource/schema/mapplanmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" @@ -88,11 +86,6 @@ func TestUseStateForUnknownModifierPlanModifyMap(t *testing.T) { StateValue: types.MapNull(types.StringType), }, expected: &planmodifier.MapResponse{ - Diagnostics: diag.Diagnostics{ - planmodifierdiag.UseStateForUnknownUnderListOrSet( - path.Root("test").AtListIndex(0).AtName("nested_test"), - ), - }, PlanValue: types.MapUnknown(types.StringType), }, }, @@ -122,29 +115,6 @@ func TestUseStateForUnknownModifierPlanModifyMap(t *testing.T) { StateValue: types.MapNull(types.StringType), }, expected: &planmodifier.MapResponse{ - Diagnostics: diag.Diagnostics{ - planmodifierdiag.UseStateForUnknownUnderListOrSet( - path.Root("test").AtSetValue( - types.SetValueMust( - types.ObjectType{ - AttrTypes: map[string]attr.Type{ - "nested_test": types.MapType{ElemType: types.StringType}, - }, - }, - []attr.Value{ - types.ObjectValueMust( - map[string]attr.Type{ - "nested_test": types.MapType{ElemType: types.StringType}, - }, - map[string]attr.Value{ - "nested_test": types.MapUnknown(types.StringType), - }, - ), - }, - ), - ).AtName("nested_test"), - ), - }, PlanValue: types.MapUnknown(types.StringType), }, }, diff --git a/resource/schema/numberplanmodifier/use_state_for_unknown.go b/resource/schema/numberplanmodifier/use_state_for_unknown.go index 70ddc18fc..44a207c92 100644 --- a/resource/schema/numberplanmodifier/use_state_for_unknown.go +++ b/resource/schema/numberplanmodifier/use_state_for_unknown.go @@ -6,8 +6,6 @@ package numberplanmodifier import ( "context" - "github.com/hashicorp/terraform-plugin-framework/internal/parentpath" - "github.com/hashicorp/terraform-plugin-framework/internal/planmodifierdiag" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" ) @@ -19,11 +17,6 @@ import ( // and Computed attributes to an unknown value "(known after apply)" on update. // Using this plan modifier will instead display the prior state value in the // plan, unless a prior plan modifier adjusts the value. -// -// To prevent data issues and Terraform errors, this plan modifier cannot be -// implemented on attribute values beneath lists or sets. An implementation -// error diagnostic is raised if the plan modifier logic detects a list or set -// in the request path. func UseStateForUnknown() planmodifier.Number { return useStateForUnknownModifier{} } @@ -43,19 +36,6 @@ func (m useStateForUnknownModifier) MarkdownDescription(_ context.Context) strin // PlanModifyNumber implements the plan modification logic. func (m useStateForUnknownModifier) PlanModifyNumber(_ context.Context, req planmodifier.NumberRequest, resp *planmodifier.NumberResponse) { - // Verify this plan modifier is not being used beneath a list or set. - // Lists and sets do not have a generic methodology to identify/track - // an element if rearranged, especially within an object with multiple - // computed attribute values. Only the provider can determine which - // underlying values in an element are significant to realign a prior - // state value during updates. - // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/709 - if parentpath.HasListOrSet(req.Path) { - resp.Diagnostics.Append(planmodifierdiag.UseStateForUnknownUnderListOrSet(req.Path)) - - return - } - // Do nothing if there is no state value. if req.StateValue.IsNull() { return diff --git a/resource/schema/numberplanmodifier/use_state_for_unknown_test.go b/resource/schema/numberplanmodifier/use_state_for_unknown_test.go index d53c2e508..982f17854 100644 --- a/resource/schema/numberplanmodifier/use_state_for_unknown_test.go +++ b/resource/schema/numberplanmodifier/use_state_for_unknown_test.go @@ -10,8 +10,6 @@ import ( "github.com/google/go-cmp/cmp" "github.com/hashicorp/terraform-plugin-framework/attr" - "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/internal/planmodifierdiag" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource/schema/numberplanmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" @@ -89,11 +87,6 @@ func TestUseStateForUnknownModifierPlanModifyNumber(t *testing.T) { StateValue: types.NumberNull(), }, expected: &planmodifier.NumberResponse{ - Diagnostics: diag.Diagnostics{ - planmodifierdiag.UseStateForUnknownUnderListOrSet( - path.Root("test").AtListIndex(0).AtName("nested_test"), - ), - }, PlanValue: types.NumberUnknown(), }, }, @@ -123,29 +116,6 @@ func TestUseStateForUnknownModifierPlanModifyNumber(t *testing.T) { StateValue: types.NumberNull(), }, expected: &planmodifier.NumberResponse{ - Diagnostics: diag.Diagnostics{ - planmodifierdiag.UseStateForUnknownUnderListOrSet( - path.Root("test").AtSetValue( - types.SetValueMust( - types.ObjectType{ - AttrTypes: map[string]attr.Type{ - "nested_test": types.NumberType, - }, - }, - []attr.Value{ - types.ObjectValueMust( - map[string]attr.Type{ - "nested_test": types.NumberType, - }, - map[string]attr.Value{ - "nested_test": types.NumberUnknown(), - }, - ), - }, - ), - ).AtName("nested_test"), - ), - }, PlanValue: types.NumberUnknown(), }, }, diff --git a/resource/schema/objectplanmodifier/use_state_for_unknown.go b/resource/schema/objectplanmodifier/use_state_for_unknown.go index 896f693db..67b13f18b 100644 --- a/resource/schema/objectplanmodifier/use_state_for_unknown.go +++ b/resource/schema/objectplanmodifier/use_state_for_unknown.go @@ -6,8 +6,6 @@ package objectplanmodifier import ( "context" - "github.com/hashicorp/terraform-plugin-framework/internal/parentpath" - "github.com/hashicorp/terraform-plugin-framework/internal/planmodifierdiag" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" ) @@ -19,11 +17,6 @@ import ( // and Computed attributes to an unknown value "(known after apply)" on update. // Using this plan modifier will instead display the prior state value in the // plan, unless a prior plan modifier adjusts the value. -// -// To prevent data issues and Terraform errors, this plan modifier cannot be -// implemented on attribute values beneath lists or sets. An implementation -// error diagnostic is raised if the plan modifier logic detects a list or set -// in the request path. func UseStateForUnknown() planmodifier.Object { return useStateForUnknownModifier{} } @@ -43,19 +36,6 @@ func (m useStateForUnknownModifier) MarkdownDescription(_ context.Context) strin // PlanModifyObject implements the plan modification logic. func (m useStateForUnknownModifier) PlanModifyObject(_ context.Context, req planmodifier.ObjectRequest, resp *planmodifier.ObjectResponse) { - // Verify this plan modifier is not being used beneath a list or set. - // Lists and sets do not have a generic methodology to identify/track - // an element if rearranged, especially within an object with multiple - // computed attribute values. Only the provider can determine which - // underlying values in an element are significant to realign a prior - // state value during updates. - // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/709 - if parentpath.HasListOrSet(req.Path) { - resp.Diagnostics.Append(planmodifierdiag.UseStateForUnknownUnderListOrSet(req.Path)) - - return - } - // Do nothing if there is no state value. if req.StateValue.IsNull() { return diff --git a/resource/schema/objectplanmodifier/use_state_for_unknown_test.go b/resource/schema/objectplanmodifier/use_state_for_unknown_test.go index 9d887d7a5..f285194a0 100644 --- a/resource/schema/objectplanmodifier/use_state_for_unknown_test.go +++ b/resource/schema/objectplanmodifier/use_state_for_unknown_test.go @@ -9,8 +9,6 @@ import ( "github.com/google/go-cmp/cmp" "github.com/hashicorp/terraform-plugin-framework/attr" - "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/internal/planmodifierdiag" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource/schema/objectplanmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" @@ -88,11 +86,6 @@ func TestUseStateForUnknownModifierPlanModifyObject(t *testing.T) { StateValue: types.ObjectNull(map[string]attr.Type{"testattr": types.StringType}), }, expected: &planmodifier.ObjectResponse{ - Diagnostics: diag.Diagnostics{ - planmodifierdiag.UseStateForUnknownUnderListOrSet( - path.Root("test").AtListIndex(0).AtName("nested_test"), - ), - }, PlanValue: types.ObjectUnknown(map[string]attr.Type{"testattr": types.StringType}), }, }, @@ -122,29 +115,6 @@ func TestUseStateForUnknownModifierPlanModifyObject(t *testing.T) { StateValue: types.ObjectNull(map[string]attr.Type{"testattr": types.StringType}), }, expected: &planmodifier.ObjectResponse{ - Diagnostics: diag.Diagnostics{ - planmodifierdiag.UseStateForUnknownUnderListOrSet( - path.Root("test").AtSetValue( - types.SetValueMust( - types.ObjectType{ - AttrTypes: map[string]attr.Type{ - "nested_test": types.ObjectType{AttrTypes: map[string]attr.Type{"testattr": types.StringType}}, - }, - }, - []attr.Value{ - types.ObjectValueMust( - map[string]attr.Type{ - "nested_test": types.ObjectType{AttrTypes: map[string]attr.Type{"testattr": types.StringType}}, - }, - map[string]attr.Value{ - "nested_test": types.ObjectUnknown(map[string]attr.Type{"testattr": types.StringType}), - }, - ), - }, - ), - ).AtName("nested_test"), - ), - }, PlanValue: types.ObjectUnknown(map[string]attr.Type{"testattr": types.StringType}), }, }, diff --git a/resource/schema/setplanmodifier/use_state_for_unknown.go b/resource/schema/setplanmodifier/use_state_for_unknown.go index c3dc427b6..0bf359cd2 100644 --- a/resource/schema/setplanmodifier/use_state_for_unknown.go +++ b/resource/schema/setplanmodifier/use_state_for_unknown.go @@ -6,8 +6,6 @@ package setplanmodifier import ( "context" - "github.com/hashicorp/terraform-plugin-framework/internal/parentpath" - "github.com/hashicorp/terraform-plugin-framework/internal/planmodifierdiag" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" ) @@ -19,11 +17,6 @@ import ( // and Computed attributes to an unknown value "(known after apply)" on update. // Using this plan modifier will instead display the prior state value in the // plan, unless a prior plan modifier adjusts the value. -// -// To prevent data issues and Terraform errors, this plan modifier cannot be -// implemented on attribute values beneath lists or sets. An implementation -// error diagnostic is raised if the plan modifier logic detects a list or set -// in the request path. func UseStateForUnknown() planmodifier.Set { return useStateForUnknownModifier{} } @@ -43,19 +36,6 @@ func (m useStateForUnknownModifier) MarkdownDescription(_ context.Context) strin // PlanModifySet implements the plan modification logic. func (m useStateForUnknownModifier) PlanModifySet(_ context.Context, req planmodifier.SetRequest, resp *planmodifier.SetResponse) { - // Verify this plan modifier is not being used beneath a list or set. - // Lists and sets do not have a generic methodology to identify/track - // an element if rearranged, especially within an object with multiple - // computed attribute values. Only the provider can determine which - // underlying values in an element are significant to realign a prior - // state value during updates. - // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/709 - if parentpath.HasListOrSet(req.Path) { - resp.Diagnostics.Append(planmodifierdiag.UseStateForUnknownUnderListOrSet(req.Path)) - - return - } - // Do nothing if there is no state value. if req.StateValue.IsNull() { return diff --git a/resource/schema/setplanmodifier/use_state_for_unknown_test.go b/resource/schema/setplanmodifier/use_state_for_unknown_test.go index b4fc75cec..47a324dac 100644 --- a/resource/schema/setplanmodifier/use_state_for_unknown_test.go +++ b/resource/schema/setplanmodifier/use_state_for_unknown_test.go @@ -9,8 +9,6 @@ import ( "github.com/google/go-cmp/cmp" "github.com/hashicorp/terraform-plugin-framework/attr" - "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/internal/planmodifierdiag" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/setplanmodifier" @@ -88,11 +86,6 @@ func TestUseStateForUnknownModifierPlanModifySet(t *testing.T) { StateValue: types.SetNull(types.StringType), }, expected: &planmodifier.SetResponse{ - Diagnostics: diag.Diagnostics{ - planmodifierdiag.UseStateForUnknownUnderListOrSet( - path.Root("test").AtListIndex(0).AtName("nested_test"), - ), - }, PlanValue: types.SetUnknown(types.StringType), }, }, @@ -122,29 +115,6 @@ func TestUseStateForUnknownModifierPlanModifySet(t *testing.T) { StateValue: types.SetNull(types.StringType), }, expected: &planmodifier.SetResponse{ - Diagnostics: diag.Diagnostics{ - planmodifierdiag.UseStateForUnknownUnderListOrSet( - path.Root("test").AtSetValue( - types.SetValueMust( - types.ObjectType{ - AttrTypes: map[string]attr.Type{ - "nested_test": types.SetType{ElemType: types.StringType}, - }, - }, - []attr.Value{ - types.ObjectValueMust( - map[string]attr.Type{ - "nested_test": types.SetType{ElemType: types.StringType}, - }, - map[string]attr.Value{ - "nested_test": types.SetUnknown(types.StringType), - }, - ), - }, - ), - ).AtName("nested_test"), - ), - }, PlanValue: types.SetUnknown(types.StringType), }, }, diff --git a/resource/schema/stringplanmodifier/use_state_for_unknown.go b/resource/schema/stringplanmodifier/use_state_for_unknown.go index 9d17bbd81..983bc5cb0 100644 --- a/resource/schema/stringplanmodifier/use_state_for_unknown.go +++ b/resource/schema/stringplanmodifier/use_state_for_unknown.go @@ -6,8 +6,6 @@ package stringplanmodifier import ( "context" - "github.com/hashicorp/terraform-plugin-framework/internal/parentpath" - "github.com/hashicorp/terraform-plugin-framework/internal/planmodifierdiag" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" ) @@ -19,11 +17,6 @@ import ( // and Computed attributes to an unknown value "(known after apply)" on update. // Using this plan modifier will instead display the prior state value in the // plan, unless a prior plan modifier adjusts the value. -// -// To prevent data issues and Terraform errors, this plan modifier cannot be -// implemented on attribute values beneath lists or sets. An implementation -// error diagnostic is raised if the plan modifier logic detects a list or set -// in the request path. func UseStateForUnknown() planmodifier.String { return useStateForUnknownModifier{} } @@ -43,19 +36,6 @@ func (m useStateForUnknownModifier) MarkdownDescription(_ context.Context) strin // PlanModifyString implements the plan modification logic. func (m useStateForUnknownModifier) PlanModifyString(ctx context.Context, req planmodifier.StringRequest, resp *planmodifier.StringResponse) { - // Verify this plan modifier is not being used beneath a list or set. - // Lists and sets do not have a generic methodology to identify/track - // an element if rearranged, especially within an object with multiple - // computed attribute values. Only the provider can determine which - // underlying values in an element are significant to realign a prior - // state value during updates. - // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/709 - if parentpath.HasListOrSet(req.Path) { - resp.Diagnostics.Append(planmodifierdiag.UseStateForUnknownUnderListOrSet(req.Path)) - - return - } - // Do nothing if there is no state value. if req.StateValue.IsNull() { return diff --git a/resource/schema/stringplanmodifier/use_state_for_unknown_test.go b/resource/schema/stringplanmodifier/use_state_for_unknown_test.go index df41d34bf..0bdd1f513 100644 --- a/resource/schema/stringplanmodifier/use_state_for_unknown_test.go +++ b/resource/schema/stringplanmodifier/use_state_for_unknown_test.go @@ -9,8 +9,6 @@ import ( "github.com/google/go-cmp/cmp" "github.com/hashicorp/terraform-plugin-framework/attr" - "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/internal/planmodifierdiag" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" @@ -88,11 +86,6 @@ func TestUseStateForUnknownModifierPlanModifyString(t *testing.T) { StateValue: types.StringNull(), }, expected: &planmodifier.StringResponse{ - Diagnostics: diag.Diagnostics{ - planmodifierdiag.UseStateForUnknownUnderListOrSet( - path.Root("test").AtListIndex(0).AtName("nested_test"), - ), - }, PlanValue: types.StringUnknown(), }, }, @@ -122,29 +115,6 @@ func TestUseStateForUnknownModifierPlanModifyString(t *testing.T) { StateValue: types.StringNull(), }, expected: &planmodifier.StringResponse{ - Diagnostics: diag.Diagnostics{ - planmodifierdiag.UseStateForUnknownUnderListOrSet( - path.Root("test").AtSetValue( - types.SetValueMust( - types.ObjectType{ - AttrTypes: map[string]attr.Type{ - "nested_test": types.StringType, - }, - }, - []attr.Value{ - types.ObjectValueMust( - map[string]attr.Type{ - "nested_test": types.StringType, - }, - map[string]attr.Value{ - "nested_test": types.StringUnknown(), - }, - ), - }, - ), - ).AtName("nested_test"), - ), - }, PlanValue: types.StringUnknown(), }, },