Skip to content

Commit

Permalink
use protobuffer to parse openapi for performance improvement
Browse files Browse the repository at this point in the history
  • Loading branch information
natasha41575 committed Apr 15, 2022
1 parent 403971c commit fc3c59a
Showing 1 changed file with 52 additions and 28 deletions.
80 changes: 52 additions & 28 deletions kyaml/openapi/openapi.go
Expand Up @@ -11,6 +11,8 @@ import (
"reflect"
"strings"

openapi_v2 "github.com/google/gnostic/openapiv2"
"google.golang.org/protobuf/proto"
"k8s.io/kube-openapi/pkg/validation/spec"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/openapi/kubernetesapi"
Expand Down Expand Up @@ -50,6 +52,13 @@ type openapiData struct {
schemaInit bool
}

type format string

const (
JsonOrYaml format = "jsonOrYaml"
Proto format = "proto"
)

// precomputedIsNamespaceScoped precomputes IsNamespaceScoped for known types. This avoids Schema creation,
// which is expensive
// The test output from TestIsNamespaceScopedPrecompute shows the expected map in go syntax,and can be copy and pasted
Expand Down Expand Up @@ -264,12 +273,14 @@ func schemaUsingField(object *yaml.RNode, field string) (*spec.Schema, error) {

// AddSchema parses s, and adds definitions from s to the global schema.
func AddSchema(s []byte) error {
return parse(s)
return parse(s, JsonOrYaml)
}

// ResetOpenAPI resets the openapi data to empty
func ResetOpenAPI() {
globalSchema = openapiData{}
kubernetesOpenAPIVersion = ""
customSchema = nil
}

// AddDefinitions adds the definitions to the global schema.
Expand Down Expand Up @@ -592,26 +603,27 @@ func initSchema() {
}
globalSchema.schemaInit = true

// TODO(natasha41575): Accept proto-formatted schema files
if customSchema != nil {
err := parse(customSchema)
err := parse(customSchema, JsonOrYaml)
if err != nil {
panic("invalid schema file")
}
if err = parse(kustomizationapi.MustAsset(kustomizationAPIAssetName)); err != nil {
// this should never happen
panic(err)
} else {
if kubernetesOpenAPIVersion == "" {
parseBuiltinSchema(kubernetesOpenAPIDefaultVersion)
} else {
parseBuiltinSchema(kubernetesOpenAPIVersion)
}
return
}

if kubernetesOpenAPIVersion == "" {
parseBuiltinSchema(kubernetesOpenAPIDefaultVersion)
} else {
parseBuiltinSchema(kubernetesOpenAPIVersion)
if err := parse(kustomizationapi.MustAsset(kustomizationAPIAssetName), JsonOrYaml); err != nil {
// this should never happen
panic(err)
}
}

// parseBuiltinSchema calls parse to parse the json schemas
// parseBuiltinSchema calls parse to parse the json or proto schemas
func parseBuiltinSchema(version string) {
if globalSchema.noUseBuiltInSchema {
// don't parse the built in schema
Expand All @@ -622,36 +634,45 @@ func parseBuiltinSchema(version string) {
assetName := filepath.Join(
"kubernetesapi",
version,
"swagger.json")

if err := parse(kubernetesapi.OpenAPIMustAsset[version](assetName)); err != nil {
// this should never happen
panic(err)
}
"swagger.pb")

if err := parse(kustomizationapi.MustAsset(kustomizationAPIAssetName)); err != nil {
if err := parse(kubernetesapi.OpenAPIMustAsset[version](assetName), Proto); err != nil {
// this should never happen
panic(err)
}
}

// parse parses and indexes a single json schema
func parse(b []byte) error {
// parse parses and indexes a single json or proto schema
func parse(b []byte, format format) error {
var swagger spec.Swagger
s := string(b)
if len(s) > 0 && s[0] != '{' {
var err error
b, err = k8syaml.YAMLToJSON(b)
switch {
case format == Proto:
doc := &openapi_v2.Document{}
// We parse protobuf and get an openapi_v2.Document here.
if err := proto.Unmarshal(b, doc); err != nil {
return fmt.Errorf("openapi proto unmarshalling failed: %w", err)
}
// convert the openapi_v2.Document back to Swagger
_, err := swagger.FromGnostic(doc)
if err != nil {
return errors.Wrap(err)
}

case format == JsonOrYaml:
if len(b) > 0 && b[0] != byte('{') {
var err error
b, err = k8syaml.YAMLToJSON(b)
if err != nil {
return errors.Wrap(err)
}
}
if err := swagger.UnmarshalJSON(b); err != nil {
return errors.Wrap(err)
}
}
if err := swagger.UnmarshalJSON(b); err != nil {
return errors.Wrap(err)
}

AddDefinitions(swagger.Definitions)
findNamespaceability(swagger.Paths)

return nil
}

Expand Down Expand Up @@ -695,6 +716,9 @@ func findNamespaceability(paths *spec.Paths) {
}

func resolve(root interface{}, ref *spec.Ref) (*spec.Schema, error) {
if s, ok := root.(*spec.Schema); ok && s == nil {
return nil, nil
}
res, _, err := ref.GetPointer().Get(root)
if err != nil {
return nil, errors.Wrap(err)
Expand Down

0 comments on commit fc3c59a

Please sign in to comment.