Return marked After values in GetResource

If a change exists for a resource instance,
the After value is returned, however, this value
will not have its marks as it as been encoded.
This Marks the return value so the marks follow
that resource reference.
This commit is contained in:
Pam Selle 2020-10-20 16:29:05 -04:00
parent 9904667fc3
commit c6be76e53c
2 changed files with 129 additions and 1 deletions

View File

@ -756,7 +756,7 @@ func (d *evaluationStateData) GetResource(addr addrs.Resource, rng tfdiags.Sourc
if schema.ContainsSensitive() {
val = markProviderSensitiveAttributes(schema, val)
}
instances[key] = val
instances[key] = val.MarkWithPaths(change.AfterValMarks)
continue
}

View File

@ -297,6 +297,134 @@ func TestEvaluatorGetResource(t *testing.T) {
}
}
// GetResource will return a planned object's After value
// if there is a change for that resource instance.
func TestEvaluatorGetResource_changes(t *testing.T) {
// Set up existing state
stateSync := states.BuildState(func(ss *states.SyncState) {
ss.SetResourceInstanceCurrent(
addrs.Resource{
Mode: addrs.ManagedResourceMode,
Type: "test_resource",
Name: "foo",
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
&states.ResourceInstanceObjectSrc{
Status: states.ObjectPlanned,
AttrsJSON: []byte(`{"id":"foo", "to_mark_val":"tacos", "sensitive_value":"abc"}`),
},
addrs.AbsProviderConfig{
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
)
}).SyncWrapper()
// Create a change for the existing state resource,
// to exercise retrieving the After value of the change
changesSync := plans.NewChanges().SyncWrapper()
change := &plans.ResourceInstanceChange{
Addr: mustResourceInstanceAddr("test_resource.foo"),
ProviderAddr: addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("test"),
},
Change: plans.Change{
Action: plans.Update,
// Provide an After value that contains a marked value
After: cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("foo"),
"to_mark_val": cty.StringVal("pizza").Mark("sensitive"),
"sensitive_value": cty.StringVal("abc"),
}),
},
}
// Set up our schemas
schemas := &Schemas{
Providers: map[addrs.Provider]*ProviderSchema{
addrs.NewDefaultProvider("test"): {
Provider: &configschema.Block{},
ResourceTypes: map[string]*configschema.Block{
"test_resource": {
Attributes: map[string]*configschema.Attribute{
"id": {
Type: cty.String,
Computed: true,
},
"to_mark_val": {
Type: cty.String,
Computed: true,
},
"sensitive_value": {
Type: cty.String,
Computed: true,
Sensitive: true,
},
},
},
},
},
},
}
// The resource we'll inspect
addr := addrs.Resource{
Mode: addrs.ManagedResourceMode,
Type: "test_resource",
Name: "foo",
}
schema, _ := schemas.ResourceTypeConfig(addrs.NewDefaultProvider("test"), addr.Mode, addr.Type)
// This encoding separates out the After's marks into its AfterValMarks
csrc, _ := change.Encode(schema.ImpliedType())
changesSync.AppendResourceInstanceChange(csrc)
evaluator := &Evaluator{
Meta: &ContextMeta{
Env: "foo",
},
Changes: changesSync,
Config: &configs.Config{
Module: &configs.Module{
ManagedResources: map[string]*configs.Resource{
"test_resource.foo": &configs.Resource{
Mode: addrs.ManagedResourceMode,
Type: "test_resource",
Name: "foo",
Provider: addrs.Provider{
Hostname: addrs.DefaultRegistryHost,
Namespace: "hashicorp",
Type: "test",
},
},
},
},
},
State: stateSync,
Schemas: schemas,
}
data := &evaluationStateData{
Evaluator: evaluator,
}
scope := evaluator.Scope(data, nil)
want := cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("foo"),
"to_mark_val": cty.StringVal("pizza").Mark("sensitive"),
"sensitive_value": cty.StringVal("abc").Mark("sensitive"),
})
got, diags := scope.Data.GetResource(addr, tfdiags.SourceRange{})
if len(diags) != 0 {
t.Errorf("unexpected diagnostics %s", spew.Sdump(diags))
}
if !got.RawEquals(want) {
t.Errorf("wrong result:\ngot: %#v\nwant: %#v", got, want)
}
}
func TestEvaluatorGetModule(t *testing.T) {
// Create a new evaluator with an existing state
stateSync := states.BuildState(func(ss *states.SyncState) {