core: Fix crash for marked data source prior value
When planning a data source change, the object compatibility verification step should be performed with unmarked values. This value is transient and preserving marks is not necessary, and the object change code is not fully marks-aware.
This commit is contained in:
parent
543706c0d6
commit
4fe76d3f51
|
@ -4,6 +4,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/addrs"
|
"github.com/hashicorp/terraform/addrs"
|
||||||
|
"github.com/hashicorp/terraform/configs/configschema"
|
||||||
"github.com/hashicorp/terraform/plans"
|
"github.com/hashicorp/terraform/plans"
|
||||||
"github.com/hashicorp/terraform/providers"
|
"github.com/hashicorp/terraform/providers"
|
||||||
"github.com/hashicorp/terraform/states"
|
"github.com/hashicorp/terraform/states"
|
||||||
|
@ -59,3 +60,87 @@ resource "test_object" "a" {
|
||||||
t.Fatal(diags.Err())
|
t.Fatal(diags.Err())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestContext2Plan_noChangeDataSourceSensitiveNestedSet(t *testing.T) {
|
||||||
|
m := testModuleInline(t, map[string]string{
|
||||||
|
"main.tf": `
|
||||||
|
variable "bar" {
|
||||||
|
sensitive = true
|
||||||
|
default = "baz"
|
||||||
|
}
|
||||||
|
|
||||||
|
data "test_data_source" "foo" {
|
||||||
|
foo {
|
||||||
|
bar = var.bar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
|
||||||
|
p := new(MockProvider)
|
||||||
|
p.GetSchemaResponse = getSchemaResponseFromProviderSchema(&ProviderSchema{
|
||||||
|
DataSources: map[string]*configschema.Block{
|
||||||
|
"test_data_source": {
|
||||||
|
Attributes: map[string]*configschema.Attribute{
|
||||||
|
"id": {
|
||||||
|
Type: cty.String,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
BlockTypes: map[string]*configschema.NestedBlock{
|
||||||
|
"foo": {
|
||||||
|
Block: configschema.Block{
|
||||||
|
Attributes: map[string]*configschema.Attribute{
|
||||||
|
"bar": {Type: cty.String, Optional: true},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Nesting: configschema.NestingSet,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
|
||||||
|
State: cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"id": cty.StringVal("data_id"),
|
||||||
|
"foo": cty.SetVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{"bar": cty.StringVal("baz")})}),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
state := states.NewState()
|
||||||
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
||||||
|
root.SetResourceInstanceCurrent(
|
||||||
|
mustResourceInstanceAddr("data.test_data_source.foo").Resource,
|
||||||
|
&states.ResourceInstanceObjectSrc{
|
||||||
|
Status: states.ObjectReady,
|
||||||
|
AttrsJSON: []byte(`{"id":"data_id", "foo":[{"bar":"baz"}]}`),
|
||||||
|
AttrSensitivePaths: []cty.PathValueMarks{
|
||||||
|
{
|
||||||
|
Path: cty.GetAttrPath("foo"),
|
||||||
|
Marks: cty.NewValueMarks("sensitive"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
|
||||||
|
)
|
||||||
|
|
||||||
|
ctx := testContext2(t, &ContextOpts{
|
||||||
|
Config: m,
|
||||||
|
Providers: map[addrs.Provider]providers.Factory{
|
||||||
|
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
|
||||||
|
},
|
||||||
|
State: state,
|
||||||
|
})
|
||||||
|
|
||||||
|
plan, diags := ctx.Plan()
|
||||||
|
if diags.HasErrors() {
|
||||||
|
t.Fatal(diags.ErrWithWarnings())
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, res := range plan.Changes.Resources {
|
||||||
|
if res.Action != plans.NoOp {
|
||||||
|
t.Fatalf("expected NoOp, got: %q %s", res.Addr, res.Action)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1415,10 +1415,15 @@ func (n *NodeAbstractResourceInstance) planDataSource(ctx EvalContext, currentSt
|
||||||
|
|
||||||
// if we have a prior value, we can check for any irregularities in the response
|
// if we have a prior value, we can check for any irregularities in the response
|
||||||
if !priorVal.IsNull() {
|
if !priorVal.IsNull() {
|
||||||
|
// We drop marks on the values used here as the result is only
|
||||||
|
// temporarily used for validation.
|
||||||
|
unmarkedConfigVal, _ := configVal.UnmarkDeep()
|
||||||
|
unmarkedPriorVal, _ := priorVal.UnmarkDeep()
|
||||||
|
|
||||||
// While we don't propose planned changes for data sources, we can
|
// While we don't propose planned changes for data sources, we can
|
||||||
// generate a proposed value for comparison to ensure the data source
|
// generate a proposed value for comparison to ensure the data source
|
||||||
// is returning a result following the rules of the provider contract.
|
// is returning a result following the rules of the provider contract.
|
||||||
proposedVal := objchange.ProposedNewObject(schema, priorVal, configVal)
|
proposedVal := objchange.ProposedNewObject(schema, unmarkedPriorVal, unmarkedConfigVal)
|
||||||
if errs := objchange.AssertObjectCompatible(schema, proposedVal, newVal); len(errs) > 0 {
|
if errs := objchange.AssertObjectCompatible(schema, proposedVal, newVal); len(errs) > 0 {
|
||||||
// Resources have the LegacyTypeSystem field to signal when they are
|
// Resources have the LegacyTypeSystem field to signal when they are
|
||||||
// using an SDK which may not produce precise values. While data
|
// using an SDK which may not produce precise values. While data
|
||||||
|
|
Loading…
Reference in New Issue