@@ -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.
266275func AddSchema (s []byte ) error {
267- return parse (s )
276+ return parse (s , JsonOrYaml )
268277}
269278
270279// ResetOpenAPI resets the openapi data to empty
271280func 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
615627func 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
697718func 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