mirror of
https://github.com/kubernetes/client-go.git
synced 2025-06-24 14:12:18 +00:00
kubectl OpenAPI support
Kubernetes-commit: 212c2a3a7217ff7e0a7c895582c7a25d03ac7f8c
This commit is contained in:
parent
c192350f2c
commit
97a8b3b040
@ -25,6 +25,8 @@ import (
|
||||
|
||||
"github.com/emicklei/go-restful/swagger"
|
||||
|
||||
"github.com/go-openapi/loads"
|
||||
"github.com/go-openapi/spec"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
@ -47,6 +49,7 @@ type DiscoveryInterface interface {
|
||||
ServerResourcesInterface
|
||||
ServerVersionInterface
|
||||
SwaggerSchemaInterface
|
||||
OpenAPISchemaInterface
|
||||
}
|
||||
|
||||
// CachedDiscoveryInterface is a DiscoveryInterface with cache invalidation and freshness.
|
||||
@ -91,6 +94,12 @@ type SwaggerSchemaInterface interface {
|
||||
SwaggerSchema(version schema.GroupVersion) (*swagger.ApiDeclaration, error)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// DiscoveryClient implements the functions that discover server-supported API groups,
|
||||
// versions and resources.
|
||||
type DiscoveryClient struct {
|
||||
@ -332,6 +341,7 @@ func (d *DiscoveryClient) ServerVersion() (*version.Info, error) {
|
||||
}
|
||||
|
||||
// SwaggerSchema retrieves and parses the swagger API schema the server supports.
|
||||
// TODO: Replace usages with Open API. Tracked in https://github.com/kubernetes/kubernetes/issues/44589
|
||||
func (d *DiscoveryClient) SwaggerSchema(version schema.GroupVersion) (*swagger.ApiDeclaration, error) {
|
||||
if version.Empty() {
|
||||
return nil, fmt.Errorf("groupVersion cannot be empty")
|
||||
@ -365,6 +375,21 @@ 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()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
msg := json.RawMessage(data)
|
||||
doc, err := loads.Analyzed(msg, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return doc.Spec(), err
|
||||
}
|
||||
|
||||
// withRetries retries the given recovery function in case the groups supported by the server change after ServerGroup() returns.
|
||||
func withRetries(maxRetries int, f func(failEarly bool) ([]*metav1.APIResourceList, error)) ([]*metav1.APIResourceList, error) {
|
||||
var result []*metav1.APIResourceList
|
||||
|
@ -18,6 +18,7 @@ package discovery_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
@ -25,6 +26,7 @@ import (
|
||||
|
||||
"github.com/emicklei/go-restful/swagger"
|
||||
|
||||
"github.com/go-openapi/spec"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
@ -325,6 +327,81 @@ 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"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"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"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
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" {
|
||||
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)
|
||||
if err != nil {
|
||||
sErr = err
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(output)
|
||||
}))
|
||||
return server, sErr
|
||||
}
|
||||
|
||||
func TestGetOpenAPISchema(t *testing.T) {
|
||||
server, err := openapiSchemaFakeServer()
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error starting fake server: %v", err)
|
||||
}
|
||||
defer server.Close()
|
||||
|
||||
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
|
||||
got, err := client.OpenAPISchema()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error getting openapi: %v", err)
|
||||
}
|
||||
if e, a := returnedOpenAPI, *got; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServerPreferredResources(t *testing.T) {
|
||||
stable := metav1.APIResourceList{
|
||||
GroupVersion: "v1",
|
||||
|
@ -21,6 +21,7 @@ import (
|
||||
|
||||
"github.com/emicklei/go-restful/swagger"
|
||||
|
||||
"github.com/go-openapi/spec"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/version"
|
||||
@ -92,6 +93,8 @@ 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) RESTClient() restclient.Interface {
|
||||
return nil
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ import (
|
||||
"k8s.io/client-go/rest/fake"
|
||||
|
||||
"github.com/emicklei/go-restful/swagger"
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@ -347,3 +348,7 @@ func (c *fakeCachedDiscoveryInterface) ServerVersion() (*version.Info, error) {
|
||||
func (c *fakeCachedDiscoveryInterface) SwaggerSchema(version schema.GroupVersion) (*swagger.ApiDeclaration, error) {
|
||||
return &swagger.ApiDeclaration{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeCachedDiscoveryInterface) OpenAPISchema() (*spec.Swagger, error) {
|
||||
return &spec.Swagger{}, nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user