Commit d1ce3637 authored by Antoine Pelisse's avatar Antoine Pelisse

kubectl: Remove swagger 1.2 entirely.

parent d6b18a96
...@@ -24,7 +24,6 @@ go_library( ...@@ -24,7 +24,6 @@ go_library(
"//pkg/kubectl/resource:go_default_library", "//pkg/kubectl/resource:go_default_library",
"//pkg/kubectl/validation:go_default_library", "//pkg/kubectl/validation:go_default_library",
"//pkg/printers:go_default_library", "//pkg/printers:go_default_library",
"//vendor/github.com/emicklei/go-restful-swagger12:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library", "//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library", "//vendor/github.com/spf13/pflag:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
......
...@@ -23,7 +23,6 @@ import ( ...@@ -23,7 +23,6 @@ import (
"path/filepath" "path/filepath"
"time" "time"
swagger "github.com/emicklei/go-restful-swagger12"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/pflag" "github.com/spf13/pflag"
...@@ -419,10 +418,6 @@ func (f *FakeFactory) Validator(validate bool) (validation.Schema, error) { ...@@ -419,10 +418,6 @@ func (f *FakeFactory) Validator(validate bool) (validation.Schema, error) {
return f.tf.Validator, f.tf.Err return f.tf.Validator, f.tf.Err
} }
func (f *FakeFactory) SwaggerSchema(schema.GroupVersionKind) (*swagger.ApiDeclaration, error) {
return nil, nil
}
func (f *FakeFactory) OpenAPISchema() (openapi.Resources, error) { func (f *FakeFactory) OpenAPISchema() (openapi.Resources, error) {
return nil, nil return nil, nil
} }
...@@ -765,10 +760,6 @@ func (f *fakeAPIFactory) SuggestedPodTemplateResources() []schema.GroupResource ...@@ -765,10 +760,6 @@ func (f *fakeAPIFactory) SuggestedPodTemplateResources() []schema.GroupResource
return []schema.GroupResource{} return []schema.GroupResource{}
} }
func (f *fakeAPIFactory) SwaggerSchema(schema.GroupVersionKind) (*swagger.ApiDeclaration, error) {
return nil, nil
}
func (f *fakeAPIFactory) OpenAPISchema() (openapi.Resources, error) { func (f *fakeAPIFactory) OpenAPISchema() (openapi.Resources, error) {
if f.tf.OpenAPISchemaFunc != nil { if f.tf.OpenAPISchemaFunc != nil {
return f.tf.OpenAPISchemaFunc() return f.tf.OpenAPISchemaFunc()
......
...@@ -41,7 +41,6 @@ go_library( ...@@ -41,7 +41,6 @@ go_library(
"//pkg/printers:go_default_library", "//pkg/printers:go_default_library",
"//pkg/printers/internalversion:go_default_library", "//pkg/printers/internalversion:go_default_library",
"//pkg/version:go_default_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/evanphx/json-patch:go_default_library",
"//vendor/github.com/golang/glog:go_default_library", "//vendor/github.com/golang/glog:go_default_library",
"//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library", "//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library",
...@@ -57,7 +56,6 @@ go_library( ...@@ -57,7 +56,6 @@ go_library(
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library", "//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/json:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library", "//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/json:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/json:go_default_library",
...@@ -105,8 +103,6 @@ go_test( ...@@ -105,8 +103,6 @@ go_test(
"//pkg/controller:go_default_library", "//pkg/controller:go_default_library",
"//pkg/kubectl:go_default_library", "//pkg/kubectl:go_default_library",
"//pkg/kubectl/resource:go_default_library", "//pkg/kubectl/resource:go_default_library",
"//pkg/kubectl/validation:go_default_library",
"//vendor/github.com/emicklei/go-restful-swagger12:go_default_library",
"//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library", "//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library",
"//vendor/github.com/stretchr/testify/assert:go_default_library", "//vendor/github.com/stretchr/testify/assert:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library", "//vendor/k8s.io/api/core/v1:go_default_library",
......
...@@ -24,13 +24,11 @@ import ( ...@@ -24,13 +24,11 @@ import (
"sync" "sync"
"time" "time"
"github.com/emicklei/go-restful-swagger12"
"github.com/golang/glog" "github.com/golang/glog"
"github.com/googleapis/gnostic/OpenAPIv2" "github.com/googleapis/gnostic/OpenAPIv2"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/version" "k8s.io/apimachinery/pkg/version"
"k8s.io/client-go/discovery" "k8s.io/client-go/discovery"
restclient "k8s.io/client-go/rest" restclient "k8s.io/client-go/rest"
...@@ -233,10 +231,6 @@ func (d *CachedDiscoveryClient) ServerVersion() (*version.Info, error) { ...@@ -233,10 +231,6 @@ func (d *CachedDiscoveryClient) ServerVersion() (*version.Info, error) {
return d.delegate.ServerVersion() return d.delegate.ServerVersion()
} }
func (d *CachedDiscoveryClient) SwaggerSchema(version schema.GroupVersion) (*swagger.ApiDeclaration, error) {
return d.delegate.SwaggerSchema(version)
}
func (d *CachedDiscoveryClient) OpenAPISchema() (*openapi_v2.Document, error) { func (d *CachedDiscoveryClient) OpenAPISchema() (*openapi_v2.Document, error) {
return d.delegate.OpenAPISchema() return d.delegate.OpenAPISchema()
} }
......
...@@ -22,7 +22,6 @@ import ( ...@@ -22,7 +22,6 @@ import (
"testing" "testing"
"time" "time"
"github.com/emicklei/go-restful-swagger12"
"github.com/googleapis/gnostic/OpenAPIv2" "github.com/googleapis/gnostic/OpenAPIv2"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
...@@ -101,7 +100,6 @@ type fakeDiscoveryClient struct { ...@@ -101,7 +100,6 @@ type fakeDiscoveryClient struct {
groupCalls int groupCalls int
resourceCalls int resourceCalls int
versionCalls int versionCalls int
swaggerCalls int
openAPICalls int openAPICalls int
serverResourcesHandler func() ([]*metav1.APIResourceList, error) serverResourcesHandler func() ([]*metav1.APIResourceList, error)
...@@ -166,11 +164,6 @@ func (c *fakeDiscoveryClient) ServerVersion() (*version.Info, error) { ...@@ -166,11 +164,6 @@ func (c *fakeDiscoveryClient) ServerVersion() (*version.Info, error) {
return &version.Info{}, nil return &version.Info{}, nil
} }
func (c *fakeDiscoveryClient) SwaggerSchema(version schema.GroupVersion) (*swagger.ApiDeclaration, error) {
c.swaggerCalls = c.swaggerCalls + 1
return &swagger.ApiDeclaration{}, nil
}
func (c *fakeDiscoveryClient) OpenAPISchema() (*openapi_v2.Document, error) { func (c *fakeDiscoveryClient) OpenAPISchema() (*openapi_v2.Document, error) {
c.openAPICalls = c.openAPICalls + 1 c.openAPICalls = c.openAPICalls + 1
return &openapi_v2.Document{}, nil return &openapi_v2.Document{}, nil
......
...@@ -17,20 +17,13 @@ limitations under the License. ...@@ -17,20 +17,13 @@ limitations under the License.
package util package util
import ( import (
"bytes"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"os"
"os/user"
"path"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
"time" "time"
swagger "github.com/emicklei/go-restful-swagger12"
"github.com/golang/glog"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/pflag" "github.com/spf13/pflag"
...@@ -39,7 +32,6 @@ import ( ...@@ -39,7 +32,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer/json"
"k8s.io/apimachinery/pkg/watch" "k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/discovery" "k8s.io/client-go/discovery"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
...@@ -233,8 +225,6 @@ type ObjectMappingFactory interface { ...@@ -233,8 +225,6 @@ type ObjectMappingFactory interface {
// Returns a schema that can validate objects stored on disk. // Returns a schema that can validate objects stored on disk.
Validator(validate bool) (validation.Schema, error) Validator(validate bool) (validation.Schema, error)
// SwaggerSchema returns the schema declaration for the provided group version kind.
SwaggerSchema(schema.GroupVersionKind) (*swagger.ApiDeclaration, error)
// OpenAPISchema returns the schema openapi schema definiton // OpenAPISchema returns the schema openapi schema definiton
OpenAPISchema() (openapi.Resources, error) OpenAPISchema() (openapi.Resources, error)
} }
...@@ -389,145 +379,3 @@ func getServiceProtocols(spec api.ServiceSpec) map[string]string { ...@@ -389,145 +379,3 @@ func getServiceProtocols(spec api.ServiceSpec) map[string]string {
} }
return result return result
} }
type clientSwaggerSchema struct {
c restclient.Interface
cacheDir string
}
const schemaFileName = "schema.json"
type schemaClient interface {
Get() *restclient.Request
}
func recursiveSplit(dir string) []string {
parent, file := path.Split(dir)
if len(parent) == 0 {
return []string{file}
}
return append(recursiveSplit(parent[:len(parent)-1]), file)
}
func substituteUserHome(dir string) (string, error) {
if len(dir) == 0 || dir[0] != '~' {
return dir, nil
}
parts := recursiveSplit(dir)
if len(parts[0]) == 1 {
parts[0] = os.Getenv("HOME")
} else {
usr, err := user.Lookup(parts[0][1:])
if err != nil {
return "", err
}
parts[0] = usr.HomeDir
}
return path.Join(parts...), nil
}
func writeSchemaFile(schemaData []byte, cacheDir, cacheFile, prefix, groupVersion string) error {
if err := os.MkdirAll(path.Join(cacheDir, prefix, groupVersion), 0755); err != nil {
return err
}
tmpFile, err := ioutil.TempFile(cacheDir, "schema")
if err != nil {
// If we can't write, keep going.
if os.IsPermission(err) {
return nil
}
return err
}
if _, err := io.Copy(tmpFile, bytes.NewBuffer(schemaData)); err != nil {
return err
}
glog.V(4).Infof("Writing swagger cache (dir %v) file %v (from %v)", cacheDir, cacheFile, tmpFile.Name())
if err := os.Link(tmpFile.Name(), cacheFile); err != nil {
// If we can't write due to file existing, or permission problems, keep going.
if os.IsExist(err) || os.IsPermission(err) {
return nil
}
return err
}
return nil
}
func getSchemaAndValidate(c schemaClient, data []byte, prefix, groupVersion, cacheDir string, delegate validation.Schema) (err error) {
var schemaData []byte
var firstSeen bool
fullDir, err := substituteUserHome(cacheDir)
if err != nil {
return err
}
cacheFile := path.Join(fullDir, prefix, groupVersion, schemaFileName)
if len(cacheDir) != 0 {
if schemaData, err = ioutil.ReadFile(cacheFile); err != nil && !os.IsNotExist(err) {
return err
}
}
if schemaData == nil {
firstSeen = true
schemaData, err = downloadSchemaAndStore(c, cacheDir, fullDir, cacheFile, prefix, groupVersion)
if err != nil {
return err
}
}
schema, err := validation.NewSwaggerSchemaFromBytes(schemaData, delegate)
if err != nil {
return err
}
err = schema.ValidateBytes(data)
if _, ok := err.(validation.TypeNotFoundError); ok && !firstSeen {
// As a temporary hack, kubectl would re-get the schema if validation
// fails for type not found reason.
// TODO: runtime-config settings needs to make into the file's name
schemaData, err = downloadSchemaAndStore(c, cacheDir, fullDir, cacheFile, prefix, groupVersion)
if err != nil {
return err
}
schema, err := validation.NewSwaggerSchemaFromBytes(schemaData, delegate)
if err != nil {
return err
}
return schema.ValidateBytes(data)
}
return err
}
// Download swagger schema from apiserver and store it to file.
func downloadSchemaAndStore(c schemaClient, cacheDir, fullDir, cacheFile, prefix, groupVersion string) (schemaData []byte, err error) {
schemaData, err = c.Get().
AbsPath("/swaggerapi", prefix, groupVersion).
Do().
Raw()
if err != nil {
return
}
if len(cacheDir) != 0 {
if err = writeSchemaFile(schemaData, fullDir, cacheFile, prefix, groupVersion); err != nil {
return
}
}
return
}
func (c *clientSwaggerSchema) ValidateBytes(data []byte) error {
gvk, err := json.DefaultMetaFactory.Interpret(data)
if err != nil {
return err
}
if ok := api.Registry.IsEnabledVersion(gvk.GroupVersion()); !ok {
// if we don't have this in our scheme, just skip validation because its an object we don't recognize
return nil
}
switch gvk.Group {
case api.GroupName:
return getSchemaAndValidate(c.c, data, "api", gvk.GroupVersion().String(), c.cacheDir, c)
default:
return getSchemaAndValidate(c.c, data, "apis/", gvk.GroupVersion().String(), c.cacheDir, c)
}
}
...@@ -26,14 +26,11 @@ import ( ...@@ -26,14 +26,11 @@ import (
"sync" "sync"
"time" "time"
swagger "github.com/emicklei/go-restful-swagger12"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/discovery" "k8s.io/client-go/discovery"
"k8s.io/client-go/dynamic" "k8s.io/client-go/dynamic"
restclient "k8s.io/client-go/rest" restclient "k8s.io/client-go/rest"
...@@ -423,15 +420,6 @@ func (f *ring1Factory) Validator(validate bool) (validation.Schema, error) { ...@@ -423,15 +420,6 @@ func (f *ring1Factory) Validator(validate bool) (validation.Schema, error) {
}, nil }, nil
} }
func (f *ring1Factory) SwaggerSchema(gvk schema.GroupVersionKind) (*swagger.ApiDeclaration, error) {
version := gvk.GroupVersion()
discovery, err := f.clientAccessFactory.DiscoveryClient()
if err != nil {
return nil, err
}
return discovery.SwaggerSchema(version)
}
// OpenAPISchema returns metadata and structural information about Kubernetes object definitions. // OpenAPISchema returns metadata and structural information about Kubernetes object definitions.
func (f *ring1Factory) OpenAPISchema() (openapi.Resources, error) { func (f *ring1Factory) OpenAPISchema() (openapi.Resources, error) {
discovery, err := f.clientAccessFactory.DiscoveryClient() discovery, err := f.clientAccessFactory.DiscoveryClient()
......
...@@ -18,13 +18,7 @@ package util ...@@ -18,13 +18,7 @@ package util
import ( import (
"bytes" "bytes"
"encoding/json"
"fmt" "fmt"
"io/ioutil"
"net/http"
"os"
"os/user"
"path"
"sort" "sort"
"strings" "strings"
"testing" "testing"
...@@ -46,12 +40,10 @@ import ( ...@@ -46,12 +40,10 @@ import (
clientcmdapi "k8s.io/client-go/tools/clientcmd/api" clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
"k8s.io/kubernetes/pkg/controller" "k8s.io/kubernetes/pkg/controller"
"k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/resource" "k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/kubectl/validation"
) )
func TestNewFactoryDefaultFlagBindings(t *testing.T) { func TestNewFactoryDefaultFlagBindings(t *testing.T) {
...@@ -230,208 +222,6 @@ func TestFlagUnderscoreRenaming(t *testing.T) { ...@@ -230,208 +222,6 @@ func TestFlagUnderscoreRenaming(t *testing.T) {
} }
} }
func loadSchemaForTest() (validation.Schema, error) {
pathToSwaggerSpec := "../../../../api/swagger-spec/" + api.Registry.GroupOrDie(api.GroupName).GroupVersion.Version + ".json"
data, err := ioutil.ReadFile(pathToSwaggerSpec)
if err != nil {
return nil, err
}
return validation.NewSwaggerSchemaFromBytes(data, nil)
}
func header() http.Header {
header := http.Header{}
header.Set("Content-Type", runtime.ContentTypeJSON)
return header
}
func TestRefetchSchemaWhenValidationFails(t *testing.T) {
schema, err := loadSchemaForTest()
if err != nil {
t.Errorf("Error loading schema: %v", err)
t.FailNow()
}
output, err := json.Marshal(schema)
if err != nil {
t.Errorf("Error serializing schema: %v", err)
t.FailNow()
}
requests := map[string]int{}
c := &manualfake.RESTClient{
APIRegistry: api.Registry,
NegotiatedSerializer: testapi.Default.NegotiatedSerializer(),
Client: manualfake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case strings.HasPrefix(p, "/swaggerapi") && m == "GET":
requests[p] = requests[p] + 1
return &http.Response{StatusCode: 200, Header: header(), Body: ioutil.NopCloser(bytes.NewBuffer(output))}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
}
}),
}
dir, err := ioutil.TempDir("", "schemaCache")
if err != nil {
t.Fatalf("Error getting tempDir: %v", err)
}
defer os.RemoveAll(dir)
fullDir, err := substituteUserHome(dir)
if err != nil {
t.Errorf("Error getting fullDir: %v", err)
t.FailNow()
}
cacheFile := path.Join(fullDir, "foo", "bar", schemaFileName)
err = writeSchemaFile(output, fullDir, cacheFile, "foo", "bar")
if err != nil {
t.Errorf("Error building old cache schema: %v", err)
t.FailNow()
}
obj := &extensions.Deployment{}
data, err := runtime.Encode(testapi.Extensions.Codec(), obj)
if err != nil {
t.Errorf("unexpected error: %v", err)
t.FailNow()
}
// Re-get request, should use HTTP and write
if getSchemaAndValidate(c, data, "foo", "bar", dir, nil); err != nil {
t.Errorf("unexpected error validating: %v", err)
}
if requests["/swaggerapi/foo/bar"] != 1 {
t.Errorf("expected 1 schema request, saw: %d", requests["/swaggerapi/foo/bar"])
}
}
func TestValidateCachesSchema(t *testing.T) {
schema, err := loadSchemaForTest()
if err != nil {
t.Errorf("Error loading schema: %v", err)
t.FailNow()
}
output, err := json.Marshal(schema)
if err != nil {
t.Errorf("Error serializing schema: %v", err)
t.FailNow()
}
requests := map[string]int{}
c := &manualfake.RESTClient{
APIRegistry: api.Registry,
NegotiatedSerializer: testapi.Default.NegotiatedSerializer(),
Client: manualfake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case strings.HasPrefix(p, "/swaggerapi") && m == "GET":
requests[p] = requests[p] + 1
return &http.Response{StatusCode: 200, Header: header(), Body: ioutil.NopCloser(bytes.NewBuffer(output))}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
}
}),
}
dir, err := ioutil.TempDir("", "schemaCache")
if err != nil {
t.Fatalf("Error getting tempDir: %v", err)
}
defer os.RemoveAll(dir)
obj := &api.Pod{}
data, err := runtime.Encode(testapi.Default.Codec(), obj)
if err != nil {
t.Errorf("unexpected error: %v", err)
t.FailNow()
}
// Initial request, should use HTTP and write
if getSchemaAndValidate(c, data, "foo", "bar", dir, nil); err != nil {
t.Errorf("unexpected error validating: %v", err)
}
if _, err := os.Stat(path.Join(dir, "foo", "bar", schemaFileName)); err != nil {
t.Errorf("unexpected missing cache file: %v", err)
}
if requests["/swaggerapi/foo/bar"] != 1 {
t.Errorf("expected 1 schema request, saw: %d", requests["/swaggerapi/foo/bar"])
}
// Same version and group, should skip HTTP
if getSchemaAndValidate(c, data, "foo", "bar", dir, nil); err != nil {
t.Errorf("unexpected error validating: %v", err)
}
if requests["/swaggerapi/foo/bar"] != 2 {
t.Errorf("expected 1 schema request, saw: %d", requests["/swaggerapi/foo/bar"])
}
// Different API group, should go to HTTP and write
if getSchemaAndValidate(c, data, "foo", "baz", dir, nil); err != nil {
t.Errorf("unexpected error validating: %v", err)
}
if _, err := os.Stat(path.Join(dir, "foo", "baz", schemaFileName)); err != nil {
t.Errorf("unexpected missing cache file: %v", err)
}
if requests["/swaggerapi/foo/baz"] != 1 {
t.Errorf("expected 1 schema request, saw: %d", requests["/swaggerapi/foo/baz"])
}
// Different version, should go to HTTP and write
if getSchemaAndValidate(c, data, "foo2", "bar", dir, nil); err != nil {
t.Errorf("unexpected error validating: %v", err)
}
if _, err := os.Stat(path.Join(dir, "foo2", "bar", schemaFileName)); err != nil {
t.Errorf("unexpected missing cache file: %v", err)
}
if requests["/swaggerapi/foo2/bar"] != 1 {
t.Errorf("expected 1 schema request, saw: %d", requests["/swaggerapi/foo2/bar"])
}
// No cache dir, should go straight to HTTP and not write
if getSchemaAndValidate(c, data, "foo", "blah", "", nil); err != nil {
t.Errorf("unexpected error validating: %v", err)
}
if requests["/swaggerapi/foo/blah"] != 1 {
t.Errorf("expected 1 schema request, saw: %d", requests["/swaggerapi/foo/blah"])
}
if _, err := os.Stat(path.Join(dir, "foo", "blah", schemaFileName)); err == nil || !os.IsNotExist(err) {
t.Errorf("unexpected cache file error: %v", err)
}
}
func TestSubstitueUser(t *testing.T) {
usr, err := user.Current()
if err != nil {
t.Logf("SKIPPING TEST: unexpected error: %v", err)
return
}
tests := []struct {
input string
expected string
expectErr bool
}{
{input: "~/foo", expected: path.Join(os.Getenv("HOME"), "foo")},
{input: "~" + usr.Username + "/bar", expected: usr.HomeDir + "/bar"},
{input: "/foo/bar", expected: "/foo/bar"},
{input: "~doesntexit/bar", expectErr: true},
}
for _, test := range tests {
output, err := substituteUserHome(test.input)
if test.expectErr {
if err == nil {
t.Error("unexpected non-error")
}
continue
}
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if output != test.expected {
t.Errorf("expected: %s, saw: %s", test.expected, output)
}
}
}
func newPodList(count, isUnready, isUnhealthy int, labels map[string]string) *api.PodList { func newPodList(count, isUnready, isUnhealthy int, labels map[string]string) *api.PodList {
pods := []api.Pod{} pods := []api.Pod{}
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
......
...@@ -61,7 +61,6 @@ go_test( ...@@ -61,7 +61,6 @@ go_test(
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/api/testapi:go_default_library", "//pkg/api/testapi:go_default_library",
"//pkg/api/testing:go_default_library", "//pkg/api/testing:go_default_library",
"//vendor/github.com/emicklei/go-restful-swagger12:go_default_library",
"//vendor/github.com/ghodss/yaml:go_default_library", "//vendor/github.com/ghodss/yaml:go_default_library",
"//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library", "//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library",
"//vendor/github.com/stretchr/testify/assert:go_default_library", "//vendor/github.com/stretchr/testify/assert:go_default_library",
......
...@@ -20,8 +20,6 @@ import ( ...@@ -20,8 +20,6 @@ import (
"reflect" "reflect"
"testing" "testing"
swagger "github.com/emicklei/go-restful-swagger12"
"github.com/googleapis/gnostic/OpenAPIv2" "github.com/googleapis/gnostic/OpenAPIv2"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
...@@ -183,10 +181,6 @@ func (c *fakeDiscoveryClient) ServerVersion() (*version.Info, error) { ...@@ -183,10 +181,6 @@ func (c *fakeDiscoveryClient) ServerVersion() (*version.Info, error) {
return &version.Info{}, nil return &version.Info{}, nil
} }
func (c *fakeDiscoveryClient) SwaggerSchema(version schema.GroupVersion) (*swagger.ApiDeclaration, error) {
return &swagger.ApiDeclaration{}, nil
}
func (c *fakeDiscoveryClient) OpenAPISchema() (*openapi_v2.Document, error) { func (c *fakeDiscoveryClient) OpenAPISchema() (*openapi_v2.Document, error) {
return &openapi_v2.Document{}, nil return &openapi_v2.Document{}, nil
} }
...@@ -11,38 +11,13 @@ exports_files( ...@@ -11,38 +11,13 @@ exports_files(
visibility = ["//build/visible_to:COMMON_testing"], visibility = ["//build/visible_to:COMMON_testing"],
) )
filegroup(
name = "testdata",
srcs = [
"testdata/v1/invalidPod.yaml",
"testdata/v1/invalidPod1.json",
"testdata/v1/invalidPod2.json",
"testdata/v1/invalidPod3.json",
"testdata/v1/invalidPod4.yaml",
"testdata/v1/validPod.yaml",
],
visibility = ["//build/visible_to:COMMON_testing"],
)
go_test( go_test(
name = "go_default_test", name = "go_default_test",
srcs = ["schema_test.go"], srcs = ["schema_test.go"],
data = [ data = [
":testdata", ":testdata",
"//api/swagger-spec",
], ],
library = ":go_default_library", library = ":go_default_library",
deps = [
"//pkg/api:go_default_library",
"//pkg/api/testapi:go_default_library",
"//pkg/api/testing:go_default_library",
"//vendor/github.com/ghodss/yaml:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/testing/fuzzer:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/yaml:go_default_library",
],
) )
go_library( go_library(
...@@ -50,13 +25,8 @@ go_library( ...@@ -50,13 +25,8 @@ go_library(
srcs = ["schema.go"], srcs = ["schema.go"],
visibility = ["//build/visible_to:pkg_kubectl_validation_CONSUMERS"], visibility = ["//build/visible_to:pkg_kubectl_validation_CONSUMERS"],
deps = [ deps = [
"//pkg/api/util:go_default_library",
"//vendor/github.com/emicklei/go-restful-swagger12:go_default_library",
"//vendor/github.com/exponent-io/jsonpath:go_default_library", "//vendor/github.com/exponent-io/jsonpath:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/yaml:go_default_library",
], ],
) )
......
...@@ -17,297 +17,10 @@ limitations under the License. ...@@ -17,297 +17,10 @@ limitations under the License.
package validation package validation
import ( import (
"encoding/json"
"fmt" "fmt"
"io/ioutil"
"math/rand"
"strings"
"testing" "testing"
"github.com/ghodss/yaml"
"k8s.io/api/core/v1"
"k8s.io/api/extensions/v1beta1"
"k8s.io/apimachinery/pkg/api/testing/fuzzer"
"k8s.io/apimachinery/pkg/runtime"
k8syaml "k8s.io/apimachinery/pkg/util/yaml"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi"
kapitesting "k8s.io/kubernetes/pkg/api/testing"
) )
func readPod(filename string) ([]byte, error) {
data, err := ioutil.ReadFile("testdata/" + api.Registry.GroupOrDie(api.GroupName).GroupVersion.Version + "/" + filename)
return data, err
}
func readSwaggerFile() ([]byte, error) {
return readSwaggerAPIFile(testapi.Default)
}
func readSwaggerAPIFile(group testapi.TestGroup) ([]byte, error) {
// TODO: Figure out a better way of finding these files
var pathToSwaggerSpec string
if group.GroupVersion().Group == "" {
pathToSwaggerSpec = "../../../api/swagger-spec/" + group.GroupVersion().Version + ".json"
} else {
pathToSwaggerSpec = "../../../api/swagger-spec/" + group.GroupVersion().Group + "_" + group.GroupVersion().Version + ".json"
}
return ioutil.ReadFile(pathToSwaggerSpec)
}
// Mock delegating Schema. Not a full fake impl.
type Factory struct {
defaultSchema Schema
extensionsSchema Schema
}
var _ Schema = &Factory{}
// TODO: Consider using a mocking library instead or fully fleshing this out into a fake impl and putting it in some
// generally available location
func (f *Factory) ValidateBytes(data []byte) error {
var obj interface{}
out, err := k8syaml.ToJSON(data)
if err != nil {
return err
}
data = out
if err := json.Unmarshal(data, &obj); err != nil {
return err
}
fields, ok := obj.(map[string]interface{})
if !ok {
return fmt.Errorf("error in unmarshaling data %s", string(data))
}
// Note: This only supports the 2 api versions we expect from the test it is currently supporting.
groupVersion := fields["apiVersion"]
switch groupVersion {
case "v1":
return f.defaultSchema.ValidateBytes(data)
case "extensions/v1beta1":
return f.extensionsSchema.ValidateBytes(data)
default:
return fmt.Errorf("Unsupported API version %s", groupVersion)
}
}
func loadSchemaForTest() (Schema, error) {
data, err := readSwaggerFile()
if err != nil {
return nil, err
}
return NewSwaggerSchemaFromBytes(data, nil)
}
func loadSchemaForTestWithFactory(group testapi.TestGroup, factory Schema) (Schema, error) {
data, err := readSwaggerAPIFile(group)
if err != nil {
return nil, err
}
return NewSwaggerSchemaFromBytes(data, factory)
}
func NewFactory() (*Factory, error) {
f := &Factory{}
defaultSchema, err := loadSchemaForTestWithFactory(testapi.Default, f)
if err != nil {
return nil, err
}
f.defaultSchema = defaultSchema
extensionSchema, err := loadSchemaForTestWithFactory(testapi.Extensions, f)
if err != nil {
return nil, err
}
f.extensionsSchema = extensionSchema
return f, nil
}
func TestLoad(t *testing.T) {
_, err := loadSchemaForTest()
if err != nil {
t.Errorf("Failed to load: %v", err)
}
}
func TestValidateOk(t *testing.T) {
schema, err := loadSchemaForTest()
if err != nil {
t.Fatalf("Failed to load: %v", err)
}
tests := []struct {
obj runtime.Object
typeName string
}{
{obj: &api.Pod{}},
{obj: &api.Service{}},
{obj: &api.ReplicationController{}},
}
seed := rand.Int63()
apiObjectFuzzer := fuzzer.FuzzerFor(kapitesting.FuzzerFuncs, rand.NewSource(seed), api.Codecs)
for i := 0; i < 5; i++ {
for _, test := range tests {
testObj := test.obj
apiObjectFuzzer.Fuzz(testObj)
data, err := runtime.Encode(testapi.Default.Codec(), testObj)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
err = schema.ValidateBytes(data)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
}
}
}
func TestValidateDifferentApiVersions(t *testing.T) {
schema, err := loadSchemaForTest()
if err != nil {
t.Fatalf("Failed to load: %v", err)
}
pod := &v1.Pod{}
pod.APIVersion = "v1"
pod.Kind = "Pod"
deployment := &v1beta1.Deployment{}
deployment.APIVersion = "extensions/v1beta1"
deployment.Kind = "Deployment"
list := &v1.List{}
list.APIVersion = "v1"
list.Kind = "List"
list.Items = []runtime.RawExtension{{Object: pod}, {Object: deployment}}
bytes, err := json.Marshal(list)
if err != nil {
t.Error(err)
}
err = schema.ValidateBytes(bytes)
if err == nil {
t.Error(fmt.Errorf("expected error when validating different api version and no delegate exists"))
}
f, err := NewFactory()
if err != nil {
t.Error(fmt.Errorf("failed to create Schema factory %v", err))
}
err = f.ValidateBytes(bytes)
if err != nil {
t.Error(fmt.Errorf("failed to validate object with multiple ApiGroups: %v", err))
}
}
func TestInvalid(t *testing.T) {
schema, err := loadSchemaForTest()
if err != nil {
t.Fatalf("Failed to load: %v", err)
}
tests := []string{
"invalidPod1.json", // command is a string, instead of []string.
"invalidPod2.json", // hostPort if of type string, instead of int.
"invalidPod3.json", // volumes is not an array of objects.
"invalidPod4.yaml", // string list with empty string.
"invalidPod.yaml", // command is a string, instead of []string.
}
for _, test := range tests {
pod, err := readPod(test)
if err != nil {
t.Errorf("could not read file: %s, err: %v", test, err)
}
err = schema.ValidateBytes(pod)
if err == nil {
t.Errorf("unexpected non-error, err: %s for pod: %s", err, pod)
}
}
}
func TestValid(t *testing.T) {
schema, err := loadSchemaForTest()
if err != nil {
t.Fatalf("Failed to load: %v", err)
}
tests := []string{
"validPod.yaml",
}
for _, test := range tests {
pod, err := readPod(test)
if err != nil {
t.Errorf("could not read file: %s, err: %v", test, err)
}
err = schema.ValidateBytes(pod)
if err != nil {
t.Errorf("unexpected error: %s, for pod %s", err, pod)
}
}
}
func TestVersionRegex(t *testing.T) {
testCases := []struct {
typeName string
match bool
}{
{
typeName: "v1.Binding",
match: true,
},
{
typeName: "v1beta1.Binding",
match: true,
},
{
typeName: "Binding",
match: false,
},
}
for _, test := range testCases {
if versionRegexp.MatchString(test.typeName) && !test.match {
t.Errorf("unexpected error: expect %s not to match the regular expression", test.typeName)
}
if !versionRegexp.MatchString(test.typeName) && test.match {
t.Errorf("unexpected error: expect %s to match the regular expression", test.typeName)
}
}
}
// Tests that validation works fine when spec contains "type": "any" instead of "type": "object"
// Ref: https://github.com/kubernetes/kubernetes/issues/24309
func TestTypeAny(t *testing.T) {
data, err := readSwaggerFile()
if err != nil {
t.Errorf("failed to read swagger file: %v", err)
}
// Replace type: "any" in the spec by type: "object" and verify that the validation still passes.
newData := strings.Replace(string(data), `"type": "object"`, `"type": "any"`, -1)
schema, err := NewSwaggerSchemaFromBytes([]byte(newData), nil)
if err != nil {
t.Fatalf("Failed to load: %v", err)
}
tests := []string{
"validPod.yaml",
}
for _, test := range tests {
podBytes, err := readPod(test)
if err != nil {
t.Errorf("could not read file: %s, err: %v", test, err)
}
// Verify that pod has at least one label (labels are type "any")
var pod v1.Pod
err = yaml.Unmarshal(podBytes, &pod)
if err != nil {
t.Errorf("error in unmarshalling pod: %v", err)
}
if len(pod.Labels) == 0 {
t.Errorf("invalid test input: the pod should have at least one label")
}
err = schema.ValidateBytes(podBytes)
if err != nil {
t.Errorf("unexpected error: %s, for pod %s", err, string(podBytes))
}
}
}
func TestValidateDuplicateLabelsFailCases(t *testing.T) { func TestValidateDuplicateLabelsFailCases(t *testing.T) {
strs := []string{ strs := []string{
`{ `{
......
...@@ -91,10 +91,6 @@ ...@@ -91,10 +91,6 @@
"Rev": "ff4f55a206334ef123e4f79bbf348980da81ca46" "Rev": "ff4f55a206334ef123e4f79bbf348980da81ca46"
}, },
{ {
"ImportPath": "github.com/emicklei/go-restful-swagger12",
"Rev": "dcef7f55730566d41eae5db10e7d6981829720f6"
},
{
"ImportPath": "github.com/emicklei/go-restful/log", "ImportPath": "github.com/emicklei/go-restful/log",
"Rev": "ff4f55a206334ef123e4f79bbf348980da81ca46" "Rev": "ff4f55a206334ef123e4f79bbf348980da81ca46"
}, },
......
...@@ -15,11 +15,9 @@ go_library( ...@@ -15,11 +15,9 @@ go_library(
"unstructured.go", "unstructured.go",
], ],
deps = [ deps = [
"//vendor/github.com/emicklei/go-restful-swagger12:go_default_library",
"//vendor/github.com/golang/glog:go_default_library", "//vendor/github.com/golang/glog:go_default_library",
"//vendor/github.com/golang/protobuf/proto:go_default_library", "//vendor/github.com/golang/protobuf/proto:go_default_library",
"//vendor/github.com/googleapis/gnostic/OpenAPIv2: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/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
...@@ -41,7 +39,6 @@ go_test( ...@@ -41,7 +39,6 @@ go_test(
"restmapper_test.go", "restmapper_test.go",
], ],
deps = [ deps = [
"//vendor/github.com/emicklei/go-restful-swagger12:go_default_library",
"//vendor/github.com/gogo/protobuf/proto:go_default_library", "//vendor/github.com/gogo/protobuf/proto:go_default_library",
"//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library", "//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library",
"//vendor/github.com/stretchr/testify/assert:go_default_library", "//vendor/github.com/stretchr/testify/assert:go_default_library",
......
...@@ -20,10 +20,8 @@ go_library( ...@@ -20,10 +20,8 @@ go_library(
name = "go_default_library", name = "go_default_library",
srcs = ["memcache.go"], srcs = ["memcache.go"],
deps = [ deps = [
"//vendor/github.com/emicklei/go-restful-swagger12:go_default_library",
"//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library", "//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/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",
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/version:go_default_library", "//vendor/k8s.io/apimachinery/pkg/version:go_default_library",
"//vendor/k8s.io/client-go/discovery:go_default_library", "//vendor/k8s.io/client-go/discovery:go_default_library",
......
...@@ -21,11 +21,9 @@ import ( ...@@ -21,11 +21,9 @@ import (
"fmt" "fmt"
"sync" "sync"
"github.com/emicklei/go-restful-swagger12"
"github.com/googleapis/gnostic/OpenAPIv2" "github.com/googleapis/gnostic/OpenAPIv2"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
utilruntime "k8s.io/apimachinery/pkg/util/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/version" "k8s.io/apimachinery/pkg/version"
"k8s.io/client-go/discovery" "k8s.io/client-go/discovery"
...@@ -116,10 +114,6 @@ func (d *memCacheClient) ServerVersion() (*version.Info, error) { ...@@ -116,10 +114,6 @@ func (d *memCacheClient) ServerVersion() (*version.Info, error) {
return d.delegate.ServerVersion() return d.delegate.ServerVersion()
} }
func (d *memCacheClient) SwaggerSchema(version schema.GroupVersion) (*swagger.ApiDeclaration, error) {
return d.delegate.SwaggerSchema(version)
}
func (d *memCacheClient) OpenAPISchema() (*openapi_v2.Document, error) { func (d *memCacheClient) OpenAPISchema() (*openapi_v2.Document, error) {
return d.delegate.OpenAPISchema() return d.delegate.OpenAPISchema()
} }
......
...@@ -23,11 +23,9 @@ import ( ...@@ -23,11 +23,9 @@ import (
"sort" "sort"
"strings" "strings"
"github.com/emicklei/go-restful-swagger12"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"github.com/googleapis/gnostic/OpenAPIv2" "github.com/googleapis/gnostic/OpenAPIv2"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
...@@ -48,7 +46,6 @@ type DiscoveryInterface interface { ...@@ -48,7 +46,6 @@ type DiscoveryInterface interface {
ServerGroupsInterface ServerGroupsInterface
ServerResourcesInterface ServerResourcesInterface
ServerVersionInterface ServerVersionInterface
SwaggerSchemaInterface
OpenAPISchemaInterface OpenAPISchemaInterface
} }
...@@ -92,12 +89,6 @@ type ServerVersionInterface interface { ...@@ -92,12 +89,6 @@ type ServerVersionInterface interface {
ServerVersion() (*version.Info, error) ServerVersion() (*version.Info, error)
} }
// SwaggerSchemaInterface has a method to retrieve the swagger schema.
type SwaggerSchemaInterface interface {
// SwaggerSchema retrieves and parses the swagger API schema the server supports.
SwaggerSchema(version schema.GroupVersion) (*swagger.ApiDeclaration, error)
}
// OpenAPISchemaInterface has a method to retrieve the open API schema. // OpenAPISchemaInterface has a method to retrieve the open API schema.
type OpenAPISchemaInterface interface { type OpenAPISchemaInterface interface {
// OpenAPISchema retrieves and parses the swagger API schema the server supports. // OpenAPISchema retrieves and parses the swagger API schema the server supports.
...@@ -336,41 +327,6 @@ func (d *DiscoveryClient) ServerVersion() (*version.Info, error) { ...@@ -336,41 +327,6 @@ func (d *DiscoveryClient) ServerVersion() (*version.Info, error) {
return &info, nil return &info, nil
} }
// 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")
}
groupList, err := d.ServerGroups()
if err != nil {
return nil, err
}
groupVersions := metav1.ExtractGroupVersions(groupList)
// This check also takes care the case that kubectl is newer than the running endpoint
if stringDoesntExistIn(version.String(), groupVersions) {
return nil, fmt.Errorf("API version: %v is not supported by the server. Use one of: %v", version, groupVersions)
}
var path string
if len(d.LegacyPrefix) > 0 && version == v1.SchemeGroupVersion {
path = "/swaggerapi" + d.LegacyPrefix + "/" + version.Version
} else {
path = "/swaggerapi/apis/" + version.Group + "/" + version.Version
}
body, err := d.restClient.Get().AbsPath(path).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
}
// OpenAPISchema fetches the open api schema using a rest client and parses the proto. // OpenAPISchema fetches the open api schema using a rest client and parses the proto.
func (d *DiscoveryClient) OpenAPISchema() (*openapi_v2.Document, error) { func (d *DiscoveryClient) OpenAPISchema() (*openapi_v2.Document, error) {
data, err := d.restClient.Get().AbsPath("/swagger-2.0.0.pb-v1").Do().Raw() data, err := d.restClient.Get().AbsPath("/swagger-2.0.0.pb-v1").Do().Raw()
......
...@@ -25,11 +25,9 @@ import ( ...@@ -25,11 +25,9 @@ import (
"reflect" "reflect"
"testing" "testing"
"github.com/emicklei/go-restful-swagger12"
"github.com/gogo/protobuf/proto" "github.com/gogo/protobuf/proto"
"github.com/googleapis/gnostic/OpenAPIv2" "github.com/googleapis/gnostic/OpenAPIv2"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
...@@ -267,68 +265,6 @@ func TestGetServerResources(t *testing.T) { ...@@ -267,68 +265,6 @@ func TestGetServerResources(t *testing.T) {
} }
} }
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 = metav1.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)
}
defer server.Close()
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
got, err := client.SwaggerSchema(v1.SchemeGroupVersion)
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: api.group/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)
}
defer server.Close()
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
got, err := client.SwaggerSchema(schema.GroupVersion{Group: "api.group", Version: "v4"})
if got != nil {
t.Fatalf("unexpected response: %v", got)
}
if err.Error() != expErr {
t.Errorf("expected an error, got %v", err)
}
}
var returnedOpenAPI = openapi_v2.Document{ var returnedOpenAPI = openapi_v2.Document{
Definitions: &openapi_v2.Definitions{ Definitions: &openapi_v2.Definitions{
AdditionalProperties: []*openapi_v2.NamedSchema{ AdditionalProperties: []*openapi_v2.NamedSchema{
......
...@@ -10,9 +10,7 @@ go_library( ...@@ -10,9 +10,7 @@ go_library(
name = "go_default_library", name = "go_default_library",
srcs = ["discovery.go"], srcs = ["discovery.go"],
deps = [ deps = [
"//vendor/github.com/emicklei/go-restful-swagger12:go_default_library",
"//vendor/github.com/googleapis/gnostic/OpenAPIv2: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/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/version:go_default_library", "//vendor/k8s.io/apimachinery/pkg/version:go_default_library",
......
...@@ -19,10 +19,8 @@ package fake ...@@ -19,10 +19,8 @@ package fake
import ( import (
"fmt" "fmt"
"github.com/emicklei/go-restful-swagger12"
"github.com/googleapis/gnostic/OpenAPIv2" "github.com/googleapis/gnostic/OpenAPIv2"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/version" "k8s.io/apimachinery/pkg/version"
...@@ -87,19 +85,6 @@ func (c *FakeDiscovery) ServerVersion() (*version.Info, error) { ...@@ -87,19 +85,6 @@ func (c *FakeDiscovery) ServerVersion() (*version.Info, error) {
return &versionInfo, nil return &versionInfo, nil
} }
func (c *FakeDiscovery) SwaggerSchema(version schema.GroupVersion) (*swagger.ApiDeclaration, error) {
action := testing.ActionImpl{}
action.Verb = "get"
if version == v1.SchemeGroupVersion {
action.Resource = schema.GroupVersionResource{Resource: "/swaggerapi/api/" + version.Version}
} else {
action.Resource = schema.GroupVersionResource{Resource: "/swaggerapi/apis/" + version.Group + "/" + version.Version}
}
c.Invokes(action, nil)
return &swagger.ApiDeclaration{}, nil
}
func (c *FakeDiscovery) OpenAPISchema() (*openapi_v2.Document, error) { func (c *FakeDiscovery) OpenAPISchema() (*openapi_v2.Document, error) {
return &openapi_v2.Document{}, nil return &openapi_v2.Document{}, nil
} }
......
...@@ -28,7 +28,6 @@ import ( ...@@ -28,7 +28,6 @@ import (
restclient "k8s.io/client-go/rest" restclient "k8s.io/client-go/rest"
"k8s.io/client-go/rest/fake" "k8s.io/client-go/rest/fake"
"github.com/emicklei/go-restful-swagger12"
"github.com/googleapis/gnostic/OpenAPIv2" "github.com/googleapis/gnostic/OpenAPIv2"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
...@@ -380,10 +379,6 @@ func (c *fakeCachedDiscoveryInterface) ServerVersion() (*version.Info, error) { ...@@ -380,10 +379,6 @@ func (c *fakeCachedDiscoveryInterface) ServerVersion() (*version.Info, error) {
return &version.Info{}, nil return &version.Info{}, nil
} }
func (c *fakeCachedDiscoveryInterface) SwaggerSchema(version schema.GroupVersion) (*swagger.ApiDeclaration, error) {
return &swagger.ApiDeclaration{}, nil
}
func (c *fakeCachedDiscoveryInterface) OpenAPISchema() (*openapi_v2.Document, error) { func (c *fakeCachedDiscoveryInterface) OpenAPISchema() (*openapi_v2.Document, error) {
return &openapi_v2.Document{}, nil return &openapi_v2.Document{}, nil
} }
...@@ -23,10 +23,6 @@ ...@@ -23,10 +23,6 @@
"Rev": "ff4f55a206334ef123e4f79bbf348980da81ca46" "Rev": "ff4f55a206334ef123e4f79bbf348980da81ca46"
}, },
{ {
"ImportPath": "github.com/emicklei/go-restful-swagger12",
"Rev": "dcef7f55730566d41eae5db10e7d6981829720f6"
},
{
"ImportPath": "github.com/emicklei/go-restful/log", "ImportPath": "github.com/emicklei/go-restful/log",
"Rev": "ff4f55a206334ef123e4f79bbf348980da81ca46" "Rev": "ff4f55a206334ef123e4f79bbf348980da81ca46"
}, },
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment