Skip to content
This repository has been archived by the owner on Aug 11, 2021. It is now read-only.

Commit

Permalink
Fix crash from inconsistent list members - move null filtering outsid…
Browse files Browse the repository at this point in the history
…e the realm of cty
  • Loading branch information
alexsomesan committed May 26, 2020
1 parent 22db1cc commit 7a84b10
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 37 deletions.
53 changes: 26 additions & 27 deletions provider/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,38 +261,37 @@ func DeepUnknownVal(ty cty.Type) cty.Value {
}
}

func transformRemoveNulls(p cty.Path, v cty.Value) (cty.Value, error) {
if v.IsNull() {
return v, nil
}
t := v.Type()
switch {
case t.IsObjectType():
nvals := make(map[string]cty.Value, len(v.Type().AttributeTypes()))
for it := v.ElementIterator(); it.Next(); {
kv, ev := it.Element()
if !ev.IsNull() {
nvals[kv.AsString()] = ev
func mapRemoveNulls(in map[string]interface{}) map[string]interface{} {
for k, v := range in {
switch tv := v.(type) {
case []interface{}:
in[k] = sliceRemoveNulls(tv)
case map[string]interface{}:
in[k] = mapRemoveNulls(tv)
default:
if v == nil {
delete(in, k)
}
}
if len(nvals) == 0 {
return cty.NullVal(t), nil
}
return cty.ObjectVal(nvals), nil
case t.IsListType():
nvals := []cty.Value{}
for et := v.ElementIterator(); et.Next(); {
_, val := et.Element()
if !val.IsNull() {
nvals = append(nvals, val)
}
return in
}

func sliceRemoveNulls(in []interface{}) []interface{} {
s := []interface{}{}
for _, v := range in {
switch tv := v.(type) {
case []interface{}:
s = append(s, sliceRemoveNulls(tv))
case map[string]interface{}:
s = append(s, mapRemoveNulls(tv))
default:
if v != nil {
s = append(s, v)
}
}
if len(nvals) == 0 {
return cty.NullVal(t), nil
}
return cty.ListVal(nvals), nil
}
return v, nil
return s
}

func resourceTypeFromOpenAPI(gvk schema.GroupVersionKind) (cty.Type, error) {
Expand Down
62 changes: 62 additions & 0 deletions provider/resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package provider
import (
"errors"
"fmt"
"reflect"
"strings"
"testing"

Expand Down Expand Up @@ -433,3 +434,64 @@ func TestTypeForPath(t *testing.T) {
)
}
}

func TestRemoveNulls(t *testing.T) {
samples := []struct {
in map[string]interface{}
out map[string]interface{}
}{
{
in: map[string]interface{}{
"foo": nil,
},
out: map[string]interface{}{},
},
{
in: map[string]interface{}{
"foo": nil,
"bar": "test",
},
out: map[string]interface{}{
"bar": "test",
},
},
{
in: map[string]interface{}{
"foo": nil,
"bar": []interface{}{nil, "test"},
},
out: map[string]interface{}{
"bar": []interface{}{"test"},
},
},
{
in: map[string]interface{}{
"foo": nil,
"bar": []interface{}{
map[string]interface{}{
"some": nil,
"other": "data",
},
"test",
},
},
out: map[string]interface{}{
"bar": []interface{}{
map[string]interface{}{
"other": "data",
},
"test",
},
},
},
}

for i, s := range samples {
t.Run(fmt.Sprintf("sample%d", i+1), func(t *testing.T) {
o := mapRemoveNulls(s.in)
if !reflect.DeepEqual(s.out, o) {
t.Fatal("sample and output are not equal")
}
})
}
}
13 changes: 3 additions & 10 deletions provider/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,6 @@ func (s *RawProviderServer) Configure(ctx context.Context, req *tfplugin5.Config
ssp := providerConfig.GetAttr("server_side_planning")

ps[SSPlanning] = ssp.True()
Dlog.Printf("[Configure] SSP %s\n", spew.Sdump(ssp))
return response, nil
}

Expand Down Expand Up @@ -362,19 +361,13 @@ func (s *RawProviderServer) ApplyResourceChange(ctx context.Context, req *tfplug
return resp, fmt.Errorf("failed to determine resource type ID: %s", err)
}

// remove null or empty attributes - the API doesn't appreciate requests that include them
so, err := cty.Transform(o, transformRemoveNulls)

if err != nil {
return resp, err
}

mi, err := CtyObjectToUnstructured(&so)
mi, err := CtyObjectToUnstructured(&o)
if err != nil {
return resp, err
}

uo := unstructured.Unstructured{Object: mi}
// remove null attributes - the API doesn't appreciate requests that include them
uo := unstructured.Unstructured{Object: mapRemoveNulls(mi)}
ns, err := IsResourceNamespaced(gvr)
if err != nil {
return resp, err
Expand Down

0 comments on commit 7a84b10

Please sign in to comment.