Flow allowUnknows for Diff/Check Config

We pass this information for Diff and Check on specific resources, so
we can correctly block unknows from flowing to plugins during applies.
This commit is contained in:
Matt Ellis 2019-05-23 10:54:18 -07:00
parent e574f33fa0
commit f897bf8b4b
7 changed files with 43 additions and 31 deletions

View file

@ -715,7 +715,8 @@ func TestSingleResourceDefaultProviderReplace(t *testing.T) {
loaders := []*deploytest.ProviderLoader{ loaders := []*deploytest.ProviderLoader{
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) { deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
return &deploytest.Provider{ return &deploytest.Provider{
DiffConfigF: func(urn resource.URN, olds, news resource.PropertyMap) (plugin.DiffResult, error) { DiffConfigF: func(urn resource.URN, olds, news resource.PropertyMap,
allowUnknowns bool) (plugin.DiffResult, error) {
// Always require replacement. // Always require replacement.
keys := []resource.PropertyKey{} keys := []resource.PropertyKey{}
for k := range news { for k := range news {
@ -793,7 +794,8 @@ func TestSingleResourceExplicitProviderReplace(t *testing.T) {
loaders := []*deploytest.ProviderLoader{ loaders := []*deploytest.ProviderLoader{
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) { deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
return &deploytest.Provider{ return &deploytest.Provider{
DiffConfigF: func(urn resource.URN, olds, news resource.PropertyMap) (plugin.DiffResult, error) { DiffConfigF: func(urn resource.URN, olds, news resource.PropertyMap,
allowUnknowns bool) (plugin.DiffResult, error) {
// Always require replacement. // Always require replacement.
keys := []resource.PropertyKey{} keys := []resource.PropertyKey{}
for k := range news { for k := range news {
@ -882,7 +884,8 @@ func TestSingleResourceExplicitProviderDeleteBeforeReplace(t *testing.T) {
loaders := []*deploytest.ProviderLoader{ loaders := []*deploytest.ProviderLoader{
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) { deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
return &deploytest.Provider{ return &deploytest.Provider{
DiffConfigF: func(urn resource.URN, olds, news resource.PropertyMap) (plugin.DiffResult, error) { DiffConfigF: func(urn resource.URN, olds, news resource.PropertyMap,
allowUnknowns bool) (plugin.DiffResult, error) {
// Always require replacement. // Always require replacement.
keys := []resource.PropertyKey{} keys := []resource.PropertyKey{}
for k := range news { for k := range news {
@ -2598,7 +2601,8 @@ func TestDeleteBeforeReplace(t *testing.T) {
loaders := []*deploytest.ProviderLoader{ loaders := []*deploytest.ProviderLoader{
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) { deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
return &deploytest.Provider{ return &deploytest.Provider{
DiffConfigF: func(urn resource.URN, olds, news resource.PropertyMap) (plugin.DiffResult, error) { DiffConfigF: func(urn resource.URN, olds, news resource.PropertyMap,
allowUnknowns bool) (plugin.DiffResult, error) {
if !olds["A"].DeepEquals(news["A"]) { if !olds["A"].DeepEquals(news["A"]) {
return plugin.DiffResult{ return plugin.DiffResult{
ReplaceKeys: []resource.PropertyKey{"A"}, ReplaceKeys: []resource.PropertyKey{"A"},

View file

@ -39,13 +39,14 @@ func (p *builtinProvider) Pkg() tokens.Package {
// CheckConfig validates the configuration for this resource provider. // CheckConfig validates the configuration for this resource provider.
func (p *builtinProvider) CheckConfig(urn resource.URN, olds, func (p *builtinProvider) CheckConfig(urn resource.URN, olds,
news resource.PropertyMap) (resource.PropertyMap, []plugin.CheckFailure, error) { news resource.PropertyMap, allowUnknowns bool) (resource.PropertyMap, []plugin.CheckFailure, error) {
return nil, nil, nil return nil, nil, nil
} }
// DiffConfig checks what impacts a hypothetical change to this provider's configuration will have on the provider. // DiffConfig checks what impacts a hypothetical change to this provider's configuration will have on the provider.
func (p *builtinProvider) DiffConfig(urn resource.URN, olds, news resource.PropertyMap) (plugin.DiffResult, error) { func (p *builtinProvider) DiffConfig(urn resource.URN, olds, news resource.PropertyMap,
allowUnknowns bool) (plugin.DiffResult, error) {
return plugin.DiffResult{Changes: plugin.DiffNone}, nil return plugin.DiffResult{Changes: plugin.DiffNone}, nil
} }

View file

@ -33,8 +33,8 @@ type Provider struct {
configured bool configured bool
CheckConfigF func(urn resource.URN, olds, CheckConfigF func(urn resource.URN, olds,
news resource.PropertyMap) (resource.PropertyMap, []plugin.CheckFailure, error) news resource.PropertyMap, allowUnknowns bool) (resource.PropertyMap, []plugin.CheckFailure, error)
DiffConfigF func(urn resource.URN, olds, news resource.PropertyMap) (plugin.DiffResult, error) DiffConfigF func(urn resource.URN, olds, news resource.PropertyMap, allowUnknowns bool) (plugin.DiffResult, error)
ConfigureF func(news resource.PropertyMap) error ConfigureF func(news resource.PropertyMap) error
CheckF func(urn resource.URN, CheckF func(urn resource.URN,
@ -77,17 +77,18 @@ func (prov *Provider) GetPluginInfo() (workspace.PluginInfo, error) {
} }
func (prov *Provider) CheckConfig(urn resource.URN, olds, func (prov *Provider) CheckConfig(urn resource.URN, olds,
news resource.PropertyMap) (resource.PropertyMap, []plugin.CheckFailure, error) { news resource.PropertyMap, allowUnknowns bool) (resource.PropertyMap, []plugin.CheckFailure, error) {
if prov.CheckConfigF == nil { if prov.CheckConfigF == nil {
return news, nil, nil return news, nil, nil
} }
return prov.CheckConfigF(urn, olds, news) return prov.CheckConfigF(urn, olds, news, allowUnknowns)
} }
func (prov *Provider) DiffConfig(urn resource.URN, olds, news resource.PropertyMap) (plugin.DiffResult, error) { func (prov *Provider) DiffConfig(urn resource.URN, olds, news resource.PropertyMap,
allowUnknowns bool) (plugin.DiffResult, error) {
if prov.DiffConfigF == nil { if prov.DiffConfigF == nil {
return plugin.DiffResult{}, nil return plugin.DiffResult{}, nil
} }
return prov.DiffConfigF(urn, olds, news) return prov.DiffConfigF(urn, olds, news, allowUnknowns)
} }
func (prov *Provider) Configure(inputs resource.PropertyMap) error { func (prov *Provider) Configure(inputs resource.PropertyMap) error {
contract.Assert(!prov.configured) contract.Assert(!prov.configured)

View file

@ -186,14 +186,15 @@ func (r *Registry) label() string {
// CheckConfig validates the configuration for this resource provider. // CheckConfig validates the configuration for this resource provider.
func (r *Registry) CheckConfig(urn resource.URN, olds, func (r *Registry) CheckConfig(urn resource.URN, olds,
news resource.PropertyMap) (resource.PropertyMap, []plugin.CheckFailure, error) { news resource.PropertyMap, allowUnknowns bool) (resource.PropertyMap, []plugin.CheckFailure, error) {
contract.Fail() contract.Fail()
return nil, nil, errors.New("the provider registry is not configurable") return nil, nil, errors.New("the provider registry is not configurable")
} }
// DiffConfig checks what impacts a hypothetical change to this provider's configuration will have on the provider. // DiffConfig checks what impacts a hypothetical change to this provider's configuration will have on the provider.
func (r *Registry) DiffConfig(urn resource.URN, olds, news resource.PropertyMap) (plugin.DiffResult, error) { func (r *Registry) DiffConfig(urn resource.URN, olds, news resource.PropertyMap,
allowUnknowns bool) (plugin.DiffResult, error) {
contract.Fail() contract.Fail()
return plugin.DiffResult{}, errors.New("the provider registry is not configurable") return plugin.DiffResult{}, errors.New("the provider registry is not configurable")
} }
@ -233,7 +234,7 @@ func (r *Registry) Check(urn resource.URN, olds, news resource.PropertyMap,
} }
// Check the provider's config. If the check fails, unload the provider. // Check the provider's config. If the check fails, unload the provider.
inputs, failures, err := provider.CheckConfig(urn, olds, news) inputs, failures, err := provider.CheckConfig(urn, olds, news, allowUnknowns)
if len(failures) != 0 || err != nil { if len(failures) != 0 || err != nil {
closeErr := r.host.CloseProvider(provider) closeErr := r.host.CloseProvider(provider)
contract.IgnoreError(closeErr) contract.IgnoreError(closeErr)
@ -276,7 +277,7 @@ func (r *Registry) Diff(urn resource.URN, id resource.ID, olds, news resource.Pr
provider, ok = r.GetProvider(mustNewReference(urn, id)) provider, ok = r.GetProvider(mustNewReference(urn, id))
contract.Assertf(ok, "Provider must have been registered by NewRegistry for DBR Diff (%v::%v)", urn, id) contract.Assertf(ok, "Provider must have been registered by NewRegistry for DBR Diff (%v::%v)", urn, id)
diff, err := provider.DiffConfig(urn, olds, news) diff, err := provider.DiffConfig(urn, olds, news, allowUnknowns)
if err != nil { if err != nil {
return plugin.DiffResult{Changes: plugin.DiffUnknown}, err return plugin.DiffResult{Changes: plugin.DiffUnknown}, err
} }
@ -284,7 +285,7 @@ func (r *Registry) Diff(urn resource.URN, id resource.ID, olds, news resource.Pr
} }
// Diff the properties. // Diff the properties.
diff, err := provider.DiffConfig(urn, olds, news) diff, err := provider.DiffConfig(urn, olds, news, allowUnknowns)
if err != nil { if err != nil {
return plugin.DiffResult{Changes: plugin.DiffUnknown}, err return plugin.DiffResult{Changes: plugin.DiffUnknown}, err
} }

View file

@ -78,8 +78,8 @@ type testProvider struct {
version semver.Version version semver.Version
configured bool configured bool
checkConfig func(resource.URN, resource.PropertyMap, checkConfig func(resource.URN, resource.PropertyMap,
resource.PropertyMap) (resource.PropertyMap, []plugin.CheckFailure, error) resource.PropertyMap, bool) (resource.PropertyMap, []plugin.CheckFailure, error)
diffConfig func(resource.URN, resource.PropertyMap, resource.PropertyMap) (plugin.DiffResult, error) diffConfig func(resource.URN, resource.PropertyMap, resource.PropertyMap, bool) (plugin.DiffResult, error)
config func(resource.PropertyMap) error config func(resource.PropertyMap) error
} }
@ -93,11 +93,12 @@ func (prov *testProvider) Pkg() tokens.Package {
return prov.pkg return prov.pkg
} }
func (prov *testProvider) CheckConfig(urn resource.URN, olds, func (prov *testProvider) CheckConfig(urn resource.URN, olds,
news resource.PropertyMap) (resource.PropertyMap, []plugin.CheckFailure, error) { news resource.PropertyMap, allowUnknowns bool) (resource.PropertyMap, []plugin.CheckFailure, error) {
return prov.checkConfig(urn, olds, news) return prov.checkConfig(urn, olds, news, allowUnknowns)
} }
func (prov *testProvider) DiffConfig(urn resource.URN, olds, news resource.PropertyMap) (plugin.DiffResult, error) { func (prov *testProvider) DiffConfig(urn resource.URN, olds, news resource.PropertyMap,
return prov.diffConfig(urn, olds, news) allowUnknowns bool) (plugin.DiffResult, error) {
return prov.diffConfig(urn, olds, news, allowUnknowns)
} }
func (prov *testProvider) Configure(inputs resource.PropertyMap) error { func (prov *testProvider) Configure(inputs resource.PropertyMap) error {
if err := prov.config(inputs); err != nil { if err := prov.config(inputs); err != nil {
@ -204,10 +205,11 @@ func newSimpleLoader(t *testing.T, pkg, version string, config func(resource.Pro
pkg: pkg, pkg: pkg,
version: ver, version: ver,
checkConfig: func(urn resource.URN, olds, checkConfig: func(urn resource.URN, olds,
news resource.PropertyMap) (resource.PropertyMap, []plugin.CheckFailure, error) { news resource.PropertyMap, allowUnknowns bool) (resource.PropertyMap, []plugin.CheckFailure, error) {
return news, nil, nil return news, nil, nil
}, },
diffConfig: func(urn resource.URN, olds, news resource.PropertyMap) (plugin.DiffResult, error) { diffConfig: func(urn resource.URN, olds, news resource.PropertyMap,
allowUnknowns bool) (plugin.DiffResult, error) {
return plugin.DiffResult{}, nil return plugin.DiffResult{}, nil
}, },
config: config, config: config,
@ -515,10 +517,11 @@ func TestCRUDPreview(t *testing.T) {
pkg: pkg, pkg: pkg,
version: ver, version: ver,
checkConfig: func(urn resource.URN, olds, checkConfig: func(urn resource.URN, olds,
news resource.PropertyMap) (resource.PropertyMap, []plugin.CheckFailure, error) { news resource.PropertyMap, allowUnknowns bool) (resource.PropertyMap, []plugin.CheckFailure, error) {
return news, nil, nil return news, nil, nil
}, },
diffConfig: func(urn resource.URN, olds, news resource.PropertyMap) (plugin.DiffResult, error) { diffConfig: func(urn resource.URN, olds, news resource.PropertyMap,
allowUnknowns bool) (plugin.DiffResult, error) {
// Always reuquire replacement. // Always reuquire replacement.
return plugin.DiffResult{ReplaceKeys: []resource.PropertyKey{"id"}}, nil return plugin.DiffResult{ReplaceKeys: []resource.PropertyKey{"id"}}, nil
}, },

View file

@ -39,9 +39,10 @@ type Provider interface {
Pkg() tokens.Package Pkg() tokens.Package
// CheckConfig validates the configuration for this resource provider. // CheckConfig validates the configuration for this resource provider.
CheckConfig(urn resource.URN, olds, news resource.PropertyMap) (resource.PropertyMap, []CheckFailure, error) CheckConfig(urn resource.URN, olds, news resource.PropertyMap,
allowUnknowns bool) (resource.PropertyMap, []CheckFailure, error)
// DiffConfig checks what impacts a hypothetical change to this provider's configuration will have on the provider. // DiffConfig checks what impacts a hypothetical change to this provider's configuration will have on the provider.
DiffConfig(urn resource.URN, olds, news resource.PropertyMap) (DiffResult, error) DiffConfig(urn resource.URN, olds, news resource.PropertyMap, allowUnknowns bool) (DiffResult, error)
// Configure configures the resource provider with "globals" that control its behavior. // Configure configures the resource provider with "globals" that control its behavior.
Configure(inputs resource.PropertyMap) error Configure(inputs resource.PropertyMap) error

View file

@ -86,7 +86,7 @@ func (p *provider) label() string {
// CheckConfig validates the configuration for this resource provider. // CheckConfig validates the configuration for this resource provider.
func (p *provider) CheckConfig(urn resource.URN, olds, func (p *provider) CheckConfig(urn resource.URN, olds,
news resource.PropertyMap) (resource.PropertyMap, []CheckFailure, error) { news resource.PropertyMap, allowUnknowns bool) (resource.PropertyMap, []CheckFailure, error) {
// Ensure that all config values are strings or unknowns. // Ensure that all config values are strings or unknowns.
var failures []CheckFailure var failures []CheckFailure
for k, v := range news { for k, v := range news {
@ -112,7 +112,8 @@ func (p *provider) CheckConfig(urn resource.URN, olds,
} }
// DiffConfig checks what impacts a hypothetical change to this provider's configuration will have on the provider. // DiffConfig checks what impacts a hypothetical change to this provider's configuration will have on the provider.
func (p *provider) DiffConfig(urn resource.URN, olds, news resource.PropertyMap) (DiffResult, error) { func (p *provider) DiffConfig(urn resource.URN, olds, news resource.PropertyMap,
allowUnknowns bool) (DiffResult, error) {
// There are two interesting scenarios with the present gRPC interface: // There are two interesting scenarios with the present gRPC interface:
// 1. Configuration differences in which all properties are known // 1. Configuration differences in which all properties are known
// 2. Configuration differences in which some new property is unknown. // 2. Configuration differences in which some new property is unknown.