Skip to content

Commit fc3c59a

Browse files
committed
use protobuffer to parse openapi for performance improvement
1 parent 403971c commit fc3c59a

File tree

1 file changed

+52
-28
lines changed

1 file changed

+52
-28
lines changed

kyaml/openapi/openapi.go

Lines changed: 52 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import (
1111
"reflect"
1212
"strings"
1313

14+
openapi_v2 "github.com/google/gnostic/openapiv2"
15+
"google.golang.org/protobuf/proto"
1416
"k8s.io/kube-openapi/pkg/validation/spec"
1517
"sigs.k8s.io/kustomize/kyaml/errors"
1618
"sigs.k8s.io/kustomize/kyaml/openapi/kubernetesapi"
@@ -50,6 +52,13 @@ type openapiData struct {
5052
schemaInit bool
5153
}
5254

55+
type format string
56+
57+
const (
58+
JsonOrYaml format = "jsonOrYaml"
59+
Proto format = "proto"
60+
)
61+
5362
// precomputedIsNamespaceScoped precomputes IsNamespaceScoped for known types. This avoids Schema creation,
5463
// which is expensive
5564
// The test output from TestIsNamespaceScopedPrecompute shows the expected map in go syntax,and can be copy and pasted
@@ -264,12 +273,14 @@ func schemaUsingField(object *yaml.RNode, field string) (*spec.Schema, error) {
264273

265274
// AddSchema parses s, and adds definitions from s to the global schema.
266275
func AddSchema(s []byte) error {
267-
return parse(s)
276+
return parse(s, JsonOrYaml)
268277
}
269278

270279
// ResetOpenAPI resets the openapi data to empty
271280
func ResetOpenAPI() {
272281
globalSchema = openapiData{}
282+
kubernetesOpenAPIVersion = ""
283+
customSchema = nil
273284
}
274285

275286
// AddDefinitions adds the definitions to the global schema.
@@ -592,26 +603,27 @@ func initSchema() {
592603
}
593604
globalSchema.schemaInit = true
594605

606+
// TODO(natasha41575): Accept proto-formatted schema files
595607
if customSchema != nil {
596-
err := parse(customSchema)
608+
err := parse(customSchema, JsonOrYaml)
597609
if err != nil {
598610
panic("invalid schema file")
599611
}
600-
if err = parse(kustomizationapi.MustAsset(kustomizationAPIAssetName)); err != nil {
601-
// this should never happen
602-
panic(err)
612+
} else {
613+
if kubernetesOpenAPIVersion == "" {
614+
parseBuiltinSchema(kubernetesOpenAPIDefaultVersion)
615+
} else {
616+
parseBuiltinSchema(kubernetesOpenAPIVersion)
603617
}
604-
return
605618
}
606619

607-
if kubernetesOpenAPIVersion == "" {
608-
parseBuiltinSchema(kubernetesOpenAPIDefaultVersion)
609-
} else {
610-
parseBuiltinSchema(kubernetesOpenAPIVersion)
620+
if err := parse(kustomizationapi.MustAsset(kustomizationAPIAssetName), JsonOrYaml); err != nil {
621+
// this should never happen
622+
panic(err)
611623
}
612624
}
613625

614-
// parseBuiltinSchema calls parse to parse the json schemas
626+
// parseBuiltinSchema calls parse to parse the json or proto schemas
615627
func parseBuiltinSchema(version string) {
616628
if globalSchema.noUseBuiltInSchema {
617629
// don't parse the built in schema
@@ -622,36 +634,45 @@ func parseBuiltinSchema(version string) {
622634
assetName := filepath.Join(
623635
"kubernetesapi",
624636
version,
625-
"swagger.json")
626-
627-
if err := parse(kubernetesapi.OpenAPIMustAsset[version](assetName)); err != nil {
628-
// this should never happen
629-
panic(err)
630-
}
637+
"swagger.pb")
631638

632-
if err := parse(kustomizationapi.MustAsset(kustomizationAPIAssetName)); err != nil {
639+
if err := parse(kubernetesapi.OpenAPIMustAsset[version](assetName), Proto); err != nil {
633640
// this should never happen
634641
panic(err)
635642
}
636643
}
637644

638-
// parse parses and indexes a single json schema
639-
func parse(b []byte) error {
645+
// parse parses and indexes a single json or proto schema
646+
func parse(b []byte, format format) error {
640647
var swagger spec.Swagger
641-
s := string(b)
642-
if len(s) > 0 && s[0] != '{' {
643-
var err error
644-
b, err = k8syaml.YAMLToJSON(b)
648+
switch {
649+
case format == Proto:
650+
doc := &openapi_v2.Document{}
651+
// We parse protobuf and get an openapi_v2.Document here.
652+
if err := proto.Unmarshal(b, doc); err != nil {
653+
return fmt.Errorf("openapi proto unmarshalling failed: %w", err)
654+
}
655+
// convert the openapi_v2.Document back to Swagger
656+
_, err := swagger.FromGnostic(doc)
645657
if err != nil {
646658
return errors.Wrap(err)
647659
}
660+
661+
case format == JsonOrYaml:
662+
if len(b) > 0 && b[0] != byte('{') {
663+
var err error
664+
b, err = k8syaml.YAMLToJSON(b)
665+
if err != nil {
666+
return errors.Wrap(err)
667+
}
668+
}
669+
if err := swagger.UnmarshalJSON(b); err != nil {
670+
return errors.Wrap(err)
671+
}
648672
}
649-
if err := swagger.UnmarshalJSON(b); err != nil {
650-
return errors.Wrap(err)
651-
}
673+
652674
AddDefinitions(swagger.Definitions)
653675
findNamespaceability(swagger.Paths)
654-
655676
return nil
656677
}
657678

@@ -695,6 +716,9 @@ func findNamespaceability(paths *spec.Paths) {
695716
}
696717

697718
func resolve(root interface{}, ref *spec.Ref) (*spec.Schema, error) {
719+
if s, ok := root.(*spec.Schema); ok && s == nil {
720+
return nil, nil
721+
}
698722
res, _, err := ref.GetPointer().Get(root)
699723
if err != nil {
700724
return nil, errors.Wrap(err)

0 commit comments

Comments
 (0)