Insert default values into provider config
Add any top-level default attributes from the provider schema into Null config values.
This commit is contained in:
parent
ac5f08c5d8
commit
e077c9ce95
|
@ -6,6 +6,7 @@ import (
|
|||
"strconv"
|
||||
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
ctyconvert "github.com/zclconf/go-cty/cty/convert"
|
||||
"github.com/zclconf/go-cty/cty/msgpack"
|
||||
context "golang.org/x/net/context"
|
||||
|
||||
|
@ -88,13 +89,67 @@ func (s *GRPCProviderServer) PrepareProviderConfig(_ context.Context, req *proto
|
|||
return resp, nil
|
||||
}
|
||||
|
||||
// lookup any required, top-level attributes that are Null, and see if we
|
||||
// have a Default value available.
|
||||
configVal, _ = cty.Transform(configVal, func(path cty.Path, val cty.Value) (cty.Value, error) {
|
||||
// we're only looking for top-level attributes
|
||||
if len(path) != 1 {
|
||||
return val, nil
|
||||
}
|
||||
|
||||
// nothing to do if we already have a value
|
||||
if !val.IsNull() {
|
||||
return val, nil
|
||||
}
|
||||
|
||||
// get the Schema definition for this attribute
|
||||
getAttr, ok := path[0].(cty.GetAttrStep)
|
||||
// these should all exist, but just ignore anything strange
|
||||
if !ok {
|
||||
return val, nil
|
||||
}
|
||||
|
||||
attrSchema := s.provider.Schema[getAttr.Name]
|
||||
// continue to ignore anything that doesn't match
|
||||
if attrSchema == nil {
|
||||
return val, nil
|
||||
}
|
||||
|
||||
// find a default value if it exists
|
||||
def, err := attrSchema.DefaultValue()
|
||||
if err != nil {
|
||||
return val, err
|
||||
}
|
||||
|
||||
// no default
|
||||
if def == nil {
|
||||
return val, err
|
||||
}
|
||||
|
||||
// create a cty.Value and make sure it's the correct type
|
||||
tmpVal := hcl2shim.HCL2ValueFromConfigValue(def)
|
||||
val, err = ctyconvert.Convert(tmpVal, val.Type())
|
||||
return val, err
|
||||
})
|
||||
|
||||
configVal, err = block.CoerceValue(configVal)
|
||||
if err != nil {
|
||||
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
config := terraform.NewResourceConfigShimmed(configVal, block)
|
||||
|
||||
warns, errs := s.provider.Validate(config)
|
||||
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, convert.WarnsAndErrsToProto(warns, errs))
|
||||
|
||||
// TODO: set defaults
|
||||
resp.PreparedConfig = req.Config
|
||||
preparedConfigMP, err := msgpack.Marshal(configVal, block.ImpliedType())
|
||||
if err != nil {
|
||||
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
resp.PreparedConfig = &proto.DynamicValue{Msgpack: preparedConfigMP}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package plugin
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
@ -425,3 +426,155 @@ func TestApplyResourceChange(t *testing.T) {
|
|||
t.Fatalf("incorrect final state: %#v\n", newStateVal)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrepareProviderConfig(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
Name string
|
||||
Schema map[string]*schema.Schema
|
||||
ConfigVal cty.Value
|
||||
ExpectError string
|
||||
ExpectConfig cty.Value
|
||||
}{
|
||||
{
|
||||
Name: "test prepare",
|
||||
Schema: map[string]*schema.Schema{
|
||||
"foo": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
ConfigVal: cty.ObjectVal(map[string]cty.Value{
|
||||
"foo": cty.StringVal("bar"),
|
||||
}),
|
||||
ExpectConfig: cty.ObjectVal(map[string]cty.Value{
|
||||
"foo": cty.StringVal("bar"),
|
||||
}),
|
||||
},
|
||||
{
|
||||
Name: "test default",
|
||||
Schema: map[string]*schema.Schema{
|
||||
"foo": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Default: "default",
|
||||
},
|
||||
},
|
||||
ConfigVal: cty.ObjectVal(map[string]cty.Value{
|
||||
"foo": cty.NullVal(cty.String),
|
||||
}),
|
||||
ExpectConfig: cty.ObjectVal(map[string]cty.Value{
|
||||
"foo": cty.StringVal("default"),
|
||||
}),
|
||||
},
|
||||
{
|
||||
Name: "test defaultfunc",
|
||||
Schema: map[string]*schema.Schema{
|
||||
"foo": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
DefaultFunc: func() (interface{}, error) {
|
||||
return "defaultfunc", nil
|
||||
},
|
||||
},
|
||||
},
|
||||
ConfigVal: cty.ObjectVal(map[string]cty.Value{
|
||||
"foo": cty.NullVal(cty.String),
|
||||
}),
|
||||
ExpectConfig: cty.ObjectVal(map[string]cty.Value{
|
||||
"foo": cty.StringVal("defaultfunc"),
|
||||
}),
|
||||
},
|
||||
{
|
||||
Name: "test default required",
|
||||
Schema: map[string]*schema.Schema{
|
||||
"foo": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
DefaultFunc: func() (interface{}, error) {
|
||||
return "defaultfunc", nil
|
||||
},
|
||||
},
|
||||
},
|
||||
ConfigVal: cty.ObjectVal(map[string]cty.Value{
|
||||
"foo": cty.NullVal(cty.String),
|
||||
}),
|
||||
ExpectConfig: cty.ObjectVal(map[string]cty.Value{
|
||||
"foo": cty.StringVal("defaultfunc"),
|
||||
}),
|
||||
},
|
||||
{
|
||||
Name: "test incorrect type",
|
||||
Schema: map[string]*schema.Schema{
|
||||
"foo": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
ConfigVal: cty.ObjectVal(map[string]cty.Value{
|
||||
"foo": cty.NumberIntVal(3),
|
||||
}),
|
||||
ExpectConfig: cty.ObjectVal(map[string]cty.Value{
|
||||
"foo": cty.StringVal("3"),
|
||||
}),
|
||||
},
|
||||
{
|
||||
Name: "test incorrect default type",
|
||||
Schema: map[string]*schema.Schema{
|
||||
"foo": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
Default: true,
|
||||
},
|
||||
},
|
||||
ConfigVal: cty.ObjectVal(map[string]cty.Value{
|
||||
"foo": cty.NullVal(cty.String),
|
||||
}),
|
||||
ExpectConfig: cty.ObjectVal(map[string]cty.Value{
|
||||
"foo": cty.StringVal("true"),
|
||||
}),
|
||||
},
|
||||
} {
|
||||
t.Run(tc.Name, func(t *testing.T) {
|
||||
server := &GRPCProviderServer{
|
||||
provider: &schema.Provider{
|
||||
Schema: tc.Schema,
|
||||
},
|
||||
}
|
||||
|
||||
block := schema.InternalMap(tc.Schema).CoreConfigSchema()
|
||||
|
||||
rawConfig, err := msgpack.Marshal(tc.ConfigVal, block.ImpliedType())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
testReq := &proto.PrepareProviderConfig_Request{
|
||||
Config: &proto.DynamicValue{
|
||||
Msgpack: rawConfig,
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := server.PrepareProviderConfig(nil, testReq)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if tc.ExpectError == "" && len(resp.Diagnostics) > 0 {
|
||||
for _, d := range resp.Diagnostics {
|
||||
if !strings.Contains(d.Summary, tc.ExpectError) {
|
||||
t.Fatalf("Unexpected error: %s/%s", d.Summary, d.Detail)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val, err := msgpack.Unmarshal(resp.PreparedConfig.Msgpack, block.ImpliedType())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if tc.ExpectConfig.GoString() != val.GoString() {
|
||||
t.Fatalf("\nexpected: %#v\ngot: %#v", tc.ExpectConfig, val)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue