mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-30 06:54:01 +00:00
Merge pull request #46803 from apelisse/new-download-openapi
Automatic merge from submit-queue (batch tested with PRs 43558, 48261, 42376, 46803, 47058) OpenAPI downloads protobuf rather than Json **What this PR does / why we need it**: The current implementation of the OpenAPI getter fetches the swagger in a Json format from the apiserver. The Json file is big (~1.7mb), which means that it takes a long time to download, and then a long time to parse. Because that is going to be needed on each `kubectl` run later, we want this to be as fast as possible. The apiserver has been modified to be able to return a protobuf version of the swagger, which this patch intends to use. Note that there is currently no piece of code that exists that allows us to go from the protobuf version of the file, back into Json and/or `spec.Swagger`. Because the protobuf is not very different (but significantly different enough that it can't be translated), I've updated the code to use `openapi_v2.Document` (the protobuf type) everywhere rather than `spec.Swagger`. The behavior should be identical though. There are more changes that are coming in follow-up pull-requests: using the gzip version (also provided by the new apiserver) to even further reduce the size of the downloaded content, and use the HTTP Etag cache mechanism to completely get rid of recurrent fetch requests. I'm currently working on these two features. **Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: partly #38637 **Special notes for your reviewer**: **Release note**: ```release-note NONE ```
This commit is contained in:
commit
9c74026ffc
@ -46,8 +46,8 @@ go_library(
|
||||
"//pkg/version:go_default_library",
|
||||
"//vendor/github.com/emicklei/go-restful-swagger12:go_default_library",
|
||||
"//vendor/github.com/evanphx/json-patch:go_default_library",
|
||||
"//vendor/github.com/go-openapi/spec:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library",
|
||||
"//vendor/github.com/spf13/cobra:go_default_library",
|
||||
"//vendor/github.com/spf13/pflag:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
@ -108,7 +108,7 @@ go_test(
|
||||
"//pkg/kubectl/resource:go_default_library",
|
||||
"//pkg/util/exec:go_default_library",
|
||||
"//vendor/github.com/emicklei/go-restful-swagger12:go_default_library",
|
||||
"//vendor/github.com/go-openapi/spec:go_default_library",
|
||||
"//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library",
|
||||
"//vendor/github.com/stretchr/testify/assert:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
|
||||
|
@ -25,8 +25,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/emicklei/go-restful-swagger12"
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/golang/glog"
|
||||
"github.com/googleapis/gnostic/OpenAPIv2"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
@ -237,7 +237,7 @@ func (d *CachedDiscoveryClient) SwaggerSchema(version schema.GroupVersion) (*swa
|
||||
return d.delegate.SwaggerSchema(version)
|
||||
}
|
||||
|
||||
func (d *CachedDiscoveryClient) OpenAPISchema() (*spec.Swagger, error) {
|
||||
func (d *CachedDiscoveryClient) OpenAPISchema() (*openapi_v2.Document, error) {
|
||||
return d.delegate.OpenAPISchema()
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/emicklei/go-restful-swagger12"
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/googleapis/gnostic/OpenAPIv2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
@ -171,7 +171,7 @@ func (c *fakeDiscoveryClient) SwaggerSchema(version schema.GroupVersion) (*swagg
|
||||
return &swagger.ApiDeclaration{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeDiscoveryClient) OpenAPISchema() (*spec.Swagger, error) {
|
||||
func (c *fakeDiscoveryClient) OpenAPISchema() (*openapi_v2.Document, error) {
|
||||
c.openAPICalls = c.openAPICalls + 1
|
||||
return &spec.Swagger{}, nil
|
||||
return &openapi_v2.Document{}, nil
|
||||
}
|
||||
|
@ -22,6 +22,8 @@ go_library(
|
||||
"//pkg/version:go_default_library",
|
||||
"//vendor/github.com/go-openapi/spec:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library",
|
||||
"//vendor/gopkg.in/yaml.v2:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/client-go/discovery:go_default_library",
|
||||
@ -41,12 +43,14 @@ go_test(
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/kubectl/cmd/util/openapi:go_default_library",
|
||||
"//vendor/github.com/go-openapi/loads:go_default_library",
|
||||
"//vendor/github.com/go-openapi/spec:go_default_library",
|
||||
"//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library",
|
||||
"//vendor/github.com/googleapis/gnostic/compiler:go_default_library",
|
||||
"//vendor/github.com/onsi/ginkgo:go_default_library",
|
||||
"//vendor/github.com/onsi/ginkgo/config:go_default_library",
|
||||
"//vendor/github.com/onsi/ginkgo/types:go_default_library",
|
||||
"//vendor/github.com/onsi/gomega:go_default_library",
|
||||
"//vendor/gopkg.in/yaml.v2:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
],
|
||||
)
|
||||
|
@ -20,8 +20,10 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/spec"
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/googleapis/gnostic/OpenAPIv2"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
@ -98,7 +100,7 @@ type Kind struct {
|
||||
PrimitiveType string
|
||||
|
||||
// Extensions are openapi extensions for the object definition.
|
||||
Extensions spec.Extensions
|
||||
Extensions map[string]interface{}
|
||||
|
||||
// Fields are the fields defined for this Kind
|
||||
Fields map[string]Type
|
||||
@ -130,21 +132,45 @@ type Type struct {
|
||||
// Extensions are extensions for this field and may contain
|
||||
// metadata from the types.go struct field tags.
|
||||
// e.g. contains patchStrategy, patchMergeKey, etc
|
||||
Extensions spec.Extensions
|
||||
Extensions map[string]interface{}
|
||||
}
|
||||
|
||||
func vendorExtensionToMap(e []*openapi_v2.NamedAny) map[string]interface{} {
|
||||
var values map[string]interface{}
|
||||
|
||||
for _, na := range e {
|
||||
if na.GetName() == "" || na.GetValue() == nil {
|
||||
continue
|
||||
}
|
||||
if na.GetValue().GetYaml() == "" {
|
||||
continue
|
||||
}
|
||||
var value interface{}
|
||||
err := yaml.Unmarshal([]byte(na.GetValue().GetYaml()), &value)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if values == nil {
|
||||
values = make(map[string]interface{})
|
||||
}
|
||||
values[na.GetName()] = value
|
||||
}
|
||||
|
||||
return values
|
||||
}
|
||||
|
||||
// NewOpenAPIData parses the resource definitions in openapi data by groupversionkind and name
|
||||
func NewOpenAPIData(s *spec.Swagger) (*Resources, error) {
|
||||
func NewOpenAPIData(doc *openapi_v2.Document) (*Resources, error) {
|
||||
o := &Resources{
|
||||
GroupVersionKindToName: map[schema.GroupVersionKind]string{},
|
||||
NameToDefinition: map[string]Kind{},
|
||||
}
|
||||
// Parse and index definitions by name
|
||||
for name, d := range s.Definitions {
|
||||
definition := o.parseDefinition(name, d)
|
||||
o.NameToDefinition[name] = definition
|
||||
for _, ns := range doc.GetDefinitions().GetAdditionalProperties() {
|
||||
definition := o.parseDefinition(ns.GetName(), ns.GetValue())
|
||||
o.NameToDefinition[ns.GetName()] = definition
|
||||
if len(definition.GroupVersionKind.Kind) > 0 {
|
||||
o.GroupVersionKindToName[definition.GroupVersionKind] = name
|
||||
o.GroupVersionKindToName[definition.GroupVersionKind] = ns.GetName()
|
||||
}
|
||||
}
|
||||
|
||||
@ -185,12 +211,12 @@ func (o *Resources) getTypeNames(elem Type) []string {
|
||||
return t
|
||||
}
|
||||
|
||||
func (o *Resources) parseDefinition(name string, s spec.Schema) Kind {
|
||||
func (o *Resources) parseDefinition(name string, s *openapi_v2.Schema) Kind {
|
||||
gvk, err := o.getGroupVersionKind(s)
|
||||
value := Kind{
|
||||
Name: name,
|
||||
GroupVersionKind: gvk,
|
||||
Extensions: s.Extensions,
|
||||
Extensions: vendorExtensionToMap(s.GetVendorExtension()),
|
||||
Fields: map[string]Type{},
|
||||
}
|
||||
if err != nil {
|
||||
@ -202,13 +228,13 @@ func (o *Resources) parseDefinition(name string, s spec.Schema) Kind {
|
||||
if o.isPrimitive(s) {
|
||||
value.PrimitiveType = o.getTypeNameForField(s)
|
||||
}
|
||||
for fieldname, property := range s.Properties {
|
||||
value.Fields[fieldname] = o.parseField(property)
|
||||
for _, ns := range s.GetProperties().GetAdditionalProperties() {
|
||||
value.Fields[ns.GetName()] = o.parseField(ns.GetValue())
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func (o *Resources) parseField(s spec.Schema) Type {
|
||||
func (o *Resources) parseField(s *openapi_v2.Schema) Type {
|
||||
def := Type{
|
||||
TypeName: o.getTypeNameForField(s),
|
||||
IsPrimitive: o.isPrimitive(s),
|
||||
@ -225,14 +251,14 @@ func (o *Resources) parseField(s spec.Schema) Type {
|
||||
def.ElementType = &d
|
||||
}
|
||||
|
||||
def.Extensions = s.Extensions
|
||||
def.Extensions = vendorExtensionToMap(s.GetVendorExtension())
|
||||
|
||||
return def
|
||||
}
|
||||
|
||||
// isArray returns true if s is an array type.
|
||||
func (o *Resources) isArray(s spec.Schema) bool {
|
||||
if len(s.Properties) > 0 {
|
||||
func (o *Resources) isArray(s *openapi_v2.Schema) bool {
|
||||
if len(s.GetProperties().GetAdditionalProperties()) > 0 {
|
||||
// Open API can have embedded type definitions, but Kubernetes doesn't generate these.
|
||||
// This should just be a sanity check against changing the format.
|
||||
return false
|
||||
@ -241,8 +267,8 @@ func (o *Resources) isArray(s spec.Schema) bool {
|
||||
}
|
||||
|
||||
// isMap returns true if s is a map type.
|
||||
func (o *Resources) isMap(s spec.Schema) bool {
|
||||
if len(s.Properties) > 0 {
|
||||
func (o *Resources) isMap(s *openapi_v2.Schema) bool {
|
||||
if len(s.GetProperties().GetAdditionalProperties()) > 0 {
|
||||
// Open API can have embedded type definitions, but Kubernetes doesn't generate these.
|
||||
// This should just be a sanity check against changing the format.
|
||||
return false
|
||||
@ -253,8 +279,8 @@ func (o *Resources) isMap(s spec.Schema) bool {
|
||||
// isPrimitive returns true if s is a primitive type
|
||||
// Note: For object references that represent primitive types - e.g. IntOrString - this will
|
||||
// be false, and the referenced Kind will have a non-empty "PrimitiveType".
|
||||
func (o *Resources) isPrimitive(s spec.Schema) bool {
|
||||
if len(s.Properties) > 0 {
|
||||
func (o *Resources) isPrimitive(s *openapi_v2.Schema) bool {
|
||||
if len(s.GetProperties().GetAdditionalProperties()) > 0 {
|
||||
// Open API can have embedded type definitions, but Kubernetes doesn't generate these.
|
||||
// This should just be a sanity check against changing the format.
|
||||
return false
|
||||
@ -266,96 +292,96 @@ func (o *Resources) isPrimitive(s spec.Schema) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (*Resources) getType(s spec.Schema) string {
|
||||
if len(s.Type) != 1 {
|
||||
func (*Resources) getType(s *openapi_v2.Schema) string {
|
||||
if len(s.GetType().GetValue()) != 1 {
|
||||
return ""
|
||||
}
|
||||
return strings.ToLower(s.Type[0])
|
||||
return strings.ToLower(s.GetType().GetValue()[0])
|
||||
}
|
||||
|
||||
func (o *Resources) getTypeNameForField(s spec.Schema) string {
|
||||
func (o *Resources) getTypeNameForField(s *openapi_v2.Schema) string {
|
||||
// Get the reference for complex types
|
||||
if o.isDefinitionReference(s) {
|
||||
return o.nameForDefinitionField(s)
|
||||
}
|
||||
// Recurse if type is array
|
||||
if o.isArray(s) {
|
||||
return fmt.Sprintf("%s array", o.getTypeNameForField(*s.Items.Schema))
|
||||
return fmt.Sprintf("%s array", o.getTypeNameForField(s.GetItems().GetSchema()[0]))
|
||||
}
|
||||
if o.isMap(s) {
|
||||
return fmt.Sprintf("%s map", o.getTypeNameForField(*s.AdditionalProperties.Schema))
|
||||
return fmt.Sprintf("%s map", o.getTypeNameForField(s.GetAdditionalProperties().GetSchema()))
|
||||
}
|
||||
|
||||
// Get the value for primitive types
|
||||
if o.isPrimitive(s) {
|
||||
return fmt.Sprintf("%s", s.Type[0])
|
||||
return fmt.Sprintf("%s", s.GetType().GetValue()[0])
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// isDefinitionReference returns true s is a complex type that should have a Kind.
|
||||
func (o *Resources) isDefinitionReference(s spec.Schema) bool {
|
||||
if len(s.Properties) > 0 {
|
||||
func (o *Resources) isDefinitionReference(s *openapi_v2.Schema) bool {
|
||||
if len(s.GetProperties().GetAdditionalProperties()) > 0 {
|
||||
// Open API can have embedded type definitions, but Kubernetes doesn't generate these.
|
||||
// This should just be a sanity check against changing the format.
|
||||
return false
|
||||
}
|
||||
if len(s.Type) > 0 {
|
||||
if len(s.GetType().GetValue()) > 0 {
|
||||
// Definition references won't have a type
|
||||
return false
|
||||
}
|
||||
|
||||
p := s.SchemaProps.Ref.GetPointer().String()
|
||||
return len(p) > 0 && strings.HasPrefix(p, "/definitions/")
|
||||
p := s.GetXRef()
|
||||
return len(p) > 0 && strings.HasPrefix(p, "#/definitions/")
|
||||
}
|
||||
|
||||
// getElementType returns the type of an element for arrays
|
||||
// returns an error if s is not an array.
|
||||
func (o *Resources) getElementType(s spec.Schema) (spec.Schema, error) {
|
||||
func (o *Resources) getElementType(s *openapi_v2.Schema) (*openapi_v2.Schema, error) {
|
||||
if !o.isArray(s) {
|
||||
return spec.Schema{}, fmt.Errorf("%v is not an array type", s.Type)
|
||||
return &openapi_v2.Schema{}, fmt.Errorf("%v is not an array type", o.getTypeNameForField(s))
|
||||
}
|
||||
return *s.Items.Schema, nil
|
||||
return s.GetItems().GetSchema()[0], nil
|
||||
}
|
||||
|
||||
// getElementType returns the type of an element for maps
|
||||
// getValueType returns the type of an element for maps
|
||||
// returns an error if s is not a map.
|
||||
func (o *Resources) getValueType(s spec.Schema) (spec.Schema, error) {
|
||||
func (o *Resources) getValueType(s *openapi_v2.Schema) (*openapi_v2.Schema, error) {
|
||||
if !o.isMap(s) {
|
||||
return spec.Schema{}, fmt.Errorf("%v is not an map type", s.Type)
|
||||
return &openapi_v2.Schema{}, fmt.Errorf("%v is not an map type", o.getTypeNameForField(s))
|
||||
}
|
||||
return *s.AdditionalProperties.Schema, nil
|
||||
return s.GetAdditionalProperties().GetSchema(), nil
|
||||
}
|
||||
|
||||
// nameForDefinitionField returns the definition name for the schema (field) if it is a complex type
|
||||
func (o *Resources) nameForDefinitionField(s spec.Schema) string {
|
||||
p := s.SchemaProps.Ref.GetPointer().String()
|
||||
func (o *Resources) nameForDefinitionField(s *openapi_v2.Schema) string {
|
||||
p := s.GetXRef()
|
||||
if len(p) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Strip the "definitions/" pieces of the reference
|
||||
return strings.Replace(p, "/definitions/", "", -1)
|
||||
return strings.Replace(p, "#/definitions/", "", -1)
|
||||
}
|
||||
|
||||
// getGroupVersionKind implements OpenAPIData
|
||||
// getGVK parses the gropuversionkind for a resource definition from the x-kubernetes
|
||||
// extensions
|
||||
// Expected format for s.Extensions: map[string][]map[string]string
|
||||
// map[x-kubernetes-group-version-kind:[map[Group:authentication.k8s.io Version:v1 Kind:TokenReview]]]
|
||||
func (o *Resources) getGroupVersionKind(s spec.Schema) (schema.GroupVersionKind, error) {
|
||||
func (o *Resources) getGroupVersionKind(s *openapi_v2.Schema) (schema.GroupVersionKind, error) {
|
||||
empty := schema.GroupVersionKind{}
|
||||
|
||||
extensionMap := vendorExtensionToMap(s.GetVendorExtension())
|
||||
// Get the extensions
|
||||
extList, f := s.Extensions[groupVersionKindExtensionKey]
|
||||
extList, f := extensionMap[groupVersionKindExtensionKey]
|
||||
if !f {
|
||||
return empty, fmt.Errorf("No %s extension present in %v", groupVersionKindExtensionKey, s.Extensions)
|
||||
return empty, fmt.Errorf("No %s extension present in %v", groupVersionKindExtensionKey, extensionMap)
|
||||
}
|
||||
|
||||
// Expect a empty of a list with 1 element
|
||||
extListCasted, ok := extList.([]interface{})
|
||||
if !ok {
|
||||
return empty, fmt.Errorf("%s extension has unexpected type %T in %s", groupVersionKindExtensionKey, extListCasted, s.Extensions)
|
||||
return empty, fmt.Errorf("%s extension has unexpected type %T in %s", groupVersionKindExtensionKey, extListCasted, extensionMap)
|
||||
}
|
||||
if len(extListCasted) == 0 {
|
||||
return empty, fmt.Errorf("No Group Version Kind found in %v", extListCasted)
|
||||
@ -366,9 +392,9 @@ func (o *Resources) getGroupVersionKind(s spec.Schema) (schema.GroupVersionKind,
|
||||
gvk := extListCasted[0]
|
||||
|
||||
// Expect a empty of a map with 3 entries
|
||||
gvkMap, ok := gvk.(map[string]interface{})
|
||||
gvkMap, ok := gvk.(map[interface{}]interface{})
|
||||
if !ok {
|
||||
return empty, fmt.Errorf("%s extension has unexpected type %T in %s", groupVersionKindExtensionKey, gvk, s.Extensions)
|
||||
return empty, fmt.Errorf("%s extension has unexpected type %T in %s", groupVersionKindExtensionKey, gvk, extList)
|
||||
}
|
||||
group, ok := gvkMap["group"].(string)
|
||||
if !ok {
|
||||
|
@ -187,7 +187,6 @@ func linkFiles(old, new string) error {
|
||||
|
||||
// registerBinaryEncodingTypes registers the types so they can be binary encoded by gob
|
||||
func registerBinaryEncodingTypes() {
|
||||
gob.Register(map[string]interface{}{})
|
||||
gob.Register(map[interface{}]interface{}{})
|
||||
gob.Register([]interface{}{})
|
||||
gob.Register(Resources{})
|
||||
}
|
||||
|
@ -23,8 +23,10 @@ import (
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"github.com/go-openapi/loads"
|
||||
"github.com/go-openapi/spec"
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/googleapis/gnostic/OpenAPIv2"
|
||||
"github.com/googleapis/gnostic/compiler"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
@ -220,7 +222,7 @@ type fakeOpenAPIClient struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (f *fakeOpenAPIClient) OpenAPISchema() (*spec.Swagger, error) {
|
||||
func (f *fakeOpenAPIClient) OpenAPISchema() (*openapi_v2.Document, error) {
|
||||
f.calls = f.calls + 1
|
||||
|
||||
if f.err != nil {
|
||||
@ -235,11 +237,11 @@ var data apiData
|
||||
|
||||
type apiData struct {
|
||||
sync.Once
|
||||
data *spec.Swagger
|
||||
data *openapi_v2.Document
|
||||
err error
|
||||
}
|
||||
|
||||
func (d *apiData) OpenAPISchema() (*spec.Swagger, error) {
|
||||
func (d *apiData) OpenAPISchema() (*openapi_v2.Document, error) {
|
||||
d.Do(func() {
|
||||
// Get the path to the swagger.json file
|
||||
wd, err := os.Getwd()
|
||||
@ -261,14 +263,18 @@ func (d *apiData) OpenAPISchema() (*spec.Swagger, error) {
|
||||
d.err = err
|
||||
return
|
||||
}
|
||||
// Load the openapi document
|
||||
doc, err := loads.Spec(specpath)
|
||||
spec, err := ioutil.ReadFile(specpath)
|
||||
if err != nil {
|
||||
d.err = err
|
||||
return
|
||||
}
|
||||
|
||||
d.data = doc.Spec()
|
||||
var info yaml.MapSlice
|
||||
err = yaml.Unmarshal(spec, &info)
|
||||
if err != nil {
|
||||
d.err = err
|
||||
return
|
||||
}
|
||||
d.data, d.err = openapi_v2.NewDocument(info, compiler.NewContext("$root", nil))
|
||||
})
|
||||
return d.data, d.err
|
||||
}
|
||||
|
@ -106,10 +106,6 @@
|
||||
"ImportPath": "github.com/ghodss/yaml",
|
||||
"Rev": "73d445a93680fa1a78ae23a5839bad48f32ba1ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/analysis",
|
||||
"Rev": "b44dc874b601d9e4e2f6e19140e794ba24bead3b"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/jsonpointer",
|
||||
"Rev": "46af16f9f7b149af66e5d1bd010e3574dc06de98"
|
||||
@ -118,10 +114,6 @@
|
||||
"ImportPath": "github.com/go-openapi/jsonreference",
|
||||
"Rev": "13c6e3589ad90f49bd3e3bbe2c2cb3d7a4142272"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/loads",
|
||||
"Rev": "18441dfa706d924a39a030ee2c3b1d8d81917b38"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/spec",
|
||||
"Rev": "6aced65f8501fe1217321abf0749d354824ba2ff"
|
||||
|
8
staging/src/k8s.io/apiserver/Godeps/Godeps.json
generated
8
staging/src/k8s.io/apiserver/Godeps/Godeps.json
generated
@ -326,10 +326,6 @@
|
||||
"ImportPath": "github.com/ghodss/yaml",
|
||||
"Rev": "73d445a93680fa1a78ae23a5839bad48f32ba1ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/analysis",
|
||||
"Rev": "b44dc874b601d9e4e2f6e19140e794ba24bead3b"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/jsonpointer",
|
||||
"Rev": "46af16f9f7b149af66e5d1bd010e3574dc06de98"
|
||||
@ -338,10 +334,6 @@
|
||||
"ImportPath": "github.com/go-openapi/jsonreference",
|
||||
"Rev": "13c6e3589ad90f49bd3e3bbe2c2cb3d7a4142272"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/loads",
|
||||
"Rev": "18441dfa706d924a39a030ee2c3b1d8d81917b38"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/spec",
|
||||
"Rev": "6aced65f8501fe1217321abf0749d354824ba2ff"
|
||||
|
36
staging/src/k8s.io/client-go/Godeps/Godeps.json
generated
36
staging/src/k8s.io/client-go/Godeps/Godeps.json
generated
@ -98,10 +98,6 @@
|
||||
"ImportPath": "github.com/ghodss/yaml",
|
||||
"Rev": "73d445a93680fa1a78ae23a5839bad48f32ba1ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/analysis",
|
||||
"Rev": "b44dc874b601d9e4e2f6e19140e794ba24bead3b"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/jsonpointer",
|
||||
"Rev": "46af16f9f7b149af66e5d1bd010e3574dc06de98"
|
||||
@ -110,10 +106,6 @@
|
||||
"ImportPath": "github.com/go-openapi/jsonreference",
|
||||
"Rev": "13c6e3589ad90f49bd3e3bbe2c2cb3d7a4142272"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/loads",
|
||||
"Rev": "18441dfa706d924a39a030ee2c3b1d8d81917b38"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/spec",
|
||||
"Rev": "6aced65f8501fe1217321abf0749d354824ba2ff"
|
||||
@ -142,10 +134,38 @@
|
||||
"ImportPath": "github.com/golang/protobuf/proto",
|
||||
"Rev": "4bd1920723d7b7c925de087aa32e2187708897f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/golang/protobuf/ptypes",
|
||||
"Rev": "4bd1920723d7b7c925de087aa32e2187708897f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/golang/protobuf/ptypes/any",
|
||||
"Rev": "4bd1920723d7b7c925de087aa32e2187708897f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/golang/protobuf/ptypes/duration",
|
||||
"Rev": "4bd1920723d7b7c925de087aa32e2187708897f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/golang/protobuf/ptypes/timestamp",
|
||||
"Rev": "4bd1920723d7b7c925de087aa32e2187708897f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/gofuzz",
|
||||
"Rev": "44d81051d367757e1c7c6a5a86423ece9afcf63c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/googleapis/gnostic/OpenAPIv2",
|
||||
"Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/googleapis/gnostic/compiler",
|
||||
"Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/googleapis/gnostic/extensions",
|
||||
"Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/golang-lru",
|
||||
"Rev": "a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4"
|
||||
|
@ -19,9 +19,9 @@ go_library(
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//vendor/github.com/emicklei/go-restful-swagger12:go_default_library",
|
||||
"//vendor/github.com/go-openapi/loads:go_default_library",
|
||||
"//vendor/github.com/go-openapi/spec:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/github.com/golang/protobuf/proto:go_default_library",
|
||||
"//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
||||
@ -46,7 +46,8 @@ go_test(
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//vendor/github.com/emicklei/go-restful-swagger12:go_default_library",
|
||||
"//vendor/github.com/go-openapi/spec:go_default_library",
|
||||
"//vendor/github.com/gogo/protobuf/proto:go_default_library",
|
||||
"//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library",
|
||||
"//vendor/github.com/stretchr/testify/assert:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
|
@ -24,9 +24,9 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/emicklei/go-restful-swagger12"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/googleapis/gnostic/OpenAPIv2"
|
||||
|
||||
"github.com/go-openapi/loads"
|
||||
"github.com/go-openapi/spec"
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@ -97,7 +97,7 @@ type SwaggerSchemaInterface interface {
|
||||
// OpenAPISchemaInterface has a method to retrieve the open API schema.
|
||||
type OpenAPISchemaInterface interface {
|
||||
// OpenAPISchema retrieves and parses the swagger API schema the server supports.
|
||||
OpenAPISchema() (*spec.Swagger, error)
|
||||
OpenAPISchema() (*openapi_v2.Document, error)
|
||||
}
|
||||
|
||||
// DiscoveryClient implements the functions that discover server-supported API groups,
|
||||
@ -375,19 +375,18 @@ func (d *DiscoveryClient) SwaggerSchema(version schema.GroupVersion) (*swagger.A
|
||||
return &schema, nil
|
||||
}
|
||||
|
||||
// OpenAPISchema fetches the open api schema using a rest client and parses the json.
|
||||
// Warning: this is very expensive (~1.2s)
|
||||
func (d *DiscoveryClient) OpenAPISchema() (*spec.Swagger, error) {
|
||||
data, err := d.restClient.Get().AbsPath("/swagger.json").Do().Raw()
|
||||
// OpenAPISchema fetches the open api schema using a rest client and parses the proto.
|
||||
func (d *DiscoveryClient) OpenAPISchema() (*openapi_v2.Document, error) {
|
||||
data, err := d.restClient.Get().AbsPath("/swagger-2.0.0.pb-v1").Do().Raw()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
msg := json.RawMessage(data)
|
||||
doc, err := loads.Analyzed(msg, "")
|
||||
document := &openapi_v2.Document{}
|
||||
err = proto.Unmarshal(data, document)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return doc.Spec(), err
|
||||
return document, nil
|
||||
}
|
||||
|
||||
// withRetries retries the given recovery function in case the groups supported by the server change after ServerGroup() returns.
|
||||
|
@ -19,14 +19,16 @@ package discovery_test
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"mime"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/emicklei/go-restful-swagger12"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/googleapis/gnostic/OpenAPIv2"
|
||||
|
||||
"github.com/go-openapi/spec"
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
@ -327,30 +329,44 @@ func TestGetSwaggerSchemaFail(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
var returnedOpenAPI = spec.Swagger{
|
||||
SwaggerProps: spec.SwaggerProps{
|
||||
Definitions: spec.Definitions{
|
||||
"fake.type.1": spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Properties: map[string]spec.Schema{
|
||||
"count": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"integer"},
|
||||
var returnedOpenAPI = openapi_v2.Document{
|
||||
Definitions: &openapi_v2.Definitions{
|
||||
AdditionalProperties: []*openapi_v2.NamedSchema{
|
||||
{
|
||||
Name: "fake.type.1",
|
||||
Value: &openapi_v2.Schema{
|
||||
Properties: &openapi_v2.Properties{
|
||||
AdditionalProperties: []*openapi_v2.NamedSchema{
|
||||
{
|
||||
Name: "count",
|
||||
Value: &openapi_v2.Schema{
|
||||
Type: &openapi_v2.TypeItem{
|
||||
Value: []string{"integer"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"fake.type.2": spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Properties: map[string]spec.Schema{
|
||||
"count": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"string"},
|
||||
{
|
||||
Name: "fake.type.2",
|
||||
Value: &openapi_v2.Schema{
|
||||
Properties: &openapi_v2.Properties{
|
||||
AdditionalProperties: []*openapi_v2.NamedSchema{
|
||||
{
|
||||
Name: "count",
|
||||
Value: &openapi_v2.Schema{
|
||||
Type: &openapi_v2.TypeItem{
|
||||
Value: []string{"array"},
|
||||
},
|
||||
Items: &openapi_v2.ItemsItem{
|
||||
Schema: []*openapi_v2.Schema{
|
||||
{
|
||||
Type: &openapi_v2.TypeItem{
|
||||
Value: []string{"string"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -366,19 +382,20 @@ var returnedOpenAPI = spec.Swagger{
|
||||
func openapiSchemaFakeServer() (*httptest.Server, error) {
|
||||
var sErr error
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
if req.URL.Path != "/swagger.json" {
|
||||
if req.URL.Path != "/swagger-2.0.0.pb-v1" {
|
||||
sErr = fmt.Errorf("Unexpected url %v", req.URL)
|
||||
}
|
||||
if req.Method != "GET" {
|
||||
sErr = fmt.Errorf("Unexpected method %v", req.Method)
|
||||
}
|
||||
|
||||
output, err := json.Marshal(returnedOpenAPI)
|
||||
mime.AddExtensionType(".pb-v1", "application/com.github.googleapis.gnostic.OpenAPIv2@68f4ded+protobuf")
|
||||
|
||||
output, err := proto.Marshal(&returnedOpenAPI)
|
||||
if err != nil {
|
||||
sErr = err
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(output)
|
||||
}))
|
||||
|
@ -13,7 +13,7 @@ go_library(
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//vendor/github.com/emicklei/go-restful-swagger12:go_default_library",
|
||||
"//vendor/github.com/go-openapi/spec:go_default_library",
|
||||
"//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
|
@ -20,8 +20,8 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/emicklei/go-restful-swagger12"
|
||||
"github.com/googleapis/gnostic/OpenAPIv2"
|
||||
|
||||
"github.com/go-openapi/spec"
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
@ -93,7 +93,9 @@ func (c *FakeDiscovery) SwaggerSchema(version schema.GroupVersion) (*swagger.Api
|
||||
return &swagger.ApiDeclaration{}, nil
|
||||
}
|
||||
|
||||
func (c *FakeDiscovery) OpenAPISchema() (*spec.Swagger, error) { return &spec.Swagger{}, nil }
|
||||
func (c *FakeDiscovery) OpenAPISchema() (*openapi_v2.Document, error) {
|
||||
return &openapi_v2.Document{}, nil
|
||||
}
|
||||
|
||||
func (c *FakeDiscovery) RESTClient() restclient.Interface {
|
||||
return nil
|
||||
|
@ -29,7 +29,7 @@ import (
|
||||
"k8s.io/client-go/rest/fake"
|
||||
|
||||
"github.com/emicklei/go-restful-swagger12"
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/googleapis/gnostic/OpenAPIv2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@ -348,6 +348,6 @@ func (c *fakeCachedDiscoveryInterface) SwaggerSchema(version schema.GroupVersion
|
||||
return &swagger.ApiDeclaration{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeCachedDiscoveryInterface) OpenAPISchema() (*spec.Swagger, error) {
|
||||
return &spec.Swagger{}, nil
|
||||
func (c *fakeCachedDiscoveryInterface) OpenAPISchema() (*openapi_v2.Document, error) {
|
||||
return &openapi_v2.Document{}, nil
|
||||
}
|
||||
|
@ -114,10 +114,6 @@
|
||||
"ImportPath": "github.com/ghodss/yaml",
|
||||
"Rev": "73d445a93680fa1a78ae23a5839bad48f32ba1ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/analysis",
|
||||
"Rev": "b44dc874b601d9e4e2f6e19140e794ba24bead3b"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/jsonpointer",
|
||||
"Rev": "46af16f9f7b149af66e5d1bd010e3574dc06de98"
|
||||
@ -126,10 +122,6 @@
|
||||
"ImportPath": "github.com/go-openapi/jsonreference",
|
||||
"Rev": "13c6e3589ad90f49bd3e3bbe2c2cb3d7a4142272"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/loads",
|
||||
"Rev": "18441dfa706d924a39a030ee2c3b1d8d81917b38"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/spec",
|
||||
"Rev": "6aced65f8501fe1217321abf0749d354824ba2ff"
|
||||
|
@ -106,10 +106,6 @@
|
||||
"ImportPath": "github.com/ghodss/yaml",
|
||||
"Rev": "73d445a93680fa1a78ae23a5839bad48f32ba1ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/analysis",
|
||||
"Rev": "b44dc874b601d9e4e2f6e19140e794ba24bead3b"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/jsonpointer",
|
||||
"Rev": "46af16f9f7b149af66e5d1bd010e3574dc06de98"
|
||||
@ -118,10 +114,6 @@
|
||||
"ImportPath": "github.com/go-openapi/jsonreference",
|
||||
"Rev": "13c6e3589ad90f49bd3e3bbe2c2cb3d7a4142272"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/loads",
|
||||
"Rev": "18441dfa706d924a39a030ee2c3b1d8d81917b38"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/spec",
|
||||
"Rev": "6aced65f8501fe1217321abf0749d354824ba2ff"
|
||||
|
Loading…
Reference in New Issue
Block a user