Refactor openAPI

Refactor global openapi
This commit is contained in:
Phani Teja Marupaka
2020-11-10 12:50:24 -08:00
parent b2ba82a0bd
commit b6a4dd446a
27 changed files with 178 additions and 503 deletions

View File

@@ -70,23 +70,13 @@ const Definitions = "definitions"
// The returned clean function is a no-op on error, or else it's a function
// that the caller should use to remove the added openAPI definitions from
// global schema
func AddSchemaFromFile(path string) (func(), error) {
func SchemaFromFile(path string) (*spec.Schema, error) {
object, err := parseOpenAPI(path)
if err != nil {
return func() {}, err
return nil, err
}
defs, err := definitionRefsFromRNode(object)
if err != nil {
return func() {}, err
}
clean := func() {
for _, def := range defs {
delete(globalSchema.schema.Definitions, def)
}
}
return clean, addSchemaUsingField(object, SupplementaryOpenAPIFieldName)
return schemaUsingField(object, SupplementaryOpenAPIFieldName)
}
// DefinitionRefs returns the list of openAPI definition references present in the
@@ -121,27 +111,27 @@ func parseOpenAPI(openAPIPath string) (*yaml.RNode, error) {
object, err := yaml.Parse(string(b))
if err != nil {
return nil, err
return nil, errors.Errorf("invalid file %q: %v", openAPIPath, err)
}
return object, nil
}
// addSchemaUsingField parses the OpenAPI definitions from the specified field.
// If field is the empty string, use the whole document as OpenAPI.
func addSchemaUsingField(object *yaml.RNode, field string) error {
func schemaUsingField(object *yaml.RNode, field string) (*spec.Schema, error) {
if field != "" {
// get the field containing the openAPI
m := object.Field(field)
if m.IsNilOrEmpty() {
// doesn't contain openAPI definitions
return nil
return nil, nil
}
object = m.Value
}
oAPI, err := object.String()
if err != nil {
return err
return nil, err
}
// convert the yaml openAPI to a JSON string by unmarshalling it to an
@@ -149,19 +139,20 @@ func addSchemaUsingField(object *yaml.RNode, field string) error {
var o interface{}
err = yaml.Unmarshal([]byte(oAPI), &o)
if err != nil {
return err
return nil, err
}
j, err := json.Marshal(o)
if err != nil {
return err
return nil, err
}
// add the json schema to the global schema
err = AddSchema(j)
var sc spec.Schema
err = sc.UnmarshalJSON(j)
if err != nil {
return err
return nil, err
}
return nil
return &sc, nil
}
// AddSchema parses s, and adds definitions from s to the global schema.
@@ -225,8 +216,8 @@ func toTypeMeta(ext interface{}) (yaml.TypeMeta, bool) {
}
// Resolve resolves the reference against the global schema
func Resolve(ref *spec.Ref) (*spec.Schema, error) {
return resolve(Schema(), ref)
func Resolve(ref *spec.Ref, schema *spec.Schema) (*spec.Schema, error) {
return resolve(schema, ref)
}
// Schema returns the global schema
@@ -236,13 +227,13 @@ func Schema() *spec.Schema {
// GetSchema parses s into a ResourceSchema, resolving References within the
// global schema.
func GetSchema(s string) (*ResourceSchema, error) {
func GetSchema(s string, schema *spec.Schema) (*ResourceSchema, error) {
var sc spec.Schema
if err := sc.UnmarshalJSON([]byte(s)); err != nil {
return nil, errors.Wrap(err)
}
if sc.Ref.String() != "" {
r, err := Resolve(&sc.Ref)
r, err := Resolve(&sc.Ref, schema)
if err != nil {
return nil, errors.Wrap(err)
}
@@ -287,7 +278,7 @@ func (rs *ResourceSchema) Elements() *ResourceSchema {
}
s := *rs.Schema.Items.Schema
for s.Ref.String() != "" {
sc, e := Resolve(&s.Ref)
sc, e := Resolve(&s.Ref, Schema())
if e != nil {
return nil
}
@@ -339,7 +330,7 @@ func (rs *ResourceSchema) Field(field string) *ResourceSchema {
// resolve the reference to the Schema if the Schema has one
for s.Ref.String() != "" {
sc, e := Resolve(&s.Ref)
sc, e := Resolve(&s.Ref, Schema())
if e != nil {
return nil
}

View File

@@ -20,7 +20,7 @@ func TestAddSchema(t *testing.T) {
if !assert.NoError(t, err) {
t.FailNow()
}
s, err := GetSchema(`{"$ref": "#/definitions/io.k8s.config.setters.replicas"}`)
s, err := GetSchema(`{"$ref": "#/definitions/io.k8s.config.setters.replicas"}`, Schema())
if !assert.Greater(t, len(globalSchema.schema.Definitions), 200) {
t.FailNow()
}
@@ -31,26 +31,6 @@ func TestAddSchema(t *testing.T) {
fmt.Sprintf("%v", s.Schema.Extensions))
}
func TestNoUseBuiltInSchema_AddSchema(t *testing.T) {
// reset package vars
globalSchema = openapiData{}
SuppressBuiltInSchemaUse()
err := AddSchema(additionalSchema)
if !assert.NoError(t, err) {
t.FailNow()
}
s, err := GetSchema(`{"$ref": "#/definitions/io.k8s.config.setters.replicas"}`)
if !assert.Equal(t, len(globalSchema.schema.Definitions), 1) {
t.FailNow()
}
if !assert.NoError(t, err) {
t.FailNow()
}
assert.Equal(t, `map[x-kustomize:map[setBy:Jane setter:map[name:replicas value:5]]]`,
fmt.Sprintf("%v", s.Schema.Extensions))
}
var additionalSchema = []byte(`
{
"definitions": {
@@ -124,7 +104,7 @@ func TestSchemaForResourceType(t *testing.T) {
}
}
func TestAddSchemaFromFile(t *testing.T) {
func TestSchemaFromFile(t *testing.T) {
ResetOpenAPI()
inputyaml := `
openAPI:
@@ -143,93 +123,23 @@ openAPI:
t.FailNow()
}
clean, err := AddSchemaFromFile(f.Name())
sc, err := SchemaFromFile(f.Name())
if !assert.NoError(t, err) {
t.FailNow()
}
defer clean()
s, err := GetSchema(`{"$ref": "#/definitions/io.k8s.cli.setters.image-name"}`)
s, err := GetSchema(`{"$ref": "#/definitions/io.k8s.cli.setters.image-name"}`, sc)
if !assert.NoError(t, err) {
t.FailNow()
}
if !assert.Greater(t, len(globalSchema.schema.Definitions), 200) {
if !assert.Greater(t, len(sc.Definitions), 0) {
t.FailNow()
}
assert.Equal(t, `map[x-k8s-cli:map[setter:map[name:image-name value:nginx]]]`,
fmt.Sprintf("%v", s.Schema.Extensions))
}
func TestDeleteSchemaInFile(t *testing.T) {
ResetOpenAPI()
inputyaml := `
openAPI:
definitions:
io.k8s.cli.setters.image-name:
x-k8s-cli:
setter:
name: image-name
value: "nginx"
`
f, err := ioutil.TempFile("", "openapi-")
if !assert.NoError(t, err) {
t.FailNow()
}
if !assert.NoError(t, ioutil.WriteFile(f.Name(), []byte(inputyaml), 0600)) {
t.FailNow()
}
clean, err := AddSchemaFromFile(f.Name())
if !assert.NoError(t, err) {
t.FailNow()
}
s, err := GetSchema(`{"$ref": "#/definitions/io.k8s.cli.setters.image-name"}`)
if !assert.NoError(t, err) {
t.FailNow()
}
if !assert.Greater(t, len(globalSchema.schema.Definitions), 200) {
t.FailNow()
}
assert.Equal(t, `map[x-k8s-cli:map[setter:map[name:image-name value:nginx]]]`,
fmt.Sprintf("%v", s.Schema.Extensions))
clean()
_, err = GetSchema(`{"$ref": "#/definitions/io.k8s.cli.setters.image-name"}`)
if !assert.Error(t, err) {
t.FailNow()
}
if !assert.Equal(t, `object has no key "io.k8s.cli.setters.image-name"`, err.Error()) {
t.FailNow()
}
}
func TestDeleteSchemaInFileNoDefs(t *testing.T) {
ResetOpenAPI()
inputyaml := `
openAPI:
definitions:
`
f, err := ioutil.TempFile("", "openapi-")
if !assert.NoError(t, err) {
t.FailNow()
}
if !assert.NoError(t, ioutil.WriteFile(f.Name(), []byte(inputyaml), 0600)) {
t.FailNow()
}
clean, err := AddSchemaFromFile(f.Name())
if !assert.NoError(t, err) {
t.FailNow()
}
defer clean()
}
func TestPopulateDefsInOpenAPI_Substitution(t *testing.T) {
ResetOpenAPI()
inputyaml := `
@@ -265,18 +175,17 @@ openAPI:
t.FailNow()
}
clean, err := AddSchemaFromFile(f.Name())
sc, err := SchemaFromFile(f.Name())
if !assert.NoError(t, err) {
t.FailNow()
}
defer clean()
s, err := GetSchema(`{"$ref": "#/definitions/io.k8s.cli.substitutions.image"}`)
s, err := GetSchema(`{"$ref": "#/definitions/io.k8s.cli.substitutions.image"}`, sc)
if !assert.NoError(t, err) {
t.FailNow()
}
if !assert.Greater(t, len(globalSchema.schema.Definitions), 200) {
if !assert.Equal(t, len(sc.Definitions), 3) {
t.FailNow()
}
@@ -301,13 +210,12 @@ kind: Example
t.FailNow()
}
clean, err := AddSchemaFromFile(f.Name())
sc, err := SchemaFromFile(f.Name())
if !assert.NoError(t, err) {
t.FailNow()
}
defer clean()
if !assert.Equal(t, len(globalSchema.schema.Definitions), 0) {
if !assert.Nil(t, sc) {
t.FailNow()
}
}