Merge pull request #24896 from bendrucker/validate-ignore-empty-provider
validate: ignore providers with no configuration
This commit is contained in:
commit
c9f372a62b
|
@ -135,6 +135,52 @@ func TestLocal_refreshValidate(t *testing.T) {
|
|||
}
|
||||
<-run.Done()
|
||||
|
||||
checkState(t, b.StateOutPath, `
|
||||
test_instance.foo:
|
||||
ID = yes
|
||||
provider = provider["registry.terraform.io/hashicorp/test"]
|
||||
`)
|
||||
}
|
||||
|
||||
func TestLocal_refreshValidateProviderConfigured(t *testing.T) {
|
||||
b, cleanup := TestLocal(t)
|
||||
defer cleanup()
|
||||
|
||||
schema := &terraform.ProviderSchema{
|
||||
Provider: &configschema.Block{
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"value": {Type: cty.String, Optional: true},
|
||||
},
|
||||
},
|
||||
ResourceTypes: map[string]*configschema.Block{
|
||||
"test_instance": {
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"id": {Type: cty.String, Computed: true},
|
||||
"ami": {Type: cty.String, Optional: true},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
p := TestLocalProvider(t, b, "test", schema)
|
||||
testStateFile(t, b.StatePath, testRefreshState())
|
||||
p.ReadResourceFn = nil
|
||||
p.ReadResourceResponse = providers.ReadResourceResponse{NewState: cty.ObjectVal(map[string]cty.Value{
|
||||
"id": cty.StringVal("yes"),
|
||||
})}
|
||||
|
||||
// Enable validation
|
||||
b.OpValidation = true
|
||||
|
||||
op, configCleanup := testOperationRefresh(t, "./testdata/refresh-provider-config")
|
||||
defer configCleanup()
|
||||
|
||||
run, err := b.Operation(context.Background(), op)
|
||||
if err != nil {
|
||||
t.Fatalf("bad: %s", err)
|
||||
}
|
||||
<-run.Done()
|
||||
|
||||
if !p.PrepareProviderConfigCalled {
|
||||
t.Fatal("Prepare provider config should be called")
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
resource "test_instance" "foo" {
|
||||
ami = "bar"
|
||||
}
|
||||
|
||||
provider "test" {
|
||||
value = "foo"
|
||||
}
|
|
@ -595,8 +595,8 @@ func TestContext2Validate_providerConfig_bad(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestContext2Validate_providerConfig_badEmpty(t *testing.T) {
|
||||
m := testModule(t, "validate-bad-pc-empty")
|
||||
func TestContext2Validate_providerConfig_skippedEmpty(t *testing.T) {
|
||||
m := testModule(t, "validate-skipped-pc-empty")
|
||||
p := testProvider("aws")
|
||||
p.GetSchemaReturn = &ProviderSchema{
|
||||
Provider: &configschema.Block{
|
||||
|
@ -619,12 +619,12 @@ func TestContext2Validate_providerConfig_badEmpty(t *testing.T) {
|
|||
})
|
||||
|
||||
p.PrepareProviderConfigResponse = providers.PrepareProviderConfigResponse{
|
||||
Diagnostics: tfdiags.Diagnostics{}.Append(fmt.Errorf("bad")),
|
||||
Diagnostics: tfdiags.Diagnostics{}.Append(fmt.Errorf("should not be called")),
|
||||
}
|
||||
|
||||
diags := c.Validate()
|
||||
if !diags.HasErrors() {
|
||||
t.Fatalf("succeeded; want error")
|
||||
if diags.HasErrors() {
|
||||
t.Fatalf("unexpected error: %s", diags.Err())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -48,6 +48,14 @@ func (n *NodeApplyableProvider) ValidateProvider(ctx EvalContext, provider provi
|
|||
|
||||
configBody := buildProviderConfig(ctx, n.Addr, n.ProviderConfig())
|
||||
|
||||
// if a provider config is empty (only an alias), return early and don't continue
|
||||
// validation. validate doesn't need to fully configure the provider itself, so
|
||||
// skipping a provider with an implied configuration won't prevent other validation from completing.
|
||||
_, noConfigDiags := configBody.Content(&hcl.BodySchema{})
|
||||
if !noConfigDiags.HasErrors() {
|
||||
return nil
|
||||
}
|
||||
|
||||
resp := provider.GetSchema()
|
||||
diags = diags.Append(resp.Diagnostics)
|
||||
if diags.HasErrors() {
|
||||
|
@ -64,19 +72,7 @@ func (n *NodeApplyableProvider) ValidateProvider(ctx EvalContext, provider provi
|
|||
|
||||
configVal, _, evalDiags := ctx.EvaluateBlock(configBody, configSchema, nil, EvalDataForNoInstanceKey)
|
||||
if evalDiags.HasErrors() {
|
||||
if n.Config == nil {
|
||||
// If there isn't an explicit "provider" block in the configuration,
|
||||
// this error message won't be very clear. Add some detail to the
|
||||
// error message in this case.
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Invalid provider configuration",
|
||||
fmt.Sprintf(providerConfigErr, evalDiags.Err(), n.Addr.Provider),
|
||||
))
|
||||
return diags
|
||||
} else {
|
||||
return diags.Append(evalDiags)
|
||||
}
|
||||
return diags.Append(evalDiags)
|
||||
}
|
||||
diags = diags.Append(evalDiags)
|
||||
|
||||
|
|
|
@ -196,6 +196,40 @@ func TestNodeApplyableProviderExecute_sensitiveValidate(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestNodeApplyableProviderExecute_emptyValidate(t *testing.T) {
|
||||
config := &configs.Provider{
|
||||
Name: "foo",
|
||||
Config: configs.SynthBody("", map[string]cty.Value{}),
|
||||
}
|
||||
provider := mockProviderWithConfigSchema(&configschema.Block{
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"test_string": {
|
||||
Type: cty.String,
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
providerAddr := addrs.AbsProviderConfig{
|
||||
Module: addrs.RootModule,
|
||||
Provider: addrs.NewDefaultProvider("foo"),
|
||||
}
|
||||
|
||||
n := &NodeApplyableProvider{&NodeAbstractProvider{
|
||||
Addr: providerAddr,
|
||||
Config: config,
|
||||
}}
|
||||
|
||||
ctx := &MockEvalContext{ProviderProvider: provider}
|
||||
ctx.installSimpleEval()
|
||||
if err := n.Execute(ctx, walkValidate); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if ctx.ConfigureProviderCalled {
|
||||
t.Fatal("should not be called")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNodeApplyableProvider_Validate(t *testing.T) {
|
||||
provider := &MockProvider{
|
||||
GetSchemaReturn: &ProviderSchema{
|
||||
|
@ -233,7 +267,28 @@ func TestNodeApplyableProvider_Validate(t *testing.T) {
|
|||
}
|
||||
})
|
||||
|
||||
t.Run("missing required config", func(t *testing.T) {
|
||||
t.Run("invalid", func(t *testing.T) {
|
||||
config := &configs.Provider{
|
||||
Name: "test",
|
||||
Config: configs.SynthBody("", map[string]cty.Value{
|
||||
"region": cty.MapValEmpty(cty.String),
|
||||
}),
|
||||
}
|
||||
|
||||
node := NodeApplyableProvider{
|
||||
NodeAbstractProvider: &NodeAbstractProvider{
|
||||
Addr: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
||||
Config: config,
|
||||
},
|
||||
}
|
||||
|
||||
diags := node.ValidateProvider(ctx, provider)
|
||||
if !diags.HasErrors() {
|
||||
t.Error("missing expected error with invalid config")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("empty config", func(t *testing.T) {
|
||||
node := NodeApplyableProvider{
|
||||
NodeAbstractProvider: &NodeAbstractProvider{
|
||||
Addr: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
||||
|
@ -241,8 +296,8 @@ func TestNodeApplyableProvider_Validate(t *testing.T) {
|
|||
}
|
||||
|
||||
diags := node.ValidateProvider(ctx, provider)
|
||||
if !diags.HasErrors() {
|
||||
t.Error("missing expected error with invalid config")
|
||||
if diags.HasErrors() {
|
||||
t.Errorf("unexpected error with empty config: %s", diags.Err())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue