mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
only cache Input "answers", always call Input
While merging the cached Input configs in the correct order prevents overwriting existing config values, it doesn't prevent an earlier provider from inserting unwanted values into later provider configurations. Diff the key-values returned by Input with the pre-input config, and store only the "answers" that were added during the Input call. Always call Input, even if we already have some values, since a previously cached config may not be complete.
This commit is contained in:
parent
d8f4c1f618
commit
f08bf76ef2
@ -1,6 +1,7 @@
|
||||
package terraform
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
@ -211,16 +212,25 @@ func TestContext2Input_providerOnce(t *testing.T) {
|
||||
count := 0
|
||||
p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) {
|
||||
count++
|
||||
return nil, nil
|
||||
_, set := c.Config["from_input"]
|
||||
|
||||
if count == 1 {
|
||||
if set {
|
||||
return nil, errors.New("from_input should not be set")
|
||||
}
|
||||
c.Config["from_input"] = "x"
|
||||
}
|
||||
|
||||
if count > 1 && !set {
|
||||
return nil, errors.New("from_input should be set")
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
if err := ctx.Input(InputModeStd); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if count != 1 {
|
||||
t.Fatalf("should only be called once: %d", count)
|
||||
}
|
||||
}
|
||||
|
||||
func TestContext2Input_providerId(t *testing.T) {
|
||||
|
@ -99,12 +99,8 @@ type EvalInputProvider struct {
|
||||
}
|
||||
|
||||
func (n *EvalInputProvider) Eval(ctx EvalContext) (interface{}, error) {
|
||||
// If we already configured this provider, then don't do this again
|
||||
if v := ctx.ProviderInput(n.Name); v != nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
rc := *n.Config
|
||||
orig := rc.DeepCopy()
|
||||
|
||||
// Wrap the input into a namespace
|
||||
input := &PrefixUIInput{
|
||||
@ -121,27 +117,19 @@ func (n *EvalInputProvider) Eval(ctx EvalContext) (interface{}, error) {
|
||||
"Error configuring %s: %s", n.Name, err)
|
||||
}
|
||||
|
||||
// Set the input that we received so that child modules don't attempt
|
||||
// to ask for input again.
|
||||
// We only store values that have changed through Input.
|
||||
// The goal is to cache cache input responses, not to provide a complete
|
||||
// config for other providers.
|
||||
confMap := make(map[string]interface{})
|
||||
if config != nil && len(config.Config) > 0 {
|
||||
// This repository of provider input results on the context doesn't
|
||||
// retain config.ComputedKeys, so we need to filter those out here
|
||||
// in order that later users of this data won't try to use the unknown
|
||||
// value placeholder as if it were a literal value. This map is just
|
||||
// of known values we've been able to complete so far; dynamic stuff
|
||||
// will be merged in by EvalBuildProviderConfig on subsequent
|
||||
// (post-input) walks.
|
||||
confMap := config.Config
|
||||
if config.ComputedKeys != nil {
|
||||
for _, key := range config.ComputedKeys {
|
||||
delete(confMap, key)
|
||||
// any values that weren't in the original ResourcConfig will be cached
|
||||
for k, v := range config.Config {
|
||||
if _, ok := orig.Config[k]; !ok {
|
||||
confMap[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx.SetProviderInput(n.Name, confMap)
|
||||
} else {
|
||||
ctx.SetProviderInput(n.Name, map[string]interface{}{})
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -137,9 +137,7 @@ func TestEvalInputProvider(t *testing.T) {
|
||||
}
|
||||
|
||||
rawConfig, err := config.NewRawConfig(map[string]interface{}{
|
||||
"set_in_config": "input",
|
||||
"set_by_input": "input",
|
||||
"computed": "fake_computed",
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -153,6 +151,7 @@ func TestEvalInputProvider(t *testing.T) {
|
||||
ctx := &MockEvalContext{ProviderProvider: provider}
|
||||
rawConfig, err := config.NewRawConfig(map[string]interface{}{
|
||||
"mock_config": "mock",
|
||||
"set_in_config": "input",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("NewRawConfig failed: %s", err)
|
||||
@ -182,12 +181,12 @@ func TestEvalInputProvider(t *testing.T) {
|
||||
}
|
||||
|
||||
inputCfg := ctx.SetProviderInputConfig
|
||||
|
||||
// we should only have the value that was set during Input
|
||||
want := map[string]interface{}{
|
||||
"set_in_config": "input",
|
||||
"set_by_input": "input",
|
||||
// "computed" is omitted because it value isn't known at input time
|
||||
}
|
||||
if !reflect.DeepEqual(inputCfg, want) {
|
||||
t.Errorf("got incorrect input config %#v; want %#v", inputCfg, want)
|
||||
t.Errorf("got incorrect input config:\n%#v\nwant:\n%#v", inputCfg, want)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user