catch conversion errors in PrepareProviderConfig
Errors were being ignore with the intention that they would be caught later in validation, but it turns out we nee dto catch those earlier. The legacy schemas also allowed providers to set and empty string for a bool value, which we need to handle here, since it's not being handled from user input like a normal config value.
This commit is contained in:
parent
92e83e3bcf
commit
5f9b189fcf
|
@ -3,6 +3,7 @@ package plugin
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -94,7 +95,7 @@ func (s *GRPCProviderServer) PrepareProviderConfig(_ context.Context, req *proto
|
||||||
|
|
||||||
// lookup any required, top-level attributes that are Null, and see if we
|
// lookup any required, top-level attributes that are Null, and see if we
|
||||||
// have a Default value available.
|
// have a Default value available.
|
||||||
configVal, _ = cty.Transform(configVal, func(path cty.Path, val cty.Value) (cty.Value, error) {
|
configVal, err = cty.Transform(configVal, func(path cty.Path, val cty.Value) (cty.Value, error) {
|
||||||
// we're only looking for top-level attributes
|
// we're only looking for top-level attributes
|
||||||
if len(path) != 1 {
|
if len(path) != 1 {
|
||||||
return val, nil
|
return val, nil
|
||||||
|
@ -126,20 +127,36 @@ func (s *GRPCProviderServer) PrepareProviderConfig(_ context.Context, req *proto
|
||||||
// find a default value if it exists
|
// find a default value if it exists
|
||||||
def, err := attrSchema.DefaultValue()
|
def, err := attrSchema.DefaultValue()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, fmt.Errorf("error getting default for %q: %s", getAttr.Name, err))
|
||||||
return val, err
|
return val, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// no default
|
// no default
|
||||||
if def == nil {
|
if def == nil {
|
||||||
return val, err
|
return val, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// create a cty.Value and make sure it's the correct type
|
// create a cty.Value and make sure it's the correct type
|
||||||
tmpVal := hcl2shim.HCL2ValueFromConfigValue(def)
|
tmpVal := hcl2shim.HCL2ValueFromConfigValue(def)
|
||||||
|
|
||||||
|
// helper/schema used to allow setting "" to a bool
|
||||||
|
if val.Type() == cty.Bool && tmpVal.RawEquals(cty.StringVal("")) {
|
||||||
|
// return a warning about the conversion
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, "provider set empty string as default value for bool "+getAttr.Name)
|
||||||
|
tmpVal = cty.False
|
||||||
|
}
|
||||||
|
|
||||||
val, err = ctyconvert.Convert(tmpVal, val.Type())
|
val, err = ctyconvert.Convert(tmpVal, val.Type())
|
||||||
|
if err != nil {
|
||||||
|
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, fmt.Errorf("error setting default for %q: %s", getAttr.Name, err))
|
||||||
|
}
|
||||||
|
|
||||||
return val, err
|
return val, err
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
// any error here was already added to the diagnostics
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
configVal, err = block.CoerceValue(configVal)
|
configVal, err = block.CoerceValue(configVal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -526,7 +526,7 @@ func TestPrepareProviderConfig(t *testing.T) {
|
||||||
Schema: map[string]*schema.Schema{
|
Schema: map[string]*schema.Schema{
|
||||||
"foo": &schema.Schema{
|
"foo": &schema.Schema{
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Required: true,
|
Optional: true,
|
||||||
Default: true,
|
Default: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -537,12 +537,28 @@ func TestPrepareProviderConfig(t *testing.T) {
|
||||||
"foo": cty.StringVal("true"),
|
"foo": cty.StringVal("true"),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "test incorrect default bool type",
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"foo": &schema.Schema{
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Default: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ConfigVal: cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"foo": cty.NullVal(cty.Bool),
|
||||||
|
}),
|
||||||
|
ExpectConfig: cty.ObjectVal(map[string]cty.Value{
|
||||||
|
"foo": cty.False,
|
||||||
|
}),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "test deprecated default",
|
Name: "test deprecated default",
|
||||||
Schema: map[string]*schema.Schema{
|
Schema: map[string]*schema.Schema{
|
||||||
"foo": &schema.Schema{
|
"foo": &schema.Schema{
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Required: true,
|
Optional: true,
|
||||||
Default: "do not use",
|
Default: "do not use",
|
||||||
Removed: "don't use this",
|
Removed: "don't use this",
|
||||||
},
|
},
|
||||||
|
@ -580,12 +596,20 @@ func TestPrepareProviderConfig(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if tc.ExpectError == "" && len(resp.Diagnostics) > 0 {
|
if tc.ExpectError != "" && len(resp.Diagnostics) > 0 {
|
||||||
for _, d := range resp.Diagnostics {
|
for _, d := range resp.Diagnostics {
|
||||||
if !strings.Contains(d.Summary, tc.ExpectError) {
|
if !strings.Contains(d.Summary, tc.ExpectError) {
|
||||||
t.Fatalf("Unexpected error: %s/%s", d.Summary, d.Detail)
|
t.Fatalf("Unexpected error: %s/%s", d.Summary, d.Detail)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// we should have no errors past this point
|
||||||
|
for _, d := range resp.Diagnostics {
|
||||||
|
if d.Severity == proto.Diagnostic_ERROR {
|
||||||
|
t.Fatal(resp.Diagnostics)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val, err := msgpack.Unmarshal(resp.PreparedConfig.Msgpack, block.ImpliedType())
|
val, err := msgpack.Unmarshal(resp.PreparedConfig.Msgpack, block.ImpliedType())
|
||||||
|
|
Loading…
Reference in New Issue