client can return swagger schema

This commit is contained in:
Anastasis Andronidis 2015-08-13 03:33:04 +02:00
parent d49ca164ef
commit 495433fbb7
3 changed files with 121 additions and 0 deletions

View File

@ -23,7 +23,10 @@ import (
"net/url"
"strings"
"github.com/emicklei/go-restful/swagger"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/latest"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/version"
)
@ -47,6 +50,7 @@ type Interface interface {
PersistentVolumesInterface
PersistentVolumeClaimsNamespacer
ComponentStatusesInterface
SwaggerSchemaInterface
Experimental() ExperimentalInterface
}
@ -174,6 +178,49 @@ func (c *Client) ValidateComponents() (*api.ComponentStatusList, error) {
return &api.ComponentStatusList{Items: statuses}, nil
}
// SwaggerSchemaInterface has a method to retrieve the swagger schema. Used in
// client.Interface
type SwaggerSchemaInterface interface {
SwaggerSchema(version string) (*swagger.ApiDeclaration, error)
}
// SwaggerSchema retrieves and parses the swagger API schema the server supports.
func (c *Client) SwaggerSchema(version string) (*swagger.ApiDeclaration, error) {
if version == "" {
version = latest.GroupOrDie("").Version
}
vers, err := c.ServerAPIVersions()
if err != nil {
return nil, err
}
// This check also takes care the case that kubectl is newer than the running endpoint
if stringDoesntExistIn(version, vers.Versions) {
return nil, fmt.Errorf("API version: %s is not supported by the server. Use one of: %v", version, vers.Versions)
}
body, err := c.Get().AbsPath("/swaggerapi/api/" + version).Do().Raw()
if err != nil {
return nil, err
}
var schema swagger.ApiDeclaration
err = json.Unmarshal(body, &schema)
if err != nil {
return nil, fmt.Errorf("got '%s': %v", string(body), err)
}
return &schema, nil
}
func stringDoesntExistIn(str string, slice []string) bool {
for _, s := range slice {
if s == str {
return false
}
}
return true
}
// IsTimeout tests if this is a timeout error in the underlying transport.
// This is unbelievably ugly.
// See: http://stackoverflow.com/questions/23494950/specifically-check-for-timeout-error for details

View File

@ -26,6 +26,8 @@ import (
"strings"
"testing"
"github.com/emicklei/go-restful/swagger"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/fields"
@ -290,3 +292,63 @@ func TestGetServerAPIVersions(t *testing.T) {
t.Errorf("expected %v, got %v", e, a)
}
}
func swaggerSchemaFakeServer() (*httptest.Server, error) {
request := 1
var sErr error
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
var resp interface{}
if request == 1 {
resp = api.APIVersions{Versions: []string{"v1", "v2", "v3"}}
request++
} else {
resp = swagger.ApiDeclaration{}
}
output, err := json.Marshal(resp)
if err != nil {
sErr = err
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(output)
}))
return server, sErr
}
func TestGetSwaggerSchema(t *testing.T) {
expect := swagger.ApiDeclaration{}
server, err := swaggerSchemaFakeServer()
if err != nil {
t.Errorf("unexpected encoding error: %v", err)
}
client := NewOrDie(&Config{Host: server.URL})
got, err := client.SwaggerSchema("v1")
if err != nil {
t.Fatalf("unexpected encoding error: %v", err)
}
if e, a := expect, *got; !reflect.DeepEqual(e, a) {
t.Errorf("expected %v, got %v", e, a)
}
}
func TestGetSwaggerSchemaFail(t *testing.T) {
expErr := "API version: v4 is not supported by the server. Use one of: [v1 v2 v3]"
server, err := swaggerSchemaFakeServer()
if err != nil {
t.Errorf("unexpected encoding error: %v", err)
}
client := NewOrDie(&Config{Host: server.URL})
got, err := client.SwaggerSchema("v4")
if got != nil {
t.Fatalf("unexpected response: %v", got)
}
if err.Error() != expErr {
t.Errorf("expected an error, got %v", err)
}
}

View File

@ -20,6 +20,8 @@ import (
"fmt"
"sync"
"github.com/emicklei/go-restful/swagger"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/registered"
client "k8s.io/kubernetes/pkg/client/unversioned"
@ -282,6 +284,16 @@ func (c *Fake) ComponentStatuses() client.ComponentStatusInterface {
return &FakeComponentStatuses{Fake: c}
}
// SwaggerSchema returns an empty swagger.ApiDeclaration for testing
func (c *Fake) SwaggerSchema(version string) (*swagger.ApiDeclaration, error) {
action := ActionImpl{}
action.Verb = "get"
action.Resource = "/swaggerapi/api/" + version
c.Invokes(action, nil)
return &swagger.ApiDeclaration{}, nil
}
type FakeExperimental struct {
*Fake
}