Skip to content

Commit 9dfedd8

Browse files
authored
Merge pull request #1 from alexsomesan/cache_stackdepth
Exception for JSONSchemaProps / partial type cache / limit recursion depth
2 parents 4021317 + 675c849 commit 9dfedd8

File tree

3 files changed

+60
-11
lines changed

3 files changed

+60
-11
lines changed

foundry/foundry.go

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ import (
44
"encoding/json"
55
"errors"
66
"fmt"
7+
"log"
78
"strings"
89

910
"github.com/getkin/kin-openapi/openapi2"
1011
"github.com/getkin/kin-openapi/openapi3"
1112
"github.com/hashicorp/go-cty/cty"
13+
"github.com/mitchellh/hashstructure"
1214
)
1315

1416
// NewFoundryFromSpecV2 creates a new cty.Type foundry from an OpenAPI v2 spec document
@@ -24,7 +26,11 @@ func NewFoundryFromSpecV2(spec []byte) (Foundry, error) {
2426
return nil, fmt.Errorf("failed to parse spec: %s", err)
2527
}
2628

27-
f := foapiv2{&swg}
29+
f := foapiv2{
30+
swagger: &swg,
31+
typeCache: make(map[uint64]cty.Type),
32+
recursionDepth: 50, // arbitrarily large number - a type this big will likely kill Terraform anyway
33+
}
2834
d := f.swagger.Definitions
2935
if d == nil || len(d) == 0 {
3036
return nil, errors.New("spec has no type information")
@@ -39,7 +45,9 @@ type Foundry interface {
3945
}
4046

4147
type foapiv2 struct {
42-
swagger *openapi2.Swagger
48+
swagger *openapi2.Swagger
49+
typeCache map[uint64]cty.Type
50+
recursionDepth uint64
4351
}
4452

4553
// GetTypeById looks up a type by its fully qualified ID in the Definitions sections of
@@ -60,7 +68,7 @@ func (f foapiv2) GetTypeByID(id string) (cty.Type, error) {
6068
return cty.NilType, fmt.Errorf("failed to resolve schema: %s", err)
6169
}
6270

63-
return f.getTypeFromSchema(sch)
71+
return f.getTypeFromSchema(sch, 0)
6472
}
6573

6674
func (f foapiv2) resolveSchemaRef(ref *openapi3.SchemaRef) (*openapi3.Schema, error) {
@@ -77,6 +85,11 @@ func (f foapiv2) resolveSchemaRef(ref *openapi3.SchemaRef) (*openapi3.Schema, er
7785
Type: "integer",
7886
}
7987
return &t, nil
88+
case "io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps":
89+
t := openapi3.Schema{
90+
Type: "",
91+
}
92+
return &t, nil
8093
}
8194

8295
nref, ok := f.swagger.Definitions[sid]
@@ -91,10 +104,27 @@ func (f foapiv2) resolveSchemaRef(ref *openapi3.SchemaRef) (*openapi3.Schema, er
91104
return f.resolveSchemaRef(nref)
92105
}
93106

94-
func (f foapiv2) getTypeFromSchema(elem *openapi3.Schema) (cty.Type, error) {
107+
func (f foapiv2) getTypeFromSchema(elem *openapi3.Schema, stackdepth uint64) (cty.Type, error) {
108+
if stackdepth > f.recursionDepth {
109+
log.Println("at stack depth")
110+
// this is a hack to overcome the inability to express recursion in cty
111+
return cty.DynamicPseudoType, nil
112+
}
113+
log.Printf("stack depth: %d\n", stackdepth)
114+
95115
if elem == nil {
96116
return cty.NilType, errors.New("nil type")
97117
}
118+
h, herr := hashstructure.Hash(elem, nil)
119+
120+
var t cty.Type
121+
122+
// check if type is in cache
123+
if herr == nil {
124+
if t, ok := f.typeCache[h]; ok {
125+
return t, nil
126+
}
127+
}
98128

99129
switch elem.Type {
100130

@@ -109,29 +139,41 @@ func (f foapiv2) getTypeFromSchema(elem *openapi3.Schema) (cty.Type, error) {
109139
if err != nil {
110140
return cty.NilType, fmt.Errorf("failed to resolve schema: %s", err)
111141
}
112-
pType, err := f.getTypeFromSchema(schema)
142+
pType, err := f.getTypeFromSchema(schema, stackdepth+1)
113143
if err != nil {
114144
return cty.NilType, err
115145
}
116146
atts[p] = pType
117147
}
118-
return cty.Object(atts), nil
148+
t = cty.Object(atts)
149+
if herr == nil {
150+
f.typeCache[h] = t
151+
}
152+
return t, nil
119153

120154
case elem.Properties == nil && elem.AdditionalProperties != nil:
121155
// this is how OpenAPI defines associative arrays
122156
s, err := f.resolveSchemaRef(elem.AdditionalProperties)
123157
if err != nil {
124158
return cty.NilType, fmt.Errorf("failed to resolve schema: %s", err)
125159
}
126-
pt, err := f.getTypeFromSchema(s)
160+
pt, err := f.getTypeFromSchema(s, stackdepth+1)
127161
if err != nil {
128162
return cty.NilType, err
129163
}
130-
return cty.Map(pt), nil
164+
t = cty.Map(pt)
165+
if herr == nil {
166+
f.typeCache[h] = t
167+
}
168+
return t, nil
131169

132170
case elem.Properties == nil && elem.AdditionalProperties == nil:
133171
// this is a strange case, encountered with io.k8s.apimachinery.pkg.apis.meta.v1.FieldsV1
134-
return cty.DynamicPseudoType, nil
172+
t = cty.DynamicPseudoType
173+
if herr == nil {
174+
f.typeCache[h] = t
175+
}
176+
return t, nil
135177

136178
}
137179

@@ -140,11 +182,15 @@ func (f foapiv2) getTypeFromSchema(elem *openapi3.Schema) (cty.Type, error) {
140182
if err != nil {
141183
return cty.NilType, fmt.Errorf("failed to resolve schema for items: %s", err)
142184
}
143-
t, err := f.getTypeFromSchema(it)
185+
t, err := f.getTypeFromSchema(it, stackdepth+1)
144186
if err != nil {
145187
return cty.NilType, err
146188
}
147-
return cty.List(t), nil
189+
t = cty.List(t)
190+
if herr == nil {
191+
f.typeCache[h] = t
192+
}
193+
return t, nil
148194

149195
case "string":
150196
return cty.String, nil

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ require (
66
github.com/davecgh/go-spew v1.1.1
77
github.com/getkin/kin-openapi v0.4.0
88
github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320
9+
github.com/mitchellh/hashstructure v1.0.0
910
)

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
1616
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
1717
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
1818
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
19+
github.com/mitchellh/hashstructure v1.0.0 h1:ZkRJX1CyOoTkar7p/mLS5TZU4nJ1Rn/F8u9dGS02Q3Y=
20+
github.com/mitchellh/hashstructure v1.0.0/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ=
1921
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
2022
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
2123
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=

0 commit comments

Comments
 (0)