move dynamic and discovery clients
This commit is contained in:
@@ -16,8 +16,8 @@ go_library(
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//cmd/kube-aggregator/pkg/client/clientset_generated/clientset/typed/apiregistration/v1alpha1:go_default_library",
|
||||
"//pkg/client/typed/discovery:go_default_library",
|
||||
"//vendor:github.com/golang/glog",
|
||||
"//vendor:k8s.io/client-go/discovery",
|
||||
"//vendor:k8s.io/client-go/plugin/pkg/client/auth",
|
||||
"//vendor:k8s.io/client-go/rest",
|
||||
"//vendor:k8s.io/client-go/util/flowcontrol",
|
||||
|
@@ -18,11 +18,11 @@ package clientset
|
||||
|
||||
import (
|
||||
"github.com/golang/glog"
|
||||
discovery "k8s.io/client-go/discovery"
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth"
|
||||
rest "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/util/flowcontrol"
|
||||
v1alpha1apiregistration "k8s.io/kubernetes/cmd/kube-aggregator/pkg/client/clientset_generated/clientset/typed/apiregistration/v1alpha1"
|
||||
discovery "k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
)
|
||||
|
||||
type Interface interface {
|
||||
|
@@ -20,10 +20,10 @@ go_library(
|
||||
"//cmd/kube-aggregator/pkg/client/clientset_generated/clientset/typed/apiregistration/v1alpha1/fake:go_default_library",
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/client/testing/core:go_default_library",
|
||||
"//pkg/client/typed/discovery:go_default_library",
|
||||
"//pkg/client/typed/discovery/fake:go_default_library",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||
"//vendor:k8s.io/apimachinery/pkg/watch",
|
||||
"//vendor:k8s.io/client-go/discovery",
|
||||
"//vendor:k8s.io/client-go/discovery/fake",
|
||||
],
|
||||
)
|
||||
|
||||
|
@@ -19,13 +19,13 @@ package fake
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/discovery"
|
||||
fakediscovery "k8s.io/client-go/discovery/fake"
|
||||
clientset "k8s.io/kubernetes/cmd/kube-aggregator/pkg/client/clientset_generated/clientset"
|
||||
v1alpha1apiregistration "k8s.io/kubernetes/cmd/kube-aggregator/pkg/client/clientset_generated/clientset/typed/apiregistration/v1alpha1"
|
||||
fakev1alpha1apiregistration "k8s.io/kubernetes/cmd/kube-aggregator/pkg/client/clientset_generated/clientset/typed/apiregistration/v1alpha1/fake"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/client/testing/core"
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
fakediscovery "k8s.io/kubernetes/pkg/client/typed/discovery/fake"
|
||||
)
|
||||
|
||||
// NewSimpleClientset returns a clientset that will respond with the provided objects.
|
||||
|
@@ -16,8 +16,8 @@ go_library(
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//cmd/kube-aggregator/pkg/client/clientset_generated/internalclientset/typed/apiregistration/internalversion:go_default_library",
|
||||
"//pkg/client/typed/discovery:go_default_library",
|
||||
"//vendor:github.com/golang/glog",
|
||||
"//vendor:k8s.io/client-go/discovery",
|
||||
"//vendor:k8s.io/client-go/plugin/pkg/client/auth",
|
||||
"//vendor:k8s.io/client-go/rest",
|
||||
"//vendor:k8s.io/client-go/util/flowcontrol",
|
||||
|
@@ -18,11 +18,11 @@ package internalclientset
|
||||
|
||||
import (
|
||||
"github.com/golang/glog"
|
||||
discovery "k8s.io/client-go/discovery"
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth"
|
||||
rest "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/util/flowcontrol"
|
||||
internalversionapiregistration "k8s.io/kubernetes/cmd/kube-aggregator/pkg/client/clientset_generated/internalclientset/typed/apiregistration/internalversion"
|
||||
discovery "k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
)
|
||||
|
||||
type Interface interface {
|
||||
|
@@ -20,10 +20,10 @@ go_library(
|
||||
"//cmd/kube-aggregator/pkg/client/clientset_generated/internalclientset/typed/apiregistration/internalversion/fake:go_default_library",
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/client/testing/core:go_default_library",
|
||||
"//pkg/client/typed/discovery:go_default_library",
|
||||
"//pkg/client/typed/discovery/fake:go_default_library",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||
"//vendor:k8s.io/apimachinery/pkg/watch",
|
||||
"//vendor:k8s.io/client-go/discovery",
|
||||
"//vendor:k8s.io/client-go/discovery/fake",
|
||||
],
|
||||
)
|
||||
|
||||
|
@@ -19,13 +19,13 @@ package fake
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/discovery"
|
||||
fakediscovery "k8s.io/client-go/discovery/fake"
|
||||
clientset "k8s.io/kubernetes/cmd/kube-aggregator/pkg/client/clientset_generated/internalclientset"
|
||||
internalversionapiregistration "k8s.io/kubernetes/cmd/kube-aggregator/pkg/client/clientset_generated/internalclientset/typed/apiregistration/internalversion"
|
||||
fakeinternalversionapiregistration "k8s.io/kubernetes/cmd/kube-aggregator/pkg/client/clientset_generated/internalclientset/typed/apiregistration/internalversion/fake"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/client/testing/core"
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
fakediscovery "k8s.io/kubernetes/pkg/client/typed/discovery/fake"
|
||||
)
|
||||
|
||||
// NewSimpleClientset returns a clientset that will respond with the provided objects.
|
||||
|
@@ -34,8 +34,6 @@ go_library(
|
||||
"//pkg/client/leaderelection:go_default_library",
|
||||
"//pkg/client/leaderelection/resourcelock:go_default_library",
|
||||
"//pkg/client/record:go_default_library",
|
||||
"//pkg/client/typed/discovery:go_default_library",
|
||||
"//pkg/client/typed/dynamic:go_default_library",
|
||||
"//pkg/cloudprovider:go_default_library",
|
||||
"//pkg/cloudprovider/providers:go_default_library",
|
||||
"//pkg/cloudprovider/providers/aws:go_default_library",
|
||||
@@ -99,6 +97,8 @@ go_library(
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/wait",
|
||||
"//vendor:k8s.io/apiserver/pkg/server/healthz",
|
||||
"//vendor:k8s.io/apiserver/pkg/util/feature",
|
||||
"//vendor:k8s.io/client-go/discovery",
|
||||
"//vendor:k8s.io/client-go/dynamic",
|
||||
"//vendor:k8s.io/client-go/rest",
|
||||
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||
"//vendor:k8s.io/client-go/util/cert",
|
||||
|
@@ -36,6 +36,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apiserver/pkg/server/healthz"
|
||||
"k8s.io/client-go/discovery"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
certutil "k8s.io/client-go/util/cert"
|
||||
@@ -46,7 +47,6 @@ import (
|
||||
"k8s.io/kubernetes/pkg/client/leaderelection"
|
||||
"k8s.io/kubernetes/pkg/client/leaderelection/resourcelock"
|
||||
"k8s.io/kubernetes/pkg/client/record"
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
"k8s.io/kubernetes/pkg/cloudprovider"
|
||||
"k8s.io/kubernetes/pkg/controller"
|
||||
"k8s.io/kubernetes/pkg/controller/informers"
|
||||
|
@@ -26,11 +26,11 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/client-go/discovery"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
||||
"k8s.io/kubernetes/pkg/controller"
|
||||
endpointcontroller "k8s.io/kubernetes/pkg/controller/endpoint"
|
||||
"k8s.io/kubernetes/pkg/controller/garbagecollector"
|
||||
|
@@ -45,9 +45,9 @@ go_test(
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//pkg/client/clientset_generated/clientset:go_default_library",
|
||||
"//pkg/client/typed/discovery:go_default_library",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
"//vendor:k8s.io/apimachinery/pkg/version",
|
||||
"//vendor:k8s.io/client-go/discovery",
|
||||
"//vendor:k8s.io/client-go/rest",
|
||||
],
|
||||
)
|
||||
|
@@ -24,10 +24,10 @@ import (
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/version"
|
||||
"k8s.io/client-go/discovery"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
)
|
||||
|
||||
func TestEstablishMasterConnection(t *testing.T) {
|
||||
|
@@ -71,8 +71,8 @@ func (g *genClientset) Imports(c *generator.Context) (imports []string) {
|
||||
imports = append(imports,
|
||||
"k8s.io/kubernetes/pkg/api",
|
||||
"k8s.io/kubernetes/pkg/client/testing/core",
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery",
|
||||
"fakediscovery \"k8s.io/kubernetes/pkg/client/typed/discovery/fake\"",
|
||||
"k8s.io/client-go/discovery",
|
||||
"fakediscovery \"k8s.io/client-go/discovery/fake\"",
|
||||
"k8s.io/apimachinery/pkg/runtime",
|
||||
"k8s.io/apimachinery/pkg/watch",
|
||||
)
|
||||
|
@@ -72,7 +72,7 @@ func (g *genClientset) GenerateType(c *generator.Context, t *types.Type, w io.Wr
|
||||
// TODO: We actually don't need any type information to generate the clientset,
|
||||
// perhaps we can adapt the go2ild framework to this kind of usage.
|
||||
sw := generator.NewSnippetWriter(w, c, "$", "$")
|
||||
const pkgDiscovery = "k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
const pkgDiscovery = "k8s.io/client-go/discovery"
|
||||
const pkgRESTClient = "k8s.io/client-go/rest"
|
||||
|
||||
allGroups := clientgentypes.ToGroupVersionPackages(g.groups)
|
||||
|
@@ -17,8 +17,8 @@ go_library(
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//cmd/libs/go2idl/client-gen/testoutput/clientset_generated/test_internalclientset/typed/testgroup/internalversion:go_default_library",
|
||||
"//pkg/client/typed/discovery:go_default_library",
|
||||
"//vendor:github.com/golang/glog",
|
||||
"//vendor:k8s.io/client-go/discovery",
|
||||
"//vendor:k8s.io/client-go/plugin/pkg/client/auth",
|
||||
"//vendor:k8s.io/client-go/rest",
|
||||
"//vendor:k8s.io/client-go/util/flowcontrol",
|
||||
|
@@ -18,11 +18,11 @@ package test_internalclientset
|
||||
|
||||
import (
|
||||
"github.com/golang/glog"
|
||||
discovery "k8s.io/client-go/discovery"
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth"
|
||||
rest "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/util/flowcontrol"
|
||||
internalversiontestgroup "k8s.io/kubernetes/cmd/libs/go2idl/client-gen/testoutput/clientset_generated/test_internalclientset/typed/testgroup/internalversion"
|
||||
discovery "k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
)
|
||||
|
||||
type Interface interface {
|
||||
|
@@ -20,10 +20,10 @@ go_library(
|
||||
"//cmd/libs/go2idl/client-gen/testoutput/clientset_generated/test_internalclientset/typed/testgroup/internalversion/fake:go_default_library",
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/client/testing/core:go_default_library",
|
||||
"//pkg/client/typed/discovery:go_default_library",
|
||||
"//pkg/client/typed/discovery/fake:go_default_library",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||
"//vendor:k8s.io/apimachinery/pkg/watch",
|
||||
"//vendor:k8s.io/client-go/discovery",
|
||||
"//vendor:k8s.io/client-go/discovery/fake",
|
||||
],
|
||||
)
|
||||
|
||||
|
@@ -19,13 +19,13 @@ package fake
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/discovery"
|
||||
fakediscovery "k8s.io/client-go/discovery/fake"
|
||||
clientset "k8s.io/kubernetes/cmd/libs/go2idl/client-gen/testoutput/clientset_generated/test_internalclientset"
|
||||
internalversiontestgroup "k8s.io/kubernetes/cmd/libs/go2idl/client-gen/testoutput/clientset_generated/test_internalclientset/typed/testgroup/internalversion"
|
||||
fakeinternalversiontestgroup "k8s.io/kubernetes/cmd/libs/go2idl/client-gen/testoutput/clientset_generated/test_internalclientset/typed/testgroup/internalversion/fake"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/client/testing/core"
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
fakediscovery "k8s.io/kubernetes/pkg/client/typed/discovery/fake"
|
||||
)
|
||||
|
||||
// NewSimpleClientset returns a clientset that will respond with the provided objects.
|
||||
|
@@ -22,8 +22,8 @@ go_library(
|
||||
"//federation/client/clientset_generated/federation_clientset/typed/core/v1:go_default_library",
|
||||
"//federation/client/clientset_generated/federation_clientset/typed/extensions/v1beta1:go_default_library",
|
||||
"//federation/client/clientset_generated/federation_clientset/typed/federation/v1beta1:go_default_library",
|
||||
"//pkg/client/typed/discovery:go_default_library",
|
||||
"//vendor:github.com/golang/glog",
|
||||
"//vendor:k8s.io/client-go/discovery",
|
||||
"//vendor:k8s.io/client-go/plugin/pkg/client/auth",
|
||||
"//vendor:k8s.io/client-go/rest",
|
||||
"//vendor:k8s.io/client-go/util/flowcontrol",
|
||||
|
@@ -18,6 +18,7 @@ package federation_clientset
|
||||
|
||||
import (
|
||||
"github.com/golang/glog"
|
||||
discovery "k8s.io/client-go/discovery"
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth"
|
||||
rest "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/util/flowcontrol"
|
||||
@@ -26,7 +27,6 @@ import (
|
||||
v1core "k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset/typed/core/v1"
|
||||
v1beta1extensions "k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset/typed/extensions/v1beta1"
|
||||
v1beta1federation "k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset/typed/federation/v1beta1"
|
||||
discovery "k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
)
|
||||
|
||||
type Interface interface {
|
||||
|
@@ -28,10 +28,10 @@ go_library(
|
||||
"//federation/client/clientset_generated/federation_clientset/typed/federation/v1beta1/fake:go_default_library",
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/client/testing/core:go_default_library",
|
||||
"//pkg/client/typed/discovery:go_default_library",
|
||||
"//pkg/client/typed/discovery/fake:go_default_library",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||
"//vendor:k8s.io/apimachinery/pkg/watch",
|
||||
"//vendor:k8s.io/client-go/discovery",
|
||||
"//vendor:k8s.io/client-go/discovery/fake",
|
||||
],
|
||||
)
|
||||
|
||||
|
@@ -19,6 +19,8 @@ package fake
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/discovery"
|
||||
fakediscovery "k8s.io/client-go/discovery/fake"
|
||||
clientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset"
|
||||
v1autoscaling "k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset/typed/autoscaling/v1"
|
||||
fakev1autoscaling "k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset/typed/autoscaling/v1/fake"
|
||||
@@ -32,8 +34,6 @@ import (
|
||||
fakev1beta1federation "k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset/typed/federation/v1beta1/fake"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/client/testing/core"
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
fakediscovery "k8s.io/kubernetes/pkg/client/typed/discovery/fake"
|
||||
)
|
||||
|
||||
// NewSimpleClientset returns a clientset that will respond with the provided objects.
|
||||
|
@@ -22,8 +22,8 @@ go_library(
|
||||
"//federation/client/clientset_generated/federation_internalclientset/typed/core/internalversion:go_default_library",
|
||||
"//federation/client/clientset_generated/federation_internalclientset/typed/extensions/internalversion:go_default_library",
|
||||
"//federation/client/clientset_generated/federation_internalclientset/typed/federation/internalversion:go_default_library",
|
||||
"//pkg/client/typed/discovery:go_default_library",
|
||||
"//vendor:github.com/golang/glog",
|
||||
"//vendor:k8s.io/client-go/discovery",
|
||||
"//vendor:k8s.io/client-go/plugin/pkg/client/auth",
|
||||
"//vendor:k8s.io/client-go/rest",
|
||||
"//vendor:k8s.io/client-go/util/flowcontrol",
|
||||
|
@@ -18,6 +18,7 @@ package federation_internalclientset
|
||||
|
||||
import (
|
||||
"github.com/golang/glog"
|
||||
discovery "k8s.io/client-go/discovery"
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth"
|
||||
rest "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/util/flowcontrol"
|
||||
@@ -26,7 +27,6 @@ import (
|
||||
internalversioncore "k8s.io/kubernetes/federation/client/clientset_generated/federation_internalclientset/typed/core/internalversion"
|
||||
internalversionextensions "k8s.io/kubernetes/federation/client/clientset_generated/federation_internalclientset/typed/extensions/internalversion"
|
||||
internalversionfederation "k8s.io/kubernetes/federation/client/clientset_generated/federation_internalclientset/typed/federation/internalversion"
|
||||
discovery "k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
)
|
||||
|
||||
type Interface interface {
|
||||
|
@@ -28,10 +28,10 @@ go_library(
|
||||
"//federation/client/clientset_generated/federation_internalclientset/typed/federation/internalversion/fake:go_default_library",
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/client/testing/core:go_default_library",
|
||||
"//pkg/client/typed/discovery:go_default_library",
|
||||
"//pkg/client/typed/discovery/fake:go_default_library",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||
"//vendor:k8s.io/apimachinery/pkg/watch",
|
||||
"//vendor:k8s.io/client-go/discovery",
|
||||
"//vendor:k8s.io/client-go/discovery/fake",
|
||||
],
|
||||
)
|
||||
|
||||
|
@@ -19,6 +19,8 @@ package fake
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/discovery"
|
||||
fakediscovery "k8s.io/client-go/discovery/fake"
|
||||
clientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_internalclientset"
|
||||
internalversionautoscaling "k8s.io/kubernetes/federation/client/clientset_generated/federation_internalclientset/typed/autoscaling/internalversion"
|
||||
fakeinternalversionautoscaling "k8s.io/kubernetes/federation/client/clientset_generated/federation_internalclientset/typed/autoscaling/internalversion/fake"
|
||||
@@ -32,8 +34,6 @@ import (
|
||||
fakeinternalversionfederation "k8s.io/kubernetes/federation/client/clientset_generated/federation_internalclientset/typed/federation/internalversion/fake"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/client/testing/core"
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
fakediscovery "k8s.io/kubernetes/pkg/client/typed/discovery/fake"
|
||||
)
|
||||
|
||||
// NewSimpleClientset returns a clientset that will respond with the provided objects.
|
||||
|
@@ -32,7 +32,6 @@ go_library(
|
||||
"//federation/pkg/federation-controller/secret:go_default_library",
|
||||
"//federation/pkg/federation-controller/service:go_default_library",
|
||||
"//federation/pkg/federation-controller/util:go_default_library",
|
||||
"//pkg/client/typed/discovery:go_default_library",
|
||||
"//pkg/util/configz:go_default_library",
|
||||
"//pkg/version:go_default_library",
|
||||
"//vendor:github.com/golang/glog",
|
||||
@@ -44,6 +43,7 @@ go_library(
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/wait",
|
||||
"//vendor:k8s.io/apiserver/pkg/server/healthz",
|
||||
"//vendor:k8s.io/apiserver/pkg/util/flag",
|
||||
"//vendor:k8s.io/client-go/discovery",
|
||||
"//vendor:k8s.io/client-go/rest",
|
||||
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||
],
|
||||
|
@@ -53,7 +53,7 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
"k8s.io/client-go/discovery"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@@ -24,7 +24,6 @@ go_library(
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
||||
"//pkg/client/typed/discovery:go_default_library",
|
||||
"//pkg/controller:go_default_library",
|
||||
"//vendor:github.com/golang/glog",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
@@ -33,6 +32,7 @@ go_library(
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/sets",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/wait",
|
||||
"//vendor:k8s.io/apimachinery/pkg/watch",
|
||||
"//vendor:k8s.io/client-go/discovery",
|
||||
"//vendor:k8s.io/client-go/rest",
|
||||
"//vendor:k8s.io/client-go/tools/cache",
|
||||
],
|
||||
|
@@ -23,13 +23,13 @@ import (
|
||||
"github.com/golang/glog"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/client-go/discovery"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
federation_v1beta1 "k8s.io/kubernetes/federation/apis/federation/v1beta1"
|
||||
"k8s.io/kubernetes/federation/pkg/federation-controller/util"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@@ -53,12 +53,12 @@ go_test(
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/testapi:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/client/typed/dynamic:go_default_library",
|
||||
"//pkg/kubectl/cmd/testing:go_default_library",
|
||||
"//pkg/kubectl/cmd/util:go_default_library",
|
||||
"//vendor:k8s.io/apimachinery/pkg/api/errors",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/diff",
|
||||
"//vendor:k8s.io/client-go/dynamic",
|
||||
"//vendor:k8s.io/client-go/rest/fake",
|
||||
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
||||
|
@@ -46,13 +46,13 @@ go_test(
|
||||
"//pkg/api/testapi:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/apis/extensions/v1beta1:go_default_library",
|
||||
"//pkg/client/typed/dynamic:go_default_library",
|
||||
"//pkg/kubectl/cmd/testing:go_default_library",
|
||||
"//pkg/kubectl/cmd/util:go_default_library",
|
||||
"//pkg/util/intstr:go_default_library",
|
||||
"//vendor:k8s.io/apimachinery/pkg/api/errors",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/diff",
|
||||
"//vendor:k8s.io/client-go/dynamic",
|
||||
"//vendor:k8s.io/client-go/rest/fake",
|
||||
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||
],
|
||||
|
@@ -33,6 +33,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
kubefedtesting "k8s.io/kubernetes/federation/pkg/kubefed/testing"
|
||||
@@ -42,7 +43,6 @@ import (
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/util/intstr"
|
||||
|
@@ -25,6 +25,7 @@ import (
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
@@ -34,7 +35,6 @@ import (
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
)
|
||||
|
@@ -25,12 +25,12 @@ import (
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/rest/fake"
|
||||
federationapi "k8s.io/kubernetes/federation/apis/federation"
|
||||
kubefedtesting "k8s.io/kubernetes/federation/pkg/kubefed/testing"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
)
|
||||
|
@@ -73,8 +73,6 @@ filegroup(
|
||||
"//pkg/client/testing/cache:all-srcs",
|
||||
"//pkg/client/testing/core:all-srcs",
|
||||
"//pkg/client/tests:all-srcs",
|
||||
"//pkg/client/typed/discovery:all-srcs",
|
||||
"//pkg/client/typed/dynamic:all-srcs",
|
||||
"//pkg/client/unversioned:all-srcs",
|
||||
"//pkg/cloudprovider:all-srcs",
|
||||
"//pkg/controller:all-srcs",
|
||||
|
@@ -41,8 +41,8 @@ go_library(
|
||||
"//pkg/client/clientset_generated/clientset/typed/rbac/v1alpha1:go_default_library",
|
||||
"//pkg/client/clientset_generated/clientset/typed/rbac/v1beta1:go_default_library",
|
||||
"//pkg/client/clientset_generated/clientset/typed/storage/v1beta1:go_default_library",
|
||||
"//pkg/client/typed/discovery:go_default_library",
|
||||
"//vendor:github.com/golang/glog",
|
||||
"//vendor:k8s.io/client-go/discovery",
|
||||
"//vendor:k8s.io/client-go/plugin/pkg/client/auth",
|
||||
"//vendor:k8s.io/client-go/rest",
|
||||
"//vendor:k8s.io/client-go/util/flowcontrol",
|
||||
|
@@ -18,6 +18,7 @@ package clientset
|
||||
|
||||
import (
|
||||
"github.com/golang/glog"
|
||||
discovery "k8s.io/client-go/discovery"
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth"
|
||||
rest "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/util/flowcontrol"
|
||||
@@ -34,7 +35,6 @@ import (
|
||||
v1alpha1rbac "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/typed/rbac/v1alpha1"
|
||||
v1beta1rbac "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/typed/rbac/v1beta1"
|
||||
v1beta1storage "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/typed/storage/v1beta1"
|
||||
discovery "k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
)
|
||||
|
||||
type Interface interface {
|
||||
|
@@ -44,10 +44,10 @@ go_library(
|
||||
"//pkg/client/clientset_generated/clientset/typed/storage/v1beta1:go_default_library",
|
||||
"//pkg/client/clientset_generated/clientset/typed/storage/v1beta1/fake:go_default_library",
|
||||
"//pkg/client/testing/core:go_default_library",
|
||||
"//pkg/client/typed/discovery:go_default_library",
|
||||
"//pkg/client/typed/discovery/fake:go_default_library",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||
"//vendor:k8s.io/apimachinery/pkg/watch",
|
||||
"//vendor:k8s.io/client-go/discovery",
|
||||
"//vendor:k8s.io/client-go/discovery/fake",
|
||||
],
|
||||
)
|
||||
|
||||
|
@@ -19,6 +19,8 @@ package fake
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/discovery"
|
||||
fakediscovery "k8s.io/client-go/discovery/fake"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
||||
v1beta1apps "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/typed/apps/v1beta1"
|
||||
@@ -48,8 +50,6 @@ import (
|
||||
v1beta1storage "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/typed/storage/v1beta1"
|
||||
fakev1beta1storage "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/typed/storage/v1beta1/fake"
|
||||
"k8s.io/kubernetes/pkg/client/testing/core"
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
fakediscovery "k8s.io/kubernetes/pkg/client/typed/discovery/fake"
|
||||
)
|
||||
|
||||
// NewSimpleClientset returns a clientset that will respond with the provided objects.
|
||||
|
@@ -40,8 +40,8 @@ go_library(
|
||||
"//pkg/client/clientset_generated/internalclientset/typed/policy/internalversion:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset/typed/storage/internalversion:go_default_library",
|
||||
"//pkg/client/typed/discovery:go_default_library",
|
||||
"//vendor:github.com/golang/glog",
|
||||
"//vendor:k8s.io/client-go/discovery",
|
||||
"//vendor:k8s.io/client-go/plugin/pkg/client/auth",
|
||||
"//vendor:k8s.io/client-go/rest",
|
||||
"//vendor:k8s.io/client-go/util/flowcontrol",
|
||||
|
@@ -18,6 +18,7 @@ package internalclientset
|
||||
|
||||
import (
|
||||
"github.com/golang/glog"
|
||||
discovery "k8s.io/client-go/discovery"
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth"
|
||||
rest "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/util/flowcontrol"
|
||||
@@ -32,7 +33,6 @@ import (
|
||||
internalversionpolicy "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/policy/internalversion"
|
||||
internalversionrbac "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion"
|
||||
internalversionstorage "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion"
|
||||
discovery "k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
)
|
||||
|
||||
type Interface interface {
|
||||
|
@@ -40,10 +40,10 @@ go_library(
|
||||
"//pkg/client/clientset_generated/internalclientset/typed/storage/internalversion:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/fake:go_default_library",
|
||||
"//pkg/client/testing/core:go_default_library",
|
||||
"//pkg/client/typed/discovery:go_default_library",
|
||||
"//pkg/client/typed/discovery/fake:go_default_library",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||
"//vendor:k8s.io/apimachinery/pkg/watch",
|
||||
"//vendor:k8s.io/client-go/discovery",
|
||||
"//vendor:k8s.io/client-go/discovery/fake",
|
||||
],
|
||||
)
|
||||
|
||||
|
@@ -19,6 +19,8 @@ package fake
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/discovery"
|
||||
fakediscovery "k8s.io/client-go/discovery/fake"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
internalversionapps "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/apps/internalversion"
|
||||
@@ -44,8 +46,6 @@ import (
|
||||
internalversionstorage "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion"
|
||||
fakeinternalversionstorage "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/fake"
|
||||
"k8s.io/kubernetes/pkg/client/testing/core"
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
fakediscovery "k8s.io/kubernetes/pkg/client/typed/discovery/fake"
|
||||
)
|
||||
|
||||
// NewSimpleClientset returns a clientset that will respond with the provided objects.
|
||||
|
@@ -1,15 +0,0 @@
|
||||
reviewers:
|
||||
- smarterclayton
|
||||
- wojtek-t
|
||||
- deads2k
|
||||
- derekwaynecarr
|
||||
- caesarxuchao
|
||||
- nikhiljindal
|
||||
- soltysh
|
||||
- piosz
|
||||
- hongchaodeng
|
||||
- krousey
|
||||
- jdef
|
||||
- jessfraz
|
||||
- pweil-
|
||||
- goltermann
|
@@ -1,79 +0,0 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"discovery_client.go",
|
||||
"helper.go",
|
||||
"restmapper.go",
|
||||
"unstructured.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/version:go_default_library",
|
||||
"//vendor:github.com/emicklei/go-restful/swagger",
|
||||
"//vendor:github.com/golang/glog",
|
||||
"//vendor:k8s.io/apimachinery/pkg/api/errors",
|
||||
"//vendor:k8s.io/apimachinery/pkg/api/meta",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime/serializer",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/sets",
|
||||
"//vendor:k8s.io/apimachinery/pkg/version",
|
||||
"//vendor:k8s.io/client-go/plugin/pkg/client/auth",
|
||||
"//vendor:k8s.io/client-go/rest",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_xtest",
|
||||
srcs = [
|
||||
"discovery_client_test.go",
|
||||
"helper_blackbox_test.go",
|
||||
"restmapper_test.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/testapi:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/client/typed/discovery:go_default_library",
|
||||
"//vendor:github.com/emicklei/go-restful/swagger",
|
||||
"//vendor:github.com/stretchr/testify/assert",
|
||||
"//vendor:k8s.io/apimachinery/pkg/api/errors",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/sets",
|
||||
"//vendor:k8s.io/apimachinery/pkg/version",
|
||||
"//vendor:k8s.io/client-go/rest",
|
||||
"//vendor:k8s.io/client-go/rest/fake",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//pkg/client/typed/discovery/fake:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
@@ -1,437 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package discovery
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/emicklei/go-restful/swagger"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/apimachinery/pkg/version"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
)
|
||||
|
||||
// defaultRetries is the number of times a resource discovery is repeated if an api group disappears on the fly (e.g. ThirdPartyResources).
|
||||
const defaultRetries = 2
|
||||
|
||||
// DiscoveryInterface holds the methods that discover server-supported API groups,
|
||||
// versions and resources.
|
||||
type DiscoveryInterface interface {
|
||||
RESTClient() restclient.Interface
|
||||
ServerGroupsInterface
|
||||
ServerResourcesInterface
|
||||
ServerVersionInterface
|
||||
SwaggerSchemaInterface
|
||||
}
|
||||
|
||||
// CachedDiscoveryInterface is a DiscoveryInterface with cache invalidation and freshness.
|
||||
type CachedDiscoveryInterface interface {
|
||||
DiscoveryInterface
|
||||
// Fresh returns true if no cached data was used that had been retrieved before the instantiation.
|
||||
Fresh() bool
|
||||
// Invalidate enforces that no cached data is used in the future that is older than the current time.
|
||||
Invalidate()
|
||||
}
|
||||
|
||||
// ServerGroupsInterface has methods for obtaining supported groups on the API server
|
||||
type ServerGroupsInterface interface {
|
||||
// ServerGroups returns the supported groups, with information like supported versions and the
|
||||
// preferred version.
|
||||
ServerGroups() (*metav1.APIGroupList, error)
|
||||
}
|
||||
|
||||
// ServerResourcesInterface has methods for obtaining supported resources on the API server
|
||||
type ServerResourcesInterface interface {
|
||||
// ServerResourcesForGroupVersion returns the supported resources for a group and version.
|
||||
ServerResourcesForGroupVersion(groupVersion string) (*metav1.APIResourceList, error)
|
||||
// ServerResources returns the supported resources for all groups and versions.
|
||||
ServerResources() ([]*metav1.APIResourceList, error)
|
||||
// ServerPreferredResources returns the supported resources with the version preferred by the
|
||||
// server.
|
||||
ServerPreferredResources() ([]*metav1.APIResourceList, error)
|
||||
// ServerPreferredNamespacedResources returns the supported namespaced resources with the
|
||||
// version preferred by the server.
|
||||
ServerPreferredNamespacedResources() ([]*metav1.APIResourceList, error)
|
||||
}
|
||||
|
||||
// ServerVersionInterface has a method for retrieving the server's version.
|
||||
type ServerVersionInterface interface {
|
||||
// ServerVersion retrieves and parses the server's version (git version).
|
||||
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)
|
||||
}
|
||||
|
||||
// DiscoveryClient implements the functions that discover server-supported API groups,
|
||||
// versions and resources.
|
||||
type DiscoveryClient struct {
|
||||
restClient restclient.Interface
|
||||
|
||||
LegacyPrefix string
|
||||
}
|
||||
|
||||
// Convert metav1.APIVersions to metav1.APIGroup. APIVersions is used by legacy v1, so
|
||||
// group would be "".
|
||||
func apiVersionsToAPIGroup(apiVersions *metav1.APIVersions) (apiGroup metav1.APIGroup) {
|
||||
groupVersions := []metav1.GroupVersionForDiscovery{}
|
||||
for _, version := range apiVersions.Versions {
|
||||
groupVersion := metav1.GroupVersionForDiscovery{
|
||||
GroupVersion: version,
|
||||
Version: version,
|
||||
}
|
||||
groupVersions = append(groupVersions, groupVersion)
|
||||
}
|
||||
apiGroup.Versions = groupVersions
|
||||
// There should be only one groupVersion returned at /api
|
||||
apiGroup.PreferredVersion = groupVersions[0]
|
||||
return
|
||||
}
|
||||
|
||||
// ServerGroups returns the supported groups, with information like supported versions and the
|
||||
// preferred version.
|
||||
func (d *DiscoveryClient) ServerGroups() (apiGroupList *metav1.APIGroupList, err error) {
|
||||
// Get the groupVersions exposed at /api
|
||||
v := &metav1.APIVersions{}
|
||||
err = d.restClient.Get().AbsPath(d.LegacyPrefix).Do().Into(v)
|
||||
apiGroup := metav1.APIGroup{}
|
||||
if err == nil {
|
||||
apiGroup = apiVersionsToAPIGroup(v)
|
||||
}
|
||||
if err != nil && !errors.IsNotFound(err) && !errors.IsForbidden(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get the groupVersions exposed at /apis
|
||||
apiGroupList = &metav1.APIGroupList{}
|
||||
err = d.restClient.Get().AbsPath("/apis").Do().Into(apiGroupList)
|
||||
if err != nil && !errors.IsNotFound(err) && !errors.IsForbidden(err) {
|
||||
return nil, err
|
||||
}
|
||||
// to be compatible with a v1.0 server, if it's a 403 or 404, ignore and return whatever we got from /api
|
||||
if err != nil && (errors.IsNotFound(err) || errors.IsForbidden(err)) {
|
||||
apiGroupList = &metav1.APIGroupList{}
|
||||
}
|
||||
|
||||
// append the group retrieved from /api to the list
|
||||
apiGroupList.Groups = append(apiGroupList.Groups, apiGroup)
|
||||
return apiGroupList, nil
|
||||
}
|
||||
|
||||
// ServerResourcesForGroupVersion returns the supported resources for a group and version.
|
||||
func (d *DiscoveryClient) ServerResourcesForGroupVersion(groupVersion string) (resources *metav1.APIResourceList, err error) {
|
||||
url := url.URL{}
|
||||
if len(groupVersion) == 0 {
|
||||
return nil, fmt.Errorf("groupVersion shouldn't be empty")
|
||||
}
|
||||
if len(d.LegacyPrefix) > 0 && groupVersion == "v1" {
|
||||
url.Path = d.LegacyPrefix + "/" + groupVersion
|
||||
} else {
|
||||
url.Path = "/apis/" + groupVersion
|
||||
}
|
||||
resources = &metav1.APIResourceList{
|
||||
GroupVersion: groupVersion,
|
||||
}
|
||||
err = d.restClient.Get().AbsPath(url.String()).Do().Into(resources)
|
||||
if err != nil {
|
||||
// ignore 403 or 404 error to be compatible with an v1.0 server.
|
||||
if groupVersion == "v1" && (errors.IsNotFound(err) || errors.IsForbidden(err)) {
|
||||
return resources, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return resources, nil
|
||||
}
|
||||
|
||||
// serverResources returns the supported resources for all groups and versions.
|
||||
func (d *DiscoveryClient) serverResources(failEarly bool) ([]*metav1.APIResourceList, error) {
|
||||
apiGroups, err := d.ServerGroups()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := []*metav1.APIResourceList{}
|
||||
failedGroups := make(map[schema.GroupVersion]error)
|
||||
|
||||
for _, apiGroup := range apiGroups.Groups {
|
||||
for _, version := range apiGroup.Versions {
|
||||
gv := schema.GroupVersion{Group: apiGroup.Name, Version: version.Version}
|
||||
resources, err := d.ServerResourcesForGroupVersion(version.GroupVersion)
|
||||
if err != nil {
|
||||
// TODO: maybe restrict this to NotFound errors
|
||||
failedGroups[gv] = err
|
||||
if failEarly {
|
||||
return nil, &ErrGroupDiscoveryFailed{Groups: failedGroups}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
result = append(result, resources)
|
||||
}
|
||||
}
|
||||
|
||||
if len(failedGroups) == 0 {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
return result, &ErrGroupDiscoveryFailed{Groups: failedGroups}
|
||||
}
|
||||
|
||||
// ServerResources returns the supported resources for all groups and versions.
|
||||
func (d *DiscoveryClient) ServerResources() ([]*metav1.APIResourceList, error) {
|
||||
return withRetries(defaultRetries, d.serverResources)
|
||||
}
|
||||
|
||||
// ErrGroupDiscoveryFailed is returned if one or more API groups fail to load.
|
||||
type ErrGroupDiscoveryFailed struct {
|
||||
// Groups is a list of the groups that failed to load and the error cause
|
||||
Groups map[schema.GroupVersion]error
|
||||
}
|
||||
|
||||
// Error implements the error interface
|
||||
func (e *ErrGroupDiscoveryFailed) Error() string {
|
||||
var groups []string
|
||||
for k, v := range e.Groups {
|
||||
groups = append(groups, fmt.Sprintf("%s: %v", k, v))
|
||||
}
|
||||
sort.Strings(groups)
|
||||
return fmt.Sprintf("unable to retrieve the complete list of server APIs: %s", strings.Join(groups, ", "))
|
||||
}
|
||||
|
||||
// IsGroupDiscoveryFailedError returns true if the provided error indicates the server was unable to discover
|
||||
// a complete list of APIs for the client to use.
|
||||
func IsGroupDiscoveryFailedError(err error) bool {
|
||||
_, ok := err.(*ErrGroupDiscoveryFailed)
|
||||
return err != nil && ok
|
||||
}
|
||||
|
||||
// serverPreferredResources returns the supported resources with the version preferred by the server.
|
||||
func (d *DiscoveryClient) serverPreferredResources(failEarly bool) ([]*metav1.APIResourceList, error) {
|
||||
serverGroupList, err := d.ServerGroups()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := []*metav1.APIResourceList{}
|
||||
failedGroups := make(map[schema.GroupVersion]error)
|
||||
|
||||
grVersions := map[schema.GroupResource]string{} // selected version of a GroupResource
|
||||
grApiResources := map[schema.GroupResource]*metav1.APIResource{} // selected APIResource for a GroupResource
|
||||
gvApiResourceLists := map[schema.GroupVersion]*metav1.APIResourceList{} // blueprint for a APIResourceList for later grouping
|
||||
|
||||
for _, apiGroup := range serverGroupList.Groups {
|
||||
for _, version := range apiGroup.Versions {
|
||||
groupVersion := schema.GroupVersion{Group: apiGroup.Name, Version: version.Version}
|
||||
apiResourceList, err := d.ServerResourcesForGroupVersion(version.GroupVersion)
|
||||
if err != nil {
|
||||
// TODO: maybe restrict this to NotFound errors
|
||||
failedGroups[groupVersion] = err
|
||||
if failEarly {
|
||||
return nil, &ErrGroupDiscoveryFailed{Groups: failedGroups}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// create empty list which is filled later in another loop
|
||||
emptyApiResourceList := metav1.APIResourceList{
|
||||
GroupVersion: version.GroupVersion,
|
||||
}
|
||||
gvApiResourceLists[groupVersion] = &emptyApiResourceList
|
||||
result = append(result, &emptyApiResourceList)
|
||||
|
||||
for i := range apiResourceList.APIResources {
|
||||
apiResource := &apiResourceList.APIResources[i]
|
||||
if strings.Contains(apiResource.Name, "/") {
|
||||
continue
|
||||
}
|
||||
gv := schema.GroupResource{Group: apiGroup.Name, Resource: apiResource.Name}
|
||||
if _, ok := grApiResources[gv]; ok && version.Version != apiGroup.PreferredVersion.Version {
|
||||
// only override with preferred version
|
||||
continue
|
||||
}
|
||||
grVersions[gv] = version.Version
|
||||
grApiResources[gv] = apiResource
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// group selected APIResources according to GroupVersion into APIResourceLists
|
||||
for groupResource, apiResource := range grApiResources {
|
||||
version := grVersions[groupResource]
|
||||
groupVersion := schema.GroupVersion{Group: groupResource.Group, Version: version}
|
||||
apiResourceList := gvApiResourceLists[groupVersion]
|
||||
apiResourceList.APIResources = append(apiResourceList.APIResources, *apiResource)
|
||||
}
|
||||
|
||||
if len(failedGroups) == 0 {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
return result, &ErrGroupDiscoveryFailed{Groups: failedGroups}
|
||||
}
|
||||
|
||||
// ServerPreferredResources returns the supported resources with the version preferred by the
|
||||
// server.
|
||||
func (d *DiscoveryClient) ServerPreferredResources() ([]*metav1.APIResourceList, error) {
|
||||
return withRetries(defaultRetries, func(retryEarly bool) ([]*metav1.APIResourceList, error) {
|
||||
return d.serverPreferredResources(retryEarly)
|
||||
})
|
||||
}
|
||||
|
||||
// ServerPreferredNamespacedResources returns the supported namespaced resources with the
|
||||
// version preferred by the server.
|
||||
func (d *DiscoveryClient) ServerPreferredNamespacedResources() ([]*metav1.APIResourceList, error) {
|
||||
all, err := d.ServerPreferredResources()
|
||||
return FilteredBy(ResourcePredicateFunc(func(groupVersion string, r *metav1.APIResource) bool {
|
||||
return r.Namespaced
|
||||
}), all), err
|
||||
}
|
||||
|
||||
// ServerVersion retrieves and parses the server's version (git version).
|
||||
func (d *DiscoveryClient) ServerVersion() (*version.Info, error) {
|
||||
body, err := d.restClient.Get().AbsPath("/version").Do().Raw()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var info version.Info
|
||||
err = json.Unmarshal(body, &info)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("got '%s': %v", string(body), err)
|
||||
}
|
||||
return &info, nil
|
||||
}
|
||||
|
||||
// SwaggerSchema retrieves and parses the swagger API schema the server supports.
|
||||
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
|
||||
}
|
||||
|
||||
// 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
|
||||
var err error
|
||||
for i := 0; i < maxRetries; i++ {
|
||||
failEarly := i < maxRetries-1
|
||||
result, err = f(failEarly)
|
||||
if err == nil {
|
||||
return result, nil
|
||||
}
|
||||
if _, ok := err.(*ErrGroupDiscoveryFailed); !ok {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func setDiscoveryDefaults(config *restclient.Config) error {
|
||||
config.APIPath = ""
|
||||
config.GroupVersion = nil
|
||||
codec := runtime.NoopEncoder{Decoder: api.Codecs.UniversalDecoder()}
|
||||
config.NegotiatedSerializer = serializer.NegotiatedSerializerWrapper(runtime.SerializerInfo{Serializer: codec})
|
||||
if len(config.UserAgent) == 0 {
|
||||
config.UserAgent = restclient.DefaultKubernetesUserAgent()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewDiscoveryClientForConfig creates a new DiscoveryClient for the given config. This client
|
||||
// can be used to discover supported resources in the API server.
|
||||
func NewDiscoveryClientForConfig(c *restclient.Config) (*DiscoveryClient, error) {
|
||||
config := *c
|
||||
if err := setDiscoveryDefaults(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client, err := restclient.UnversionedRESTClientFor(&config)
|
||||
return &DiscoveryClient{restClient: client, LegacyPrefix: "/api"}, err
|
||||
}
|
||||
|
||||
// NewDiscoveryClientForConfig creates a new DiscoveryClient for the given config. If
|
||||
// there is an error, it panics.
|
||||
func NewDiscoveryClientForConfigOrDie(c *restclient.Config) *DiscoveryClient {
|
||||
client, err := NewDiscoveryClientForConfig(c)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return client
|
||||
|
||||
}
|
||||
|
||||
// New creates a new DiscoveryClient for the given RESTClient.
|
||||
func NewDiscoveryClient(c restclient.Interface) *DiscoveryClient {
|
||||
return &DiscoveryClient{restClient: c, LegacyPrefix: "/api"}
|
||||
}
|
||||
|
||||
func stringDoesntExistIn(str string, slice []string) bool {
|
||||
for _, s := range slice {
|
||||
if s == str {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// RESTClient returns a RESTClient that is used to communicate
|
||||
// with API server by this client implementation.
|
||||
func (c *DiscoveryClient) RESTClient() restclient.Interface {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
return c.restClient
|
||||
}
|
@@ -1,740 +0,0 @@
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package discovery_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/emicklei/go-restful/swagger"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/version"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
. "k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
)
|
||||
|
||||
func TestGetServerVersion(t *testing.T) {
|
||||
expect := version.Info{
|
||||
Major: "foo",
|
||||
Minor: "bar",
|
||||
GitCommit: "baz",
|
||||
}
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
output, err := json.Marshal(expect)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected encoding error: %v", err)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(output)
|
||||
}))
|
||||
defer server.Close()
|
||||
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
|
||||
|
||||
got, err := client.ServerVersion()
|
||||
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 TestGetServerGroupsWithV1Server(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
var obj interface{}
|
||||
switch req.URL.Path {
|
||||
case "/api":
|
||||
obj = &metav1.APIVersions{
|
||||
Versions: []string{
|
||||
"v1",
|
||||
},
|
||||
}
|
||||
default:
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
output, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected encoding error: %v", err)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(output)
|
||||
}))
|
||||
defer server.Close()
|
||||
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
|
||||
// ServerGroups should not return an error even if server returns error at /api and /apis
|
||||
apiGroupList, err := client.ServerGroups()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
groupVersions := metav1.ExtractGroupVersions(apiGroupList)
|
||||
if !reflect.DeepEqual(groupVersions, []string{"v1"}) {
|
||||
t.Errorf("expected: %q, got: %q", []string{"v1"}, groupVersions)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetServerGroupsWithBrokenServer(t *testing.T) {
|
||||
for _, statusCode := range []int{http.StatusNotFound, http.StatusForbidden} {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
w.WriteHeader(statusCode)
|
||||
}))
|
||||
defer server.Close()
|
||||
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
|
||||
// ServerGroups should not return an error even if server returns Not Found or Forbidden error at all end points
|
||||
apiGroupList, err := client.ServerGroups()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
groupVersions := metav1.ExtractGroupVersions(apiGroupList)
|
||||
if len(groupVersions) != 0 {
|
||||
t.Errorf("expected empty list, got: %q", groupVersions)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetServerResourcesWithV1Server(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
var obj interface{}
|
||||
switch req.URL.Path {
|
||||
case "/api":
|
||||
obj = &metav1.APIVersions{
|
||||
Versions: []string{
|
||||
"v1",
|
||||
},
|
||||
}
|
||||
default:
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
output, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected encoding error: %v", err)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(output)
|
||||
}))
|
||||
defer server.Close()
|
||||
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
|
||||
// ServerResources should not return an error even if server returns error at /api/v1.
|
||||
serverResources, err := client.ServerResources()
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
gvs := groupVersions(serverResources)
|
||||
if !sets.NewString(gvs...).Has("v1") {
|
||||
t.Errorf("missing v1 in resource list: %v", serverResources)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetServerResources(t *testing.T) {
|
||||
stable := metav1.APIResourceList{
|
||||
GroupVersion: "v1",
|
||||
APIResources: []metav1.APIResource{
|
||||
{Name: "pods", Namespaced: true, Kind: "Pod"},
|
||||
{Name: "services", Namespaced: true, Kind: "Service"},
|
||||
{Name: "namespaces", Namespaced: false, Kind: "Namespace"},
|
||||
},
|
||||
}
|
||||
beta := metav1.APIResourceList{
|
||||
GroupVersion: "extensions/v1beta1",
|
||||
APIResources: []metav1.APIResource{
|
||||
{Name: "deployments", Namespaced: true, Kind: "Deployment"},
|
||||
{Name: "ingresses", Namespaced: true, Kind: "Ingress"},
|
||||
{Name: "jobs", Namespaced: true, Kind: "Job"},
|
||||
},
|
||||
}
|
||||
tests := []struct {
|
||||
resourcesList *metav1.APIResourceList
|
||||
path string
|
||||
request string
|
||||
expectErr bool
|
||||
}{
|
||||
{
|
||||
resourcesList: &stable,
|
||||
path: "/api/v1",
|
||||
request: "v1",
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
resourcesList: &beta,
|
||||
path: "/apis/extensions/v1beta1",
|
||||
request: "extensions/v1beta1",
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
resourcesList: &stable,
|
||||
path: "/api/v1",
|
||||
request: "foobar",
|
||||
expectErr: true,
|
||||
},
|
||||
}
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
var list interface{}
|
||||
switch req.URL.Path {
|
||||
case "/api/v1":
|
||||
list = &stable
|
||||
case "/apis/extensions/v1beta1":
|
||||
list = &beta
|
||||
case "/api":
|
||||
list = &metav1.APIVersions{
|
||||
Versions: []string{
|
||||
"v1",
|
||||
},
|
||||
}
|
||||
case "/apis":
|
||||
list = &metav1.APIGroupList{
|
||||
Groups: []metav1.APIGroup{
|
||||
{
|
||||
Versions: []metav1.GroupVersionForDiscovery{
|
||||
{GroupVersion: "extensions/v1beta1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
default:
|
||||
t.Logf("unexpected request: %s", req.URL.Path)
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
output, err := json.Marshal(list)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected encoding error: %v", err)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(output)
|
||||
}))
|
||||
defer server.Close()
|
||||
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
|
||||
for _, test := range tests {
|
||||
got, err := client.ServerResourcesForGroupVersion(test.request)
|
||||
if test.expectErr {
|
||||
if err == nil {
|
||||
t.Error("unexpected non-error")
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(got, test.resourcesList) {
|
||||
t.Errorf("expected:\n%v\ngot:\n%v\n", test.resourcesList, got)
|
||||
}
|
||||
}
|
||||
|
||||
serverResources, err := client.ServerResources()
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
serverGroupVersions := sets.NewString(groupVersions(serverResources)...)
|
||||
for _, api := range []string{"v1", "extensions/v1beta1"} {
|
||||
if !serverGroupVersions.Has(api) {
|
||||
t.Errorf("missing expected api %q in %v", api, serverResources)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServerPreferredResources(t *testing.T) {
|
||||
stable := metav1.APIResourceList{
|
||||
GroupVersion: "v1",
|
||||
APIResources: []metav1.APIResource{
|
||||
{Name: "pods", Namespaced: true, Kind: "Pod"},
|
||||
{Name: "services", Namespaced: true, Kind: "Service"},
|
||||
{Name: "namespaces", Namespaced: false, Kind: "Namespace"},
|
||||
},
|
||||
}
|
||||
tests := []struct {
|
||||
resourcesList []*metav1.APIResourceList
|
||||
response func(w http.ResponseWriter, req *http.Request)
|
||||
expectErr func(err error) bool
|
||||
}{
|
||||
{
|
||||
resourcesList: []*metav1.APIResourceList{&stable},
|
||||
expectErr: IsGroupDiscoveryFailedError,
|
||||
response: func(w http.ResponseWriter, req *http.Request) {
|
||||
var list interface{}
|
||||
switch req.URL.Path {
|
||||
case "/apis/extensions/v1beta1":
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
case "/api/v1":
|
||||
list = &stable
|
||||
case "/api":
|
||||
list = &metav1.APIVersions{
|
||||
Versions: []string{
|
||||
"v1",
|
||||
},
|
||||
}
|
||||
case "/apis":
|
||||
list = &metav1.APIGroupList{
|
||||
Groups: []metav1.APIGroup{
|
||||
{
|
||||
Versions: []metav1.GroupVersionForDiscovery{
|
||||
{GroupVersion: "extensions/v1beta1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
default:
|
||||
t.Logf("unexpected request: %s", req.URL.Path)
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
output, err := json.Marshal(list)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected encoding error: %v", err)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(output)
|
||||
},
|
||||
},
|
||||
{
|
||||
resourcesList: nil,
|
||||
expectErr: IsGroupDiscoveryFailedError,
|
||||
response: func(w http.ResponseWriter, req *http.Request) {
|
||||
var list interface{}
|
||||
switch req.URL.Path {
|
||||
case "/apis/extensions/v1beta1":
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
case "/api/v1":
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
case "/api":
|
||||
list = &metav1.APIVersions{
|
||||
Versions: []string{
|
||||
"v1",
|
||||
},
|
||||
}
|
||||
case "/apis":
|
||||
list = &metav1.APIGroupList{
|
||||
Groups: []metav1.APIGroup{
|
||||
{
|
||||
Versions: []metav1.GroupVersionForDiscovery{
|
||||
{GroupVersion: "extensions/v1beta1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
default:
|
||||
t.Logf("unexpected request: %s", req.URL.Path)
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
output, err := json.Marshal(list)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected encoding error: %v", err)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(output)
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
server := httptest.NewServer(http.HandlerFunc(test.response))
|
||||
defer server.Close()
|
||||
|
||||
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
|
||||
resources, err := client.ServerPreferredResources()
|
||||
if test.expectErr != nil {
|
||||
if err == nil {
|
||||
t.Error("unexpected non-error")
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
continue
|
||||
}
|
||||
got, err := GroupVersionResources(resources)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
continue
|
||||
}
|
||||
expected, _ := GroupVersionResources(test.resourcesList)
|
||||
if !reflect.DeepEqual(got, expected) {
|
||||
t.Errorf("expected:\n%v\ngot:\n%v\n", test.resourcesList, got)
|
||||
}
|
||||
server.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func TestServerPreferredResourcesRetries(t *testing.T) {
|
||||
stable := metav1.APIResourceList{
|
||||
GroupVersion: "v1",
|
||||
APIResources: []metav1.APIResource{
|
||||
{Name: "pods", Namespaced: true, Kind: "Pod"},
|
||||
},
|
||||
}
|
||||
beta := metav1.APIResourceList{
|
||||
GroupVersion: "extensions/v1",
|
||||
APIResources: []metav1.APIResource{
|
||||
{Name: "deployments", Namespaced: true, Kind: "Deployment"},
|
||||
},
|
||||
}
|
||||
|
||||
response := func(numErrors int) http.HandlerFunc {
|
||||
var i = 0
|
||||
return func(w http.ResponseWriter, req *http.Request) {
|
||||
var list interface{}
|
||||
switch req.URL.Path {
|
||||
case "/apis/extensions/v1beta1":
|
||||
if i < numErrors {
|
||||
i++
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
list = &beta
|
||||
case "/api/v1":
|
||||
list = &stable
|
||||
case "/api":
|
||||
list = &metav1.APIVersions{
|
||||
Versions: []string{
|
||||
"v1",
|
||||
},
|
||||
}
|
||||
case "/apis":
|
||||
list = &metav1.APIGroupList{
|
||||
Groups: []metav1.APIGroup{
|
||||
{
|
||||
Name: "extensions",
|
||||
Versions: []metav1.GroupVersionForDiscovery{
|
||||
{GroupVersion: "extensions/v1beta1"},
|
||||
},
|
||||
PreferredVersion: metav1.GroupVersionForDiscovery{
|
||||
GroupVersion: "extensions/v1beta1",
|
||||
Version: "v1beta1",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
default:
|
||||
t.Logf("unexpected request: %s", req.URL.Path)
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
output, err := json.Marshal(list)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected encoding error: %v", err)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(output)
|
||||
}
|
||||
}
|
||||
tests := []struct {
|
||||
responseErrors int
|
||||
expectResources int
|
||||
expectedError func(err error) bool
|
||||
}{
|
||||
{
|
||||
responseErrors: 1,
|
||||
expectResources: 2,
|
||||
expectedError: func(err error) bool {
|
||||
return err == nil
|
||||
},
|
||||
},
|
||||
{
|
||||
responseErrors: 2,
|
||||
expectResources: 1,
|
||||
expectedError: IsGroupDiscoveryFailedError,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range tests {
|
||||
server := httptest.NewServer(http.HandlerFunc(response(tc.responseErrors)))
|
||||
defer server.Close()
|
||||
|
||||
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
|
||||
resources, err := client.ServerPreferredResources()
|
||||
if !tc.expectedError(err) {
|
||||
t.Errorf("case %d: unexpected error: %v", i, err)
|
||||
}
|
||||
got, err := GroupVersionResources(resources)
|
||||
if err != nil {
|
||||
t.Errorf("case %d: unexpected error: %v", i, err)
|
||||
}
|
||||
if len(got) != tc.expectResources {
|
||||
t.Errorf("case %d: expect %d resources, got %#v", i, tc.expectResources, got)
|
||||
}
|
||||
server.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func TestServerPreferredNamespacedResources(t *testing.T) {
|
||||
stable := metav1.APIResourceList{
|
||||
GroupVersion: "v1",
|
||||
APIResources: []metav1.APIResource{
|
||||
{Name: "pods", Namespaced: true, Kind: "Pod"},
|
||||
{Name: "services", Namespaced: true, Kind: "Service"},
|
||||
{Name: "namespaces", Namespaced: false, Kind: "Namespace"},
|
||||
},
|
||||
}
|
||||
batchv1 := metav1.APIResourceList{
|
||||
GroupVersion: "batch/v1",
|
||||
APIResources: []metav1.APIResource{
|
||||
{Name: "jobs", Namespaced: true, Kind: "Job"},
|
||||
},
|
||||
}
|
||||
batchv2alpha1 := metav1.APIResourceList{
|
||||
GroupVersion: "batch/v2alpha1",
|
||||
APIResources: []metav1.APIResource{
|
||||
{Name: "jobs", Namespaced: true, Kind: "Job"},
|
||||
{Name: "cronjobs", Namespaced: true, Kind: "CronJob"},
|
||||
},
|
||||
}
|
||||
batchv3alpha1 := metav1.APIResourceList{
|
||||
GroupVersion: "batch/v3alpha1",
|
||||
APIResources: []metav1.APIResource{
|
||||
{Name: "jobs", Namespaced: true, Kind: "Job"},
|
||||
{Name: "cronjobs", Namespaced: true, Kind: "CronJob"},
|
||||
},
|
||||
}
|
||||
tests := []struct {
|
||||
response func(w http.ResponseWriter, req *http.Request)
|
||||
expected map[schema.GroupVersionResource]struct{}
|
||||
}{
|
||||
{
|
||||
response: func(w http.ResponseWriter, req *http.Request) {
|
||||
var list interface{}
|
||||
switch req.URL.Path {
|
||||
case "/api/v1":
|
||||
list = &stable
|
||||
case "/api":
|
||||
list = &metav1.APIVersions{
|
||||
Versions: []string{
|
||||
"v1",
|
||||
},
|
||||
}
|
||||
default:
|
||||
t.Logf("unexpected request: %s", req.URL.Path)
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
output, err := json.Marshal(list)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected encoding error: %v", err)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(output)
|
||||
},
|
||||
expected: map[schema.GroupVersionResource]struct{}{
|
||||
schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"}: {},
|
||||
schema.GroupVersionResource{Group: "", Version: "v1", Resource: "services"}: {},
|
||||
},
|
||||
},
|
||||
{
|
||||
response: func(w http.ResponseWriter, req *http.Request) {
|
||||
var list interface{}
|
||||
switch req.URL.Path {
|
||||
case "/apis":
|
||||
list = &metav1.APIGroupList{
|
||||
Groups: []metav1.APIGroup{
|
||||
{
|
||||
Name: "batch",
|
||||
Versions: []metav1.GroupVersionForDiscovery{
|
||||
{GroupVersion: "batch/v1", Version: "v1"},
|
||||
{GroupVersion: "batch/v2alpha1", Version: "v2alpha1"},
|
||||
{GroupVersion: "batch/v3alpha1", Version: "v3alpha1"},
|
||||
},
|
||||
PreferredVersion: metav1.GroupVersionForDiscovery{GroupVersion: "batch/v1", Version: "v1"},
|
||||
},
|
||||
},
|
||||
}
|
||||
case "/apis/batch/v1":
|
||||
list = &batchv1
|
||||
case "/apis/batch/v2alpha1":
|
||||
list = &batchv2alpha1
|
||||
case "/apis/batch/v3alpha1":
|
||||
list = &batchv3alpha1
|
||||
default:
|
||||
t.Logf("unexpected request: %s", req.URL.Path)
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
output, err := json.Marshal(list)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected encoding error: %v", err)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(output)
|
||||
},
|
||||
expected: map[schema.GroupVersionResource]struct{}{
|
||||
schema.GroupVersionResource{Group: "batch", Version: "v1", Resource: "jobs"}: {},
|
||||
schema.GroupVersionResource{Group: "batch", Version: "v2alpha1", Resource: "cronjobs"}: {},
|
||||
},
|
||||
},
|
||||
{
|
||||
response: func(w http.ResponseWriter, req *http.Request) {
|
||||
var list interface{}
|
||||
switch req.URL.Path {
|
||||
case "/apis":
|
||||
list = &metav1.APIGroupList{
|
||||
Groups: []metav1.APIGroup{
|
||||
{
|
||||
Name: "batch",
|
||||
Versions: []metav1.GroupVersionForDiscovery{
|
||||
{GroupVersion: "batch/v1", Version: "v1"},
|
||||
{GroupVersion: "batch/v2alpha1", Version: "v2alpha1"},
|
||||
{GroupVersion: "batch/v3alpha1", Version: "v3alpha1"},
|
||||
},
|
||||
PreferredVersion: metav1.GroupVersionForDiscovery{GroupVersion: "batch/v2alpha", Version: "v2alpha1"},
|
||||
},
|
||||
},
|
||||
}
|
||||
case "/apis/batch/v1":
|
||||
list = &batchv1
|
||||
case "/apis/batch/v2alpha1":
|
||||
list = &batchv2alpha1
|
||||
case "/apis/batch/v3alpha1":
|
||||
list = &batchv3alpha1
|
||||
default:
|
||||
t.Logf("unexpected request: %s", req.URL.Path)
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
output, err := json.Marshal(list)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected encoding error: %v", err)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(output)
|
||||
},
|
||||
expected: map[schema.GroupVersionResource]struct{}{
|
||||
schema.GroupVersionResource{Group: "batch", Version: "v2alpha1", Resource: "jobs"}: {},
|
||||
schema.GroupVersionResource{Group: "batch", Version: "v2alpha1", Resource: "cronjobs"}: {},
|
||||
},
|
||||
},
|
||||
}
|
||||
for i, test := range tests {
|
||||
server := httptest.NewServer(http.HandlerFunc(test.response))
|
||||
defer server.Close()
|
||||
|
||||
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
|
||||
resources, err := client.ServerPreferredNamespacedResources()
|
||||
if err != nil {
|
||||
t.Errorf("[%d] unexpected error: %v", i, err)
|
||||
continue
|
||||
}
|
||||
got, err := GroupVersionResources(resources)
|
||||
if err != nil {
|
||||
t.Errorf("[%d] unexpected error: %v", i, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(got, test.expected) {
|
||||
t.Errorf("[%d] expected:\n%v\ngot:\n%v\n", i, test.expected, got)
|
||||
}
|
||||
server.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func groupVersions(resources []*metav1.APIResourceList) []string {
|
||||
result := []string{}
|
||||
for _, resourceList := range resources {
|
||||
result = append(result, resourceList.GroupVersion)
|
||||
}
|
||||
return result
|
||||
}
|
@@ -1,37 +0,0 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["discovery.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/client/testing/core:go_default_library",
|
||||
"//pkg/version:go_default_library",
|
||||
"//vendor:github.com/emicklei/go-restful/swagger",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
|
||||
"//vendor:k8s.io/apimachinery/pkg/version",
|
||||
"//vendor:k8s.io/client-go/rest",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/emicklei/go-restful/swagger"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/version"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/client/testing/core"
|
||||
kubeversion "k8s.io/kubernetes/pkg/version"
|
||||
)
|
||||
|
||||
type FakeDiscovery struct {
|
||||
*core.Fake
|
||||
}
|
||||
|
||||
func (c *FakeDiscovery) ServerResourcesForGroupVersion(groupVersion string) (*metav1.APIResourceList, error) {
|
||||
action := core.ActionImpl{
|
||||
Verb: "get",
|
||||
Resource: schema.GroupVersionResource{Resource: "resource"},
|
||||
}
|
||||
c.Invokes(action, nil)
|
||||
for _, resourceList := range c.Resources {
|
||||
if resourceList.GroupVersion == groupVersion {
|
||||
return resourceList, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("GroupVersion %q not found", groupVersion)
|
||||
}
|
||||
|
||||
func (c *FakeDiscovery) ServerResources() ([]*metav1.APIResourceList, error) {
|
||||
action := core.ActionImpl{
|
||||
Verb: "get",
|
||||
Resource: schema.GroupVersionResource{Resource: "resource"},
|
||||
}
|
||||
c.Invokes(action, nil)
|
||||
return c.Resources, nil
|
||||
}
|
||||
|
||||
func (c *FakeDiscovery) ServerPreferredResources() ([]*metav1.APIResourceList, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *FakeDiscovery) ServerPreferredNamespacedResources() ([]*metav1.APIResourceList, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *FakeDiscovery) ServerGroups() (*metav1.APIGroupList, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *FakeDiscovery) ServerVersion() (*version.Info, error) {
|
||||
action := core.ActionImpl{}
|
||||
action.Verb = "get"
|
||||
action.Resource = schema.GroupVersionResource{Resource: "version"}
|
||||
|
||||
c.Invokes(action, nil)
|
||||
versionInfo := kubeversion.Get()
|
||||
return &versionInfo, nil
|
||||
}
|
||||
|
||||
func (c *FakeDiscovery) SwaggerSchema(version schema.GroupVersion) (*swagger.ApiDeclaration, error) {
|
||||
action := core.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) RESTClient() restclient.Interface {
|
||||
return nil
|
||||
}
|
@@ -1,162 +0,0 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package discovery
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/kubernetes/pkg/version"
|
||||
// Import solely to initialize client auth plugins.
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth"
|
||||
)
|
||||
|
||||
// MatchesServerVersion queries the server to compares the build version
|
||||
// (git hash) of the client with the server's build version. It returns an error
|
||||
// if it failed to contact the server or if the versions are not an exact match.
|
||||
func MatchesServerVersion(client DiscoveryInterface) error {
|
||||
cVer := version.Get()
|
||||
sVer, err := client.ServerVersion()
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't read version from server: %v\n", err)
|
||||
}
|
||||
// GitVersion includes GitCommit and GitTreeState, but best to be safe?
|
||||
if cVer.GitVersion != sVer.GitVersion || cVer.GitCommit != sVer.GitCommit || cVer.GitTreeState != sVer.GitTreeState {
|
||||
return fmt.Errorf("server version (%#v) differs from client version (%#v)!\n", sVer, cVer)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NegotiateVersion queries the server's supported api versions to find
|
||||
// a version that both client and server support.
|
||||
// - If no version is provided, try registered client versions in order of
|
||||
// preference.
|
||||
// - If version is provided and the server does not support it,
|
||||
// return an error.
|
||||
func NegotiateVersion(client DiscoveryInterface, requiredGV *schema.GroupVersion, clientRegisteredGVs []schema.GroupVersion) (*schema.GroupVersion, error) {
|
||||
clientVersions := sets.String{}
|
||||
for _, gv := range clientRegisteredGVs {
|
||||
clientVersions.Insert(gv.String())
|
||||
}
|
||||
groups, err := client.ServerGroups()
|
||||
if err != nil {
|
||||
// This is almost always a connection error, and higher level code should treat this as a generic error,
|
||||
// not a negotiation specific error.
|
||||
return nil, err
|
||||
}
|
||||
versions := metav1.ExtractGroupVersions(groups)
|
||||
serverVersions := sets.String{}
|
||||
for _, v := range versions {
|
||||
serverVersions.Insert(v)
|
||||
}
|
||||
|
||||
// If version explicitly requested verify that both client and server support it.
|
||||
// If server does not support warn, but try to negotiate a lower version.
|
||||
if requiredGV != nil {
|
||||
if !clientVersions.Has(requiredGV.String()) {
|
||||
return nil, fmt.Errorf("client does not support API version %q; client supported API versions: %v", requiredGV, clientVersions)
|
||||
|
||||
}
|
||||
// If the server supports no versions, then we should just use the preferredGV
|
||||
// This can happen because discovery fails due to 403 Forbidden errors
|
||||
if len(serverVersions) == 0 {
|
||||
return requiredGV, nil
|
||||
}
|
||||
if serverVersions.Has(requiredGV.String()) {
|
||||
return requiredGV, nil
|
||||
}
|
||||
// If we are using an explicit config version the server does not support, fail.
|
||||
return nil, fmt.Errorf("server does not support API version %q", requiredGV)
|
||||
}
|
||||
|
||||
for _, clientGV := range clientRegisteredGVs {
|
||||
if serverVersions.Has(clientGV.String()) {
|
||||
// Version was not explicitly requested in command config (--api-version).
|
||||
// Ok to fall back to a supported version with a warning.
|
||||
// TODO: caesarxuchao: enable the warning message when we have
|
||||
// proper fix. Please refer to issue #14895.
|
||||
// if len(version) != 0 {
|
||||
// glog.Warningf("Server does not support API version '%s'. Falling back to '%s'.", version, clientVersion)
|
||||
// }
|
||||
t := clientGV
|
||||
return &t, nil
|
||||
}
|
||||
}
|
||||
|
||||
// if we have no server versions and we have no required version, choose the first clientRegisteredVersion
|
||||
if len(serverVersions) == 0 && len(clientRegisteredGVs) > 0 {
|
||||
return &clientRegisteredGVs[0], nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("failed to negotiate an api version; server supports: %v, client supports: %v",
|
||||
serverVersions, clientVersions)
|
||||
}
|
||||
|
||||
// GroupVersionResources converts APIResourceLists to the GroupVersionResources.
|
||||
func GroupVersionResources(rls []*metav1.APIResourceList) (map[schema.GroupVersionResource]struct{}, error) {
|
||||
gvrs := map[schema.GroupVersionResource]struct{}{}
|
||||
for _, rl := range rls {
|
||||
gv, err := schema.ParseGroupVersion(rl.GroupVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := range rl.APIResources {
|
||||
gvrs[schema.GroupVersionResource{Group: gv.Group, Version: gv.Version, Resource: rl.APIResources[i].Name}] = struct{}{}
|
||||
}
|
||||
}
|
||||
return gvrs, nil
|
||||
}
|
||||
|
||||
// FilteredBy filters by the given predicate. Empty APIResourceLists are dropped.
|
||||
func FilteredBy(pred ResourcePredicate, rls []*metav1.APIResourceList) []*metav1.APIResourceList {
|
||||
result := []*metav1.APIResourceList{}
|
||||
for _, rl := range rls {
|
||||
filtered := *rl
|
||||
filtered.APIResources = nil
|
||||
for i := range rl.APIResources {
|
||||
if pred.Match(rl.GroupVersion, &rl.APIResources[i]) {
|
||||
filtered.APIResources = append(filtered.APIResources, rl.APIResources[i])
|
||||
}
|
||||
}
|
||||
if filtered.APIResources != nil {
|
||||
result = append(result, &filtered)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
type ResourcePredicate interface {
|
||||
Match(groupVersion string, r *metav1.APIResource) bool
|
||||
}
|
||||
|
||||
type ResourcePredicateFunc func(groupVersion string, r *metav1.APIResource) bool
|
||||
|
||||
func (fn ResourcePredicateFunc) Match(groupVersion string, r *metav1.APIResource) bool {
|
||||
return fn(groupVersion, r)
|
||||
}
|
||||
|
||||
// SupportsAllVerbs is a predicate matching a resource iff all given verbs are supported.
|
||||
type SupportsAllVerbs struct {
|
||||
Verbs []string
|
||||
}
|
||||
|
||||
func (p SupportsAllVerbs) Match(groupVersion string, r *metav1.APIResource) bool {
|
||||
return sets.NewString([]string(r.Verbs)...).HasAll(p.Verbs...)
|
||||
}
|
@@ -1,230 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package discovery_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
uapi "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
)
|
||||
|
||||
func objBody(object interface{}) io.ReadCloser {
|
||||
output, err := json.MarshalIndent(object, "", "")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return ioutil.NopCloser(bytes.NewReader([]byte(output)))
|
||||
}
|
||||
|
||||
func TestNegotiateVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
requiredVersion *schema.GroupVersion
|
||||
expectedVersion *schema.GroupVersion
|
||||
serverVersions []string
|
||||
clientVersions []schema.GroupVersion
|
||||
expectErr func(err error) bool
|
||||
sendErr error
|
||||
statusCode int
|
||||
}{
|
||||
{
|
||||
name: "server supports client default",
|
||||
serverVersions: []string{"version1", api.Registry.GroupOrDie(api.GroupName).GroupVersion.String()},
|
||||
clientVersions: []schema.GroupVersion{{Version: "version1"}, api.Registry.GroupOrDie(api.GroupName).GroupVersion},
|
||||
expectedVersion: &schema.GroupVersion{Version: "version1"},
|
||||
statusCode: http.StatusOK,
|
||||
},
|
||||
{
|
||||
name: "server falls back to client supported",
|
||||
serverVersions: []string{"version1"},
|
||||
clientVersions: []schema.GroupVersion{{Version: "version1"}, api.Registry.GroupOrDie(api.GroupName).GroupVersion},
|
||||
expectedVersion: &schema.GroupVersion{Version: "version1"},
|
||||
statusCode: http.StatusOK,
|
||||
},
|
||||
{
|
||||
name: "explicit version supported",
|
||||
requiredVersion: &schema.GroupVersion{Version: "v1"},
|
||||
serverVersions: []string{"/version1", api.Registry.GroupOrDie(api.GroupName).GroupVersion.String()},
|
||||
clientVersions: []schema.GroupVersion{{Version: "version1"}, api.Registry.GroupOrDie(api.GroupName).GroupVersion},
|
||||
expectedVersion: &schema.GroupVersion{Version: "v1"},
|
||||
statusCode: http.StatusOK,
|
||||
},
|
||||
{
|
||||
name: "explicit version not supported on server",
|
||||
requiredVersion: &schema.GroupVersion{Version: "v1"},
|
||||
serverVersions: []string{"version1"},
|
||||
clientVersions: []schema.GroupVersion{{Version: "version1"}, api.Registry.GroupOrDie(api.GroupName).GroupVersion},
|
||||
expectErr: func(err error) bool { return strings.Contains(err.Error(), `server does not support API version "v1"`) },
|
||||
statusCode: http.StatusOK,
|
||||
},
|
||||
{
|
||||
name: "explicit version not supported on client",
|
||||
requiredVersion: &schema.GroupVersion{Version: "v1"},
|
||||
serverVersions: []string{"v1"},
|
||||
clientVersions: []schema.GroupVersion{{Version: "version1"}},
|
||||
expectErr: func(err error) bool { return strings.Contains(err.Error(), `client does not support API version "v1"`) },
|
||||
statusCode: http.StatusOK,
|
||||
},
|
||||
{
|
||||
name: "connection refused error",
|
||||
serverVersions: []string{"version1"},
|
||||
clientVersions: []schema.GroupVersion{{Version: "version1"}, api.Registry.GroupOrDie(api.GroupName).GroupVersion},
|
||||
sendErr: errors.New("connection refused"),
|
||||
expectErr: func(err error) bool { return strings.Contains(err.Error(), "connection refused") },
|
||||
statusCode: http.StatusOK,
|
||||
},
|
||||
{
|
||||
name: "discovery fails due to 403 Forbidden errors and thus serverVersions is empty, use default GroupVersion",
|
||||
clientVersions: []schema.GroupVersion{{Version: "version1"}, api.Registry.GroupOrDie(api.GroupName).GroupVersion},
|
||||
expectedVersion: &schema.GroupVersion{Version: "version1"},
|
||||
statusCode: http.StatusForbidden,
|
||||
},
|
||||
{
|
||||
name: "discovery fails due to 404 Not Found errors and thus serverVersions is empty, use requested GroupVersion",
|
||||
requiredVersion: &schema.GroupVersion{Version: "version1"},
|
||||
clientVersions: []schema.GroupVersion{{Version: "version1"}, api.Registry.GroupOrDie(api.GroupName).GroupVersion},
|
||||
expectedVersion: &schema.GroupVersion{Version: "version1"},
|
||||
statusCode: http.StatusNotFound,
|
||||
},
|
||||
{
|
||||
name: "discovery fails due to 403 Forbidden errors and thus serverVersions is empty, no fallback GroupVersion",
|
||||
expectErr: func(err error) bool { return strings.Contains(err.Error(), "failed to negotiate an api version;") },
|
||||
statusCode: http.StatusForbidden,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
fakeClient := &fake.RESTClient{
|
||||
APIRegistry: api.Registry,
|
||||
NegotiatedSerializer: testapi.Default.NegotiatedSerializer(),
|
||||
Resp: &http.Response{
|
||||
StatusCode: test.statusCode,
|
||||
Body: objBody(&uapi.APIVersions{Versions: test.serverVersions}),
|
||||
},
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
if test.sendErr != nil {
|
||||
return nil, test.sendErr
|
||||
}
|
||||
header := http.Header{}
|
||||
header.Set("Content-Type", runtime.ContentTypeJSON)
|
||||
return &http.Response{StatusCode: test.statusCode, Header: header, Body: objBody(&uapi.APIVersions{Versions: test.serverVersions})}, nil
|
||||
}),
|
||||
}
|
||||
c := discovery.NewDiscoveryClientForConfigOrDie(&restclient.Config{})
|
||||
c.RESTClient().(*restclient.RESTClient).Client = fakeClient.Client
|
||||
response, err := discovery.NegotiateVersion(c, test.requiredVersion, test.clientVersions)
|
||||
if err == nil && test.expectErr != nil {
|
||||
t.Errorf("expected error, got nil for [%s].", test.name)
|
||||
}
|
||||
if err != nil {
|
||||
if test.expectErr == nil || !test.expectErr(err) {
|
||||
t.Errorf("unexpected error for [%s]: %v.", test.name, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if *response != *test.expectedVersion {
|
||||
t.Errorf("%s: expected version %s, got %s.", test.name, test.expectedVersion, response)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilteredBy(t *testing.T) {
|
||||
all := discovery.ResourcePredicateFunc(func(gv string, r *metav1.APIResource) bool {
|
||||
return true
|
||||
})
|
||||
none := discovery.ResourcePredicateFunc(func(gv string, r *metav1.APIResource) bool {
|
||||
return false
|
||||
})
|
||||
onlyV2 := discovery.ResourcePredicateFunc(func(gv string, r *metav1.APIResource) bool {
|
||||
return strings.HasSuffix(gv, "/v2") || gv == "v2"
|
||||
})
|
||||
onlyBar := discovery.ResourcePredicateFunc(func(gv string, r *metav1.APIResource) bool {
|
||||
return r.Kind == "Bar"
|
||||
})
|
||||
|
||||
foo := []*metav1.APIResourceList{
|
||||
{
|
||||
GroupVersion: "foo/v1",
|
||||
APIResources: []metav1.APIResource{
|
||||
{Name: "bar", Kind: "Bar"},
|
||||
{Name: "test", Kind: "Test"},
|
||||
},
|
||||
},
|
||||
{
|
||||
GroupVersion: "foo/v2",
|
||||
APIResources: []metav1.APIResource{
|
||||
{Name: "bar", Kind: "Bar"},
|
||||
{Name: "test", Kind: "Test"},
|
||||
},
|
||||
},
|
||||
{
|
||||
GroupVersion: "foo/v3",
|
||||
APIResources: []metav1.APIResource{},
|
||||
},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
input []*metav1.APIResourceList
|
||||
pred discovery.ResourcePredicate
|
||||
expectedResources []string
|
||||
}{
|
||||
{nil, all, []string{}},
|
||||
{[]*metav1.APIResourceList{
|
||||
{GroupVersion: "foo/v1"},
|
||||
}, all, []string{}},
|
||||
{foo, all, []string{"foo/v1.bar", "foo/v1.test", "foo/v2.bar", "foo/v2.test"}},
|
||||
{foo, onlyV2, []string{"foo/v2.bar", "foo/v2.test"}},
|
||||
{foo, onlyBar, []string{"foo/v1.bar", "foo/v2.bar"}},
|
||||
{foo, none, []string{}},
|
||||
}
|
||||
for i, test := range tests {
|
||||
filtered := discovery.FilteredBy(test.pred, test.input)
|
||||
|
||||
if expected, got := sets.NewString(test.expectedResources...), sets.NewString(stringify(filtered)...); !expected.Equal(got) {
|
||||
t.Errorf("[%d] unexpected group versions: expected=%v, got=%v", i, test.expectedResources, stringify(filtered))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func stringify(rls []*metav1.APIResourceList) []string {
|
||||
result := []string{}
|
||||
for _, rl := range rls {
|
||||
for _, r := range rl.APIResources {
|
||||
result = append(result, rl.GroupVersion+"."+r.Name)
|
||||
}
|
||||
if len(rl.APIResources) == 0 {
|
||||
result = append(result, rl.GroupVersion)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
@@ -1,319 +0,0 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package discovery
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
// APIGroupResources is an API group with a mapping of versions to
|
||||
// resources.
|
||||
type APIGroupResources struct {
|
||||
Group metav1.APIGroup
|
||||
// A mapping of version string to a slice of APIResources for
|
||||
// that version.
|
||||
VersionedResources map[string][]metav1.APIResource
|
||||
}
|
||||
|
||||
// NewRESTMapper returns a PriorityRESTMapper based on the discovered
|
||||
// groups and resources passed in.
|
||||
func NewRESTMapper(groupResources []*APIGroupResources, versionInterfaces meta.VersionInterfacesFunc) meta.RESTMapper {
|
||||
unionMapper := meta.MultiRESTMapper{}
|
||||
|
||||
var groupPriority []string
|
||||
var resourcePriority []schema.GroupVersionResource
|
||||
var kindPriority []schema.GroupVersionKind
|
||||
|
||||
for _, group := range groupResources {
|
||||
groupPriority = append(groupPriority, group.Group.Name)
|
||||
|
||||
if len(group.Group.PreferredVersion.Version) != 0 {
|
||||
preferred := group.Group.PreferredVersion.Version
|
||||
if _, ok := group.VersionedResources[preferred]; ok {
|
||||
resourcePriority = append(resourcePriority, schema.GroupVersionResource{
|
||||
Group: group.Group.Name,
|
||||
Version: group.Group.PreferredVersion.Version,
|
||||
Resource: meta.AnyResource,
|
||||
})
|
||||
|
||||
kindPriority = append(kindPriority, schema.GroupVersionKind{
|
||||
Group: group.Group.Name,
|
||||
Version: group.Group.PreferredVersion.Version,
|
||||
Kind: meta.AnyKind,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
for _, discoveryVersion := range group.Group.Versions {
|
||||
resources, ok := group.VersionedResources[discoveryVersion.Version]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
gv := schema.GroupVersion{Group: group.Group.Name, Version: discoveryVersion.Version}
|
||||
versionMapper := meta.NewDefaultRESTMapper([]schema.GroupVersion{gv}, versionInterfaces)
|
||||
|
||||
for _, resource := range resources {
|
||||
scope := meta.RESTScopeNamespace
|
||||
if !resource.Namespaced {
|
||||
scope = meta.RESTScopeRoot
|
||||
}
|
||||
versionMapper.Add(gv.WithKind(resource.Kind), scope)
|
||||
// TODO only do this if it supports listing
|
||||
versionMapper.Add(gv.WithKind(resource.Kind+"List"), scope)
|
||||
}
|
||||
// TODO why is this type not in discovery (at least for "v1")
|
||||
versionMapper.Add(gv.WithKind("List"), meta.RESTScopeRoot)
|
||||
unionMapper = append(unionMapper, versionMapper)
|
||||
}
|
||||
}
|
||||
|
||||
for _, group := range groupPriority {
|
||||
resourcePriority = append(resourcePriority, schema.GroupVersionResource{
|
||||
Group: group,
|
||||
Version: meta.AnyVersion,
|
||||
Resource: meta.AnyResource,
|
||||
})
|
||||
kindPriority = append(kindPriority, schema.GroupVersionKind{
|
||||
Group: group,
|
||||
Version: meta.AnyVersion,
|
||||
Kind: meta.AnyKind,
|
||||
})
|
||||
}
|
||||
|
||||
return meta.PriorityRESTMapper{
|
||||
Delegate: unionMapper,
|
||||
ResourcePriority: resourcePriority,
|
||||
KindPriority: kindPriority,
|
||||
}
|
||||
}
|
||||
|
||||
// GetAPIGroupResources uses the provided discovery client to gather
|
||||
// discovery information and populate a slice of APIGroupResources.
|
||||
func GetAPIGroupResources(cl DiscoveryInterface) ([]*APIGroupResources, error) {
|
||||
apiGroups, err := cl.ServerGroups()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var result []*APIGroupResources
|
||||
for _, group := range apiGroups.Groups {
|
||||
groupResources := &APIGroupResources{
|
||||
Group: group,
|
||||
VersionedResources: make(map[string][]metav1.APIResource),
|
||||
}
|
||||
for _, version := range group.Versions {
|
||||
resources, err := cl.ServerResourcesForGroupVersion(version.GroupVersion)
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
continue // ignore as this can race with deletion of 3rd party APIs
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
groupResources.VersionedResources[version.Version] = resources.APIResources
|
||||
}
|
||||
result = append(result, groupResources)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// DeferredDiscoveryRESTMapper is a RESTMapper that will defer
|
||||
// initialization of the RESTMapper until the first mapping is
|
||||
// requested.
|
||||
type DeferredDiscoveryRESTMapper struct {
|
||||
initMu sync.Mutex
|
||||
delegate meta.RESTMapper
|
||||
cl CachedDiscoveryInterface
|
||||
versionInterface meta.VersionInterfacesFunc
|
||||
}
|
||||
|
||||
// NewDeferredDiscoveryRESTMapper returns a
|
||||
// DeferredDiscoveryRESTMapper that will lazily query the provided
|
||||
// client for discovery information to do REST mappings.
|
||||
func NewDeferredDiscoveryRESTMapper(cl CachedDiscoveryInterface, versionInterface meta.VersionInterfacesFunc) *DeferredDiscoveryRESTMapper {
|
||||
return &DeferredDiscoveryRESTMapper{
|
||||
cl: cl,
|
||||
versionInterface: versionInterface,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DeferredDiscoveryRESTMapper) getDelegate() (meta.RESTMapper, error) {
|
||||
d.initMu.Lock()
|
||||
defer d.initMu.Unlock()
|
||||
|
||||
if d.delegate != nil {
|
||||
return d.delegate, nil
|
||||
}
|
||||
|
||||
groupResources, err := GetAPIGroupResources(d.cl)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
d.delegate = NewRESTMapper(groupResources, d.versionInterface)
|
||||
return d.delegate, err
|
||||
}
|
||||
|
||||
// Reset resets the internally cached Discovery information and will
|
||||
// cause the next mapping request to re-discover.
|
||||
func (d *DeferredDiscoveryRESTMapper) Reset() {
|
||||
glog.V(5).Info("Invalidating discovery information")
|
||||
|
||||
d.initMu.Lock()
|
||||
defer d.initMu.Unlock()
|
||||
|
||||
d.cl.Invalidate()
|
||||
d.delegate = nil
|
||||
}
|
||||
|
||||
// KindFor takes a partial resource and returns back the single match.
|
||||
// It returns an error if there are multiple matches.
|
||||
func (d *DeferredDiscoveryRESTMapper) KindFor(resource schema.GroupVersionResource) (gvk schema.GroupVersionKind, err error) {
|
||||
del, err := d.getDelegate()
|
||||
if err != nil {
|
||||
return schema.GroupVersionKind{}, err
|
||||
}
|
||||
gvk, err = del.KindFor(resource)
|
||||
if err != nil && !d.cl.Fresh() {
|
||||
d.Reset()
|
||||
gvk, err = d.KindFor(resource)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// KindsFor takes a partial resource and returns back the list of
|
||||
// potential kinds in priority order.
|
||||
func (d *DeferredDiscoveryRESTMapper) KindsFor(resource schema.GroupVersionResource) (gvks []schema.GroupVersionKind, err error) {
|
||||
del, err := d.getDelegate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gvks, err = del.KindsFor(resource)
|
||||
if len(gvks) == 0 && !d.cl.Fresh() {
|
||||
d.Reset()
|
||||
gvks, err = d.KindsFor(resource)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ResourceFor takes a partial resource and returns back the single
|
||||
// match. It returns an error if there are multiple matches.
|
||||
func (d *DeferredDiscoveryRESTMapper) ResourceFor(input schema.GroupVersionResource) (gvr schema.GroupVersionResource, err error) {
|
||||
del, err := d.getDelegate()
|
||||
if err != nil {
|
||||
return schema.GroupVersionResource{}, err
|
||||
}
|
||||
gvr, err = del.ResourceFor(input)
|
||||
if err != nil && !d.cl.Fresh() {
|
||||
d.Reset()
|
||||
gvr, err = d.ResourceFor(input)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ResourcesFor takes a partial resource and returns back the list of
|
||||
// potential resource in priority order.
|
||||
func (d *DeferredDiscoveryRESTMapper) ResourcesFor(input schema.GroupVersionResource) (gvrs []schema.GroupVersionResource, err error) {
|
||||
del, err := d.getDelegate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gvrs, err = del.ResourcesFor(input)
|
||||
if len(gvrs) == 0 && !d.cl.Fresh() {
|
||||
d.Reset()
|
||||
gvrs, err = d.ResourcesFor(input)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// RESTMapping identifies a preferred resource mapping for the
|
||||
// provided group kind.
|
||||
func (d *DeferredDiscoveryRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (m *meta.RESTMapping, err error) {
|
||||
del, err := d.getDelegate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m, err = del.RESTMapping(gk, versions...)
|
||||
if err != nil && !d.cl.Fresh() {
|
||||
d.Reset()
|
||||
m, err = d.RESTMapping(gk, versions...)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// RESTMappings returns the RESTMappings for the provided group kind
|
||||
// in a rough internal preferred order. If no kind is found, it will
|
||||
// return a NoResourceMatchError.
|
||||
func (d *DeferredDiscoveryRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string) (ms []*meta.RESTMapping, err error) {
|
||||
del, err := d.getDelegate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ms, err = del.RESTMappings(gk, versions...)
|
||||
if len(ms) == 0 && !d.cl.Fresh() {
|
||||
d.Reset()
|
||||
ms, err = d.RESTMappings(gk, versions...)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// AliasesForResource returns whether a resource has an alias or not.
|
||||
func (d *DeferredDiscoveryRESTMapper) AliasesForResource(resource string) (as []string, ok bool) {
|
||||
del, err := d.getDelegate()
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
as, ok = del.AliasesForResource(resource)
|
||||
if len(as) == 0 && !d.cl.Fresh() {
|
||||
d.Reset()
|
||||
as, ok = d.AliasesForResource(resource)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ResourceSingularizer converts a resource name from plural to
|
||||
// singular (e.g., from pods to pod).
|
||||
func (d *DeferredDiscoveryRESTMapper) ResourceSingularizer(resource string) (singular string, err error) {
|
||||
del, err := d.getDelegate()
|
||||
if err != nil {
|
||||
return resource, err
|
||||
}
|
||||
singular, err = del.ResourceSingularizer(resource)
|
||||
if err != nil && !d.cl.Fresh() {
|
||||
d.Reset()
|
||||
singular, err = d.ResourceSingularizer(resource)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (d *DeferredDiscoveryRESTMapper) String() string {
|
||||
del, err := d.getDelegate()
|
||||
if err != nil {
|
||||
return fmt.Sprintf("DeferredDiscoveryRESTMapper{%v}", err)
|
||||
}
|
||||
return fmt.Sprintf("DeferredDiscoveryRESTMapper{\n\t%v\n}", del)
|
||||
}
|
||||
|
||||
// Make sure it satisfies the interface
|
||||
var _ meta.RESTMapper = &DeferredDiscoveryRESTMapper{}
|
@@ -1,330 +0,0 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package discovery_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/version"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
. "k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
|
||||
"github.com/emicklei/go-restful/swagger"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestRESTMapper(t *testing.T) {
|
||||
resources := []*APIGroupResources{
|
||||
{
|
||||
Group: metav1.APIGroup{
|
||||
Versions: []metav1.GroupVersionForDiscovery{
|
||||
{Version: "v1"},
|
||||
{Version: "v2"},
|
||||
},
|
||||
PreferredVersion: metav1.GroupVersionForDiscovery{Version: "v1"},
|
||||
},
|
||||
VersionedResources: map[string][]metav1.APIResource{
|
||||
"v1": {
|
||||
{Name: "pods", Namespaced: true, Kind: "Pod"},
|
||||
},
|
||||
"v2": {
|
||||
{Name: "pods", Namespaced: true, Kind: "Pod"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Group: metav1.APIGroup{
|
||||
Name: "extensions",
|
||||
Versions: []metav1.GroupVersionForDiscovery{
|
||||
{Version: "v1beta"},
|
||||
},
|
||||
PreferredVersion: metav1.GroupVersionForDiscovery{Version: "v1beta"},
|
||||
},
|
||||
VersionedResources: map[string][]metav1.APIResource{
|
||||
"v1beta": {
|
||||
{Name: "jobs", Namespaced: true, Kind: "Job"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
restMapper := NewRESTMapper(resources, nil)
|
||||
|
||||
kindTCs := []struct {
|
||||
input schema.GroupVersionResource
|
||||
want schema.GroupVersionKind
|
||||
}{
|
||||
{
|
||||
input: schema.GroupVersionResource{
|
||||
Version: "v1",
|
||||
Resource: "pods",
|
||||
},
|
||||
want: schema.GroupVersionKind{
|
||||
Version: "v1",
|
||||
Kind: "Pod",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: schema.GroupVersionResource{
|
||||
Version: "v2",
|
||||
Resource: "pods",
|
||||
},
|
||||
want: schema.GroupVersionKind{
|
||||
Version: "v2",
|
||||
Kind: "Pod",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: schema.GroupVersionResource{
|
||||
Resource: "pods",
|
||||
},
|
||||
want: schema.GroupVersionKind{
|
||||
Version: "v1",
|
||||
Kind: "Pod",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: schema.GroupVersionResource{
|
||||
Resource: "jobs",
|
||||
},
|
||||
want: schema.GroupVersionKind{
|
||||
Group: "extensions",
|
||||
Version: "v1beta",
|
||||
Kind: "Job",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range kindTCs {
|
||||
got, err := restMapper.KindFor(tc.input)
|
||||
if err != nil {
|
||||
t.Errorf("KindFor(%#v) unexpected error: %v", tc.input, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(got, tc.want) {
|
||||
t.Errorf("KindFor(%#v) = %#v, want %#v", tc.input, got, tc.want)
|
||||
}
|
||||
}
|
||||
|
||||
resourceTCs := []struct {
|
||||
input schema.GroupVersionResource
|
||||
want schema.GroupVersionResource
|
||||
}{
|
||||
{
|
||||
input: schema.GroupVersionResource{
|
||||
Version: "v1",
|
||||
Resource: "pods",
|
||||
},
|
||||
want: schema.GroupVersionResource{
|
||||
Version: "v1",
|
||||
Resource: "pods",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: schema.GroupVersionResource{
|
||||
Version: "v2",
|
||||
Resource: "pods",
|
||||
},
|
||||
want: schema.GroupVersionResource{
|
||||
Version: "v2",
|
||||
Resource: "pods",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: schema.GroupVersionResource{
|
||||
Resource: "pods",
|
||||
},
|
||||
want: schema.GroupVersionResource{
|
||||
Version: "v1",
|
||||
Resource: "pods",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: schema.GroupVersionResource{
|
||||
Resource: "jobs",
|
||||
},
|
||||
want: schema.GroupVersionResource{
|
||||
Group: "extensions",
|
||||
Version: "v1beta",
|
||||
Resource: "jobs",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range resourceTCs {
|
||||
got, err := restMapper.ResourceFor(tc.input)
|
||||
if err != nil {
|
||||
t.Errorf("ResourceFor(%#v) unexpected error: %v", tc.input, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(got, tc.want) {
|
||||
t.Errorf("ResourceFor(%#v) = %#v, want %#v", tc.input, got, tc.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeferredDiscoveryRESTMapper_CacheMiss(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
cdc := fakeCachedDiscoveryInterface{fresh: false}
|
||||
m := NewDeferredDiscoveryRESTMapper(&cdc, api.Registry.InterfacesFor)
|
||||
assert.False(cdc.fresh, "should NOT be fresh after instantiation")
|
||||
assert.Zero(cdc.invalidateCalls, "should not have called Invalidate()")
|
||||
|
||||
gvk, err := m.KindFor(schema.GroupVersionResource{
|
||||
Group: "a",
|
||||
Version: "v1",
|
||||
Resource: "foo",
|
||||
})
|
||||
assert.NoError(err)
|
||||
assert.True(cdc.fresh, "should be fresh after a cache-miss")
|
||||
assert.Equal(cdc.invalidateCalls, 1, "should have called Invalidate() once")
|
||||
assert.Equal(gvk.Kind, "Foo")
|
||||
|
||||
gvk, err = m.KindFor(schema.GroupVersionResource{
|
||||
Group: "a",
|
||||
Version: "v1",
|
||||
Resource: "foo",
|
||||
})
|
||||
assert.NoError(err)
|
||||
assert.Equal(cdc.invalidateCalls, 1, "should NOT have called Invalidate() again")
|
||||
|
||||
gvk, err = m.KindFor(schema.GroupVersionResource{
|
||||
Group: "a",
|
||||
Version: "v1",
|
||||
Resource: "bar",
|
||||
})
|
||||
assert.Error(err)
|
||||
assert.Equal(cdc.invalidateCalls, 1, "should NOT have called Invalidate() again after another cache-miss, but with fresh==true")
|
||||
|
||||
cdc.fresh = false
|
||||
gvk, err = m.KindFor(schema.GroupVersionResource{
|
||||
Group: "a",
|
||||
Version: "v1",
|
||||
Resource: "bar",
|
||||
})
|
||||
assert.Error(err)
|
||||
assert.Equal(cdc.invalidateCalls, 2, "should HAVE called Invalidate() again after another cache-miss, but with fresh==false")
|
||||
}
|
||||
|
||||
type fakeCachedDiscoveryInterface struct {
|
||||
invalidateCalls int
|
||||
fresh bool
|
||||
enabledA bool
|
||||
}
|
||||
|
||||
var _ CachedDiscoveryInterface = &fakeCachedDiscoveryInterface{}
|
||||
|
||||
func (c *fakeCachedDiscoveryInterface) Fresh() bool {
|
||||
return c.fresh
|
||||
}
|
||||
|
||||
func (c *fakeCachedDiscoveryInterface) Invalidate() {
|
||||
c.invalidateCalls = c.invalidateCalls + 1
|
||||
c.fresh = true
|
||||
c.enabledA = true
|
||||
}
|
||||
|
||||
func (c *fakeCachedDiscoveryInterface) RESTClient() restclient.Interface {
|
||||
return &fake.RESTClient{}
|
||||
}
|
||||
|
||||
func (c *fakeCachedDiscoveryInterface) ServerGroups() (*metav1.APIGroupList, error) {
|
||||
if c.enabledA {
|
||||
return &metav1.APIGroupList{
|
||||
Groups: []metav1.APIGroup{
|
||||
{
|
||||
Name: "a",
|
||||
Versions: []metav1.GroupVersionForDiscovery{
|
||||
{
|
||||
GroupVersion: "a/v1",
|
||||
Version: "v1",
|
||||
},
|
||||
},
|
||||
PreferredVersion: metav1.GroupVersionForDiscovery{
|
||||
GroupVersion: "a/v1",
|
||||
Version: "v1",
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
return &metav1.APIGroupList{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeCachedDiscoveryInterface) ServerResourcesForGroupVersion(groupVersion string) (*metav1.APIResourceList, error) {
|
||||
if c.enabledA && groupVersion == "a/v1" {
|
||||
return &metav1.APIResourceList{
|
||||
GroupVersion: "a/v1",
|
||||
APIResources: []metav1.APIResource{
|
||||
{
|
||||
Name: "foo",
|
||||
Kind: "Foo",
|
||||
Namespaced: false,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
return nil, errors.NewNotFound(schema.GroupResource{}, "")
|
||||
}
|
||||
|
||||
func (c *fakeCachedDiscoveryInterface) ServerResources() ([]*metav1.APIResourceList, error) {
|
||||
if c.enabledA {
|
||||
av1, _ := c.ServerResourcesForGroupVersion("a/v1")
|
||||
return []*metav1.APIResourceList{av1}, nil
|
||||
}
|
||||
return []*metav1.APIResourceList{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeCachedDiscoveryInterface) ServerPreferredResources() ([]*metav1.APIResourceList, error) {
|
||||
if c.enabledA {
|
||||
return []*metav1.APIResourceList{
|
||||
{
|
||||
GroupVersion: "a/v1",
|
||||
APIResources: []metav1.APIResource{
|
||||
{
|
||||
Name: "foo",
|
||||
Kind: "Foo",
|
||||
Verbs: []string{},
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeCachedDiscoveryInterface) ServerPreferredNamespacedResources() ([]*metav1.APIResourceList, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *fakeCachedDiscoveryInterface) ServerVersion() (*version.Info, error) {
|
||||
return &version.Info{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeCachedDiscoveryInterface) SwaggerSchema(version schema.GroupVersion) (*swagger.ApiDeclaration, error) {
|
||||
return &swagger.ApiDeclaration{}, nil
|
||||
}
|
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package discovery
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// UnstructuredObjectTyper provides a runtime.ObjectTyper implmentation for
|
||||
// runtime.Unstructured object based on discovery information.
|
||||
type UnstructuredObjectTyper struct {
|
||||
registered map[schema.GroupVersionKind]bool
|
||||
}
|
||||
|
||||
// NewUnstructuredObjectTyper returns a runtime.ObjectTyper for
|
||||
// unstructred objects based on discovery information.
|
||||
func NewUnstructuredObjectTyper(groupResources []*APIGroupResources) *UnstructuredObjectTyper {
|
||||
dot := &UnstructuredObjectTyper{registered: make(map[schema.GroupVersionKind]bool)}
|
||||
for _, group := range groupResources {
|
||||
for _, discoveryVersion := range group.Group.Versions {
|
||||
resources, ok := group.VersionedResources[discoveryVersion.Version]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
gv := schema.GroupVersion{Group: group.Group.Name, Version: discoveryVersion.Version}
|
||||
for _, resource := range resources {
|
||||
dot.registered[gv.WithKind(resource.Kind)] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return dot
|
||||
}
|
||||
|
||||
// ObjectKind returns the group,version,kind of the provided object, or an error
|
||||
// if the object in not runtime.Unstructured or has no group,version,kind
|
||||
// information.
|
||||
func (d *UnstructuredObjectTyper) ObjectKind(obj runtime.Object) (schema.GroupVersionKind, error) {
|
||||
if _, ok := obj.(runtime.Unstructured); !ok {
|
||||
return schema.GroupVersionKind{}, fmt.Errorf("type %T is invalid for dynamic object typer", obj)
|
||||
}
|
||||
|
||||
return obj.GetObjectKind().GroupVersionKind(), nil
|
||||
}
|
||||
|
||||
// ObjectKinds returns a slice of one element with the group,version,kind of the
|
||||
// provided object, or an error if the object is not runtime.Unstructured or
|
||||
// has no group,version,kind information. unversionedType will always be false
|
||||
// because runtime.Unstructured object should always have group,version,kind
|
||||
// information set.
|
||||
func (d *UnstructuredObjectTyper) ObjectKinds(obj runtime.Object) (gvks []schema.GroupVersionKind, unversionedType bool, err error) {
|
||||
gvk, err := d.ObjectKind(obj)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
return []schema.GroupVersionKind{gvk}, false, nil
|
||||
}
|
||||
|
||||
// Recognizes returns true if the provided group,version,kind was in the
|
||||
// discovery information.
|
||||
func (d *UnstructuredObjectTyper) Recognizes(gvk schema.GroupVersionKind) bool {
|
||||
return d.registered[gvk]
|
||||
}
|
||||
|
||||
// IsUnversioned returns false always because runtime.Unstructured objects
|
||||
// should always have group,version,kind information set. ok will be true if the
|
||||
// object's group,version,kind is api.Registry.
|
||||
func (d *UnstructuredObjectTyper) IsUnversioned(obj runtime.Object) (unversioned bool, ok bool) {
|
||||
gvk, err := d.ObjectKind(obj)
|
||||
if err != nil {
|
||||
return false, false
|
||||
}
|
||||
|
||||
return false, d.registered[gvk]
|
||||
}
|
||||
|
||||
var _ runtime.ObjectTyper = &UnstructuredObjectTyper{}
|
@@ -1,68 +0,0 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"client.go",
|
||||
"client_pool.go",
|
||||
"dynamic_util.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//vendor:k8s.io/apimachinery/pkg/api/meta",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1/unstructured",
|
||||
"//vendor:k8s.io/apimachinery/pkg/conversion/queryparams",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime/serializer",
|
||||
"//vendor:k8s.io/apimachinery/pkg/types",
|
||||
"//vendor:k8s.io/apimachinery/pkg/watch",
|
||||
"//vendor:k8s.io/client-go/rest",
|
||||
"//vendor:k8s.io/client-go/util/flowcontrol",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"client_test.go",
|
||||
"dynamic_util_test.go",
|
||||
],
|
||||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1/unstructured",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime/serializer/streaming",
|
||||
"//vendor:k8s.io/apimachinery/pkg/types",
|
||||
"//vendor:k8s.io/apimachinery/pkg/watch",
|
||||
"//vendor:k8s.io/client-go/rest",
|
||||
"//vendor:k8s.io/client-go/rest/watch",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
@@ -1,301 +0,0 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package dynamic provides a client interface to arbitrary Kubernetes
|
||||
// APIs that exposes common high level operations and exposes common
|
||||
// metadata.
|
||||
package dynamic
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/conversion/queryparams"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/util/flowcontrol"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
)
|
||||
|
||||
// Client is a Kubernetes client that allows you to access metadata
|
||||
// and manipulate metadata of a Kubernetes API group.
|
||||
type Client struct {
|
||||
cl *restclient.RESTClient
|
||||
parameterCodec runtime.ParameterCodec
|
||||
}
|
||||
|
||||
// NewClient returns a new client based on the passed in config. The
|
||||
// codec is ignored, as the dynamic client uses it's own codec.
|
||||
func NewClient(conf *restclient.Config) (*Client, error) {
|
||||
// avoid changing the original config
|
||||
confCopy := *conf
|
||||
conf = &confCopy
|
||||
|
||||
contentConfig := ContentConfig()
|
||||
contentConfig.GroupVersion = conf.GroupVersion
|
||||
if conf.NegotiatedSerializer != nil {
|
||||
contentConfig.NegotiatedSerializer = conf.NegotiatedSerializer
|
||||
}
|
||||
conf.ContentConfig = contentConfig
|
||||
|
||||
if conf.APIPath == "" {
|
||||
conf.APIPath = "/api"
|
||||
}
|
||||
|
||||
if len(conf.UserAgent) == 0 {
|
||||
conf.UserAgent = restclient.DefaultKubernetesUserAgent()
|
||||
}
|
||||
|
||||
cl, err := restclient.RESTClientFor(conf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Client{cl: cl}, nil
|
||||
}
|
||||
|
||||
// GetRateLimiter returns rate limier.
|
||||
func (c *Client) GetRateLimiter() flowcontrol.RateLimiter {
|
||||
return c.cl.GetRateLimiter()
|
||||
}
|
||||
|
||||
// Resource returns an API interface to the specified resource for this client's
|
||||
// group and version. If resource is not a namespaced resource, then namespace
|
||||
// is ignored. The ResourceClient inherits the parameter codec of c.
|
||||
func (c *Client) Resource(resource *metav1.APIResource, namespace string) *ResourceClient {
|
||||
return &ResourceClient{
|
||||
cl: c.cl,
|
||||
resource: resource,
|
||||
ns: namespace,
|
||||
parameterCodec: c.parameterCodec,
|
||||
}
|
||||
}
|
||||
|
||||
// ParameterCodec returns a client with the provided parameter codec.
|
||||
func (c *Client) ParameterCodec(parameterCodec runtime.ParameterCodec) *Client {
|
||||
return &Client{
|
||||
cl: c.cl,
|
||||
parameterCodec: parameterCodec,
|
||||
}
|
||||
}
|
||||
|
||||
// ResourceClient is an API interface to a specific resource under a
|
||||
// dynamic client.
|
||||
type ResourceClient struct {
|
||||
cl *restclient.RESTClient
|
||||
resource *metav1.APIResource
|
||||
ns string
|
||||
parameterCodec runtime.ParameterCodec
|
||||
}
|
||||
|
||||
// List returns a list of objects for this resource.
|
||||
func (rc *ResourceClient) List(opts runtime.Object) (runtime.Object, error) {
|
||||
parameterEncoder := rc.parameterCodec
|
||||
if parameterEncoder == nil {
|
||||
parameterEncoder = defaultParameterEncoder
|
||||
}
|
||||
return rc.cl.Get().
|
||||
NamespaceIfScoped(rc.ns, rc.resource.Namespaced).
|
||||
Resource(rc.resource.Name).
|
||||
VersionedParams(opts, parameterEncoder).
|
||||
Do().
|
||||
Get()
|
||||
}
|
||||
|
||||
// Get gets the resource with the specified name.
|
||||
func (rc *ResourceClient) Get(name string) (*unstructured.Unstructured, error) {
|
||||
result := new(unstructured.Unstructured)
|
||||
err := rc.cl.Get().
|
||||
NamespaceIfScoped(rc.ns, rc.resource.Namespaced).
|
||||
Resource(rc.resource.Name).
|
||||
Name(name).
|
||||
Do().
|
||||
Into(result)
|
||||
return result, err
|
||||
}
|
||||
|
||||
// Delete deletes the resource with the specified name.
|
||||
func (rc *ResourceClient) Delete(name string, opts *metav1.DeleteOptions) error {
|
||||
return rc.cl.Delete().
|
||||
NamespaceIfScoped(rc.ns, rc.resource.Namespaced).
|
||||
Resource(rc.resource.Name).
|
||||
Name(name).
|
||||
Body(opts).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (rc *ResourceClient) DeleteCollection(deleteOptions *metav1.DeleteOptions, listOptions runtime.Object) error {
|
||||
parameterEncoder := rc.parameterCodec
|
||||
if parameterEncoder == nil {
|
||||
parameterEncoder = defaultParameterEncoder
|
||||
}
|
||||
return rc.cl.Delete().
|
||||
NamespaceIfScoped(rc.ns, rc.resource.Namespaced).
|
||||
Resource(rc.resource.Name).
|
||||
VersionedParams(listOptions, parameterEncoder).
|
||||
Body(deleteOptions).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// Create creates the provided resource.
|
||||
func (rc *ResourceClient) Create(obj *unstructured.Unstructured) (*unstructured.Unstructured, error) {
|
||||
result := new(unstructured.Unstructured)
|
||||
err := rc.cl.Post().
|
||||
NamespaceIfScoped(rc.ns, rc.resource.Namespaced).
|
||||
Resource(rc.resource.Name).
|
||||
Body(obj).
|
||||
Do().
|
||||
Into(result)
|
||||
return result, err
|
||||
}
|
||||
|
||||
// Update updates the provided resource.
|
||||
func (rc *ResourceClient) Update(obj *unstructured.Unstructured) (*unstructured.Unstructured, error) {
|
||||
result := new(unstructured.Unstructured)
|
||||
if len(obj.GetName()) == 0 {
|
||||
return result, errors.New("object missing name")
|
||||
}
|
||||
err := rc.cl.Put().
|
||||
NamespaceIfScoped(rc.ns, rc.resource.Namespaced).
|
||||
Resource(rc.resource.Name).
|
||||
Name(obj.GetName()).
|
||||
Body(obj).
|
||||
Do().
|
||||
Into(result)
|
||||
return result, err
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the resource.
|
||||
func (rc *ResourceClient) Watch(opts runtime.Object) (watch.Interface, error) {
|
||||
parameterEncoder := rc.parameterCodec
|
||||
if parameterEncoder == nil {
|
||||
parameterEncoder = defaultParameterEncoder
|
||||
}
|
||||
return rc.cl.Get().
|
||||
Prefix("watch").
|
||||
NamespaceIfScoped(rc.ns, rc.resource.Namespaced).
|
||||
Resource(rc.resource.Name).
|
||||
VersionedParams(opts, parameterEncoder).
|
||||
Watch()
|
||||
}
|
||||
|
||||
func (rc *ResourceClient) Patch(name string, pt types.PatchType, data []byte) (*unstructured.Unstructured, error) {
|
||||
result := new(unstructured.Unstructured)
|
||||
err := rc.cl.Patch(pt).
|
||||
NamespaceIfScoped(rc.ns, rc.resource.Namespaced).
|
||||
Resource(rc.resource.Name).
|
||||
Name(name).
|
||||
Body(data).
|
||||
Do().
|
||||
Into(result)
|
||||
return result, err
|
||||
}
|
||||
|
||||
// dynamicCodec is a codec that wraps the standard unstructured codec
|
||||
// with special handling for Status objects.
|
||||
type dynamicCodec struct{}
|
||||
|
||||
func (dynamicCodec) Decode(data []byte, gvk *schema.GroupVersionKind, obj runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) {
|
||||
obj, gvk, err := unstructured.UnstructuredJSONScheme.Decode(data, gvk, obj)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if _, ok := obj.(*metav1.Status); !ok && strings.ToLower(gvk.Kind) == "status" {
|
||||
obj = &metav1.Status{}
|
||||
err := json.Unmarshal(data, obj)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return obj, gvk, nil
|
||||
}
|
||||
|
||||
func (dynamicCodec) Encode(obj runtime.Object, w io.Writer) error {
|
||||
return unstructured.UnstructuredJSONScheme.Encode(obj, w)
|
||||
}
|
||||
|
||||
// ContentConfig returns a restclient.ContentConfig for dynamic types.
|
||||
func ContentConfig() restclient.ContentConfig {
|
||||
var jsonInfo runtime.SerializerInfo
|
||||
// TODO: api.Codecs here should become "pkg/apis/server/scheme" which is the minimal core you need
|
||||
// to talk to a kubernetes server
|
||||
for _, info := range api.Codecs.SupportedMediaTypes() {
|
||||
if info.MediaType == runtime.ContentTypeJSON {
|
||||
jsonInfo = info
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
jsonInfo.Serializer = dynamicCodec{}
|
||||
jsonInfo.PrettySerializer = nil
|
||||
return restclient.ContentConfig{
|
||||
AcceptContentTypes: runtime.ContentTypeJSON,
|
||||
ContentType: runtime.ContentTypeJSON,
|
||||
NegotiatedSerializer: serializer.NegotiatedSerializerWrapper(jsonInfo),
|
||||
}
|
||||
}
|
||||
|
||||
// paramaterCodec is a codec converts an API object to query
|
||||
// parameters without trying to convert to the target version.
|
||||
type parameterCodec struct{}
|
||||
|
||||
func (parameterCodec) EncodeParameters(obj runtime.Object, to schema.GroupVersion) (url.Values, error) {
|
||||
return queryparams.Convert(obj)
|
||||
}
|
||||
|
||||
func (parameterCodec) DecodeParameters(parameters url.Values, from schema.GroupVersion, into runtime.Object) error {
|
||||
return errors.New("DecodeParameters not implemented on dynamic parameterCodec")
|
||||
}
|
||||
|
||||
var defaultParameterEncoder runtime.ParameterCodec = parameterCodec{}
|
||||
|
||||
type versionedParameterEncoderWithV1Fallback struct{}
|
||||
|
||||
func (versionedParameterEncoderWithV1Fallback) EncodeParameters(obj runtime.Object, to schema.GroupVersion) (url.Values, error) {
|
||||
ret, err := api.ParameterCodec.EncodeParameters(obj, to)
|
||||
if err != nil && runtime.IsNotRegisteredError(err) {
|
||||
// fallback to v1
|
||||
return api.ParameterCodec.EncodeParameters(obj, v1.SchemeGroupVersion)
|
||||
}
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func (versionedParameterEncoderWithV1Fallback) DecodeParameters(parameters url.Values, from schema.GroupVersion, into runtime.Object) error {
|
||||
return errors.New("DecodeParameters not implemented on versionedParameterEncoderWithV1Fallback")
|
||||
}
|
||||
|
||||
// VersionedParameterEncoderWithV1Fallback is useful for encoding query
|
||||
// parameters for thirdparty resources. It tries to convert object to the
|
||||
// specified version before converting it to query parameters, and falls back to
|
||||
// converting to v1 if the object is not registered in the specified version.
|
||||
// For the record, currently API server always treats query parameters sent to a
|
||||
// thirdparty resource endpoint as v1.
|
||||
var VersionedParameterEncoderWithV1Fallback runtime.ParameterCodec = versionedParameterEncoderWithV1Fallback{}
|
@@ -1,115 +0,0 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package dynamic
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// ClientPool manages a pool of dynamic clients.
|
||||
type ClientPool interface {
|
||||
// ClientForGroupVersionKind returns a client configured for the specified groupVersionResource.
|
||||
// Resource may be empty.
|
||||
ClientForGroupVersionResource(resource schema.GroupVersionResource) (*Client, error)
|
||||
// ClientForGroupVersionKind returns a client configured for the specified groupVersionKind.
|
||||
// Kind may be empty.
|
||||
ClientForGroupVersionKind(kind schema.GroupVersionKind) (*Client, error)
|
||||
}
|
||||
|
||||
// APIPathResolverFunc knows how to convert a groupVersion to its API path. The Kind field is
|
||||
// optional.
|
||||
type APIPathResolverFunc func(kind schema.GroupVersionKind) string
|
||||
|
||||
// LegacyAPIPathResolverFunc can resolve paths properly with the legacy API.
|
||||
func LegacyAPIPathResolverFunc(kind schema.GroupVersionKind) string {
|
||||
if len(kind.Group) == 0 {
|
||||
return "/api"
|
||||
}
|
||||
return "/apis"
|
||||
}
|
||||
|
||||
// clientPoolImpl implements ClientPool and caches clients for the resource group versions
|
||||
// is asked to retrieve. This type is thread safe.
|
||||
type clientPoolImpl struct {
|
||||
lock sync.RWMutex
|
||||
config *restclient.Config
|
||||
clients map[schema.GroupVersion]*Client
|
||||
apiPathResolverFunc APIPathResolverFunc
|
||||
mapper meta.RESTMapper
|
||||
}
|
||||
|
||||
// NewClientPool returns a ClientPool from the specified config. It reuses clients for the the same
|
||||
// group version. It is expected this type may be wrapped by specific logic that special cases certain
|
||||
// resources or groups.
|
||||
func NewClientPool(config *restclient.Config, mapper meta.RESTMapper, apiPathResolverFunc APIPathResolverFunc) ClientPool {
|
||||
confCopy := *config
|
||||
|
||||
return &clientPoolImpl{
|
||||
config: &confCopy,
|
||||
clients: map[schema.GroupVersion]*Client{},
|
||||
apiPathResolverFunc: apiPathResolverFunc,
|
||||
mapper: mapper,
|
||||
}
|
||||
}
|
||||
|
||||
// ClientForGroupVersionResource uses the provided RESTMapper to identify the appropriate resource. Resource may
|
||||
// be empty. If no matching kind is found the underlying client for that group is still returned.
|
||||
func (c *clientPoolImpl) ClientForGroupVersionResource(resource schema.GroupVersionResource) (*Client, error) {
|
||||
kinds, err := c.mapper.KindsFor(resource)
|
||||
if err != nil {
|
||||
if meta.IsNoMatchError(err) {
|
||||
return c.ClientForGroupVersionKind(schema.GroupVersionKind{Group: resource.Group, Version: resource.Version})
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return c.ClientForGroupVersionKind(kinds[0])
|
||||
}
|
||||
|
||||
// ClientForGroupVersion returns a client for the specified groupVersion, creates one if none exists. Kind
|
||||
// in the GroupVersionKind may be empty.
|
||||
func (c *clientPoolImpl) ClientForGroupVersionKind(kind schema.GroupVersionKind) (*Client, error) {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
gv := kind.GroupVersion()
|
||||
|
||||
// do we have a client already configured?
|
||||
if existingClient, found := c.clients[gv]; found {
|
||||
return existingClient, nil
|
||||
}
|
||||
|
||||
// avoid changing the original config
|
||||
confCopy := *c.config
|
||||
conf := &confCopy
|
||||
|
||||
// we need to set the api path based on group version, if no group, default to legacy path
|
||||
conf.APIPath = c.apiPathResolverFunc(kind)
|
||||
|
||||
// we need to make a client
|
||||
conf.GroupVersion = &gv
|
||||
|
||||
dynamicClient, err := NewClient(conf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.clients[gv] = dynamicClient
|
||||
return dynamicClient, nil
|
||||
}
|
@@ -1,552 +0,0 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package dynamic
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/streaming"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
restclientwatch "k8s.io/client-go/rest/watch"
|
||||
)
|
||||
|
||||
func getJSON(version, kind, name string) []byte {
|
||||
return []byte(fmt.Sprintf(`{"apiVersion": %q, "kind": %q, "metadata": {"name": %q}}`, version, kind, name))
|
||||
}
|
||||
|
||||
func getListJSON(version, kind string, items ...[]byte) []byte {
|
||||
json := fmt.Sprintf(`{"apiVersion": %q, "kind": %q, "items": [%s]}`,
|
||||
version, kind, bytes.Join(items, []byte(",")))
|
||||
return []byte(json)
|
||||
}
|
||||
|
||||
func getObject(version, kind, name string) *unstructured.Unstructured {
|
||||
return &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": version,
|
||||
"kind": kind,
|
||||
"metadata": map[string]interface{}{
|
||||
"name": name,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getClientServer(gv *schema.GroupVersion, h func(http.ResponseWriter, *http.Request)) (*Client, *httptest.Server, error) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(h))
|
||||
cl, err := NewClient(&restclient.Config{
|
||||
Host: srv.URL,
|
||||
ContentConfig: restclient.ContentConfig{GroupVersion: gv},
|
||||
})
|
||||
if err != nil {
|
||||
srv.Close()
|
||||
return nil, nil, err
|
||||
}
|
||||
return cl, srv, nil
|
||||
}
|
||||
|
||||
func TestList(t *testing.T) {
|
||||
tcs := []struct {
|
||||
name string
|
||||
namespace string
|
||||
path string
|
||||
resp []byte
|
||||
want *unstructured.UnstructuredList
|
||||
}{
|
||||
{
|
||||
name: "normal_list",
|
||||
path: "/api/gtest/vtest/rtest",
|
||||
resp: getListJSON("vTest", "rTestList",
|
||||
getJSON("vTest", "rTest", "item1"),
|
||||
getJSON("vTest", "rTest", "item2")),
|
||||
want: &unstructured.UnstructuredList{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "vTest",
|
||||
"kind": "rTestList",
|
||||
},
|
||||
Items: []*unstructured.Unstructured{
|
||||
getObject("vTest", "rTest", "item1"),
|
||||
getObject("vTest", "rTest", "item2"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "namespaced_list",
|
||||
namespace: "nstest",
|
||||
path: "/api/gtest/vtest/namespaces/nstest/rtest",
|
||||
resp: getListJSON("vTest", "rTestList",
|
||||
getJSON("vTest", "rTest", "item1"),
|
||||
getJSON("vTest", "rTest", "item2")),
|
||||
want: &unstructured.UnstructuredList{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "vTest",
|
||||
"kind": "rTestList",
|
||||
},
|
||||
Items: []*unstructured.Unstructured{
|
||||
getObject("vTest", "rTest", "item1"),
|
||||
getObject("vTest", "rTest", "item2"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"}
|
||||
resource := &metav1.APIResource{Name: "rtest", Namespaced: len(tc.namespace) != 0}
|
||||
cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" {
|
||||
t.Errorf("List(%q) got HTTP method %s. wanted GET", tc.name, r.Method)
|
||||
}
|
||||
|
||||
if r.URL.Path != tc.path {
|
||||
t.Errorf("List(%q) got path %s. wanted %s", tc.name, r.URL.Path, tc.path)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", runtime.ContentTypeJSON)
|
||||
w.Write(tc.resp)
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when creating client: %v", err)
|
||||
continue
|
||||
}
|
||||
defer srv.Close()
|
||||
|
||||
got, err := cl.Resource(resource, tc.namespace).List(&metav1.ListOptions{})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when listing %q: %v", tc.name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(got, tc.want) {
|
||||
t.Errorf("List(%q) want: %v\ngot: %v", tc.name, tc.want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
tcs := []struct {
|
||||
namespace string
|
||||
name string
|
||||
path string
|
||||
resp []byte
|
||||
want *unstructured.Unstructured
|
||||
}{
|
||||
{
|
||||
name: "normal_get",
|
||||
path: "/api/gtest/vtest/rtest/normal_get",
|
||||
resp: getJSON("vTest", "rTest", "normal_get"),
|
||||
want: getObject("vTest", "rTest", "normal_get"),
|
||||
},
|
||||
{
|
||||
namespace: "nstest",
|
||||
name: "namespaced_get",
|
||||
path: "/api/gtest/vtest/namespaces/nstest/rtest/namespaced_get",
|
||||
resp: getJSON("vTest", "rTest", "namespaced_get"),
|
||||
want: getObject("vTest", "rTest", "namespaced_get"),
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"}
|
||||
resource := &metav1.APIResource{Name: "rtest", Namespaced: len(tc.namespace) != 0}
|
||||
cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" {
|
||||
t.Errorf("Get(%q) got HTTP method %s. wanted GET", tc.name, r.Method)
|
||||
}
|
||||
|
||||
if r.URL.Path != tc.path {
|
||||
t.Errorf("Get(%q) got path %s. wanted %s", tc.name, r.URL.Path, tc.path)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", runtime.ContentTypeJSON)
|
||||
w.Write(tc.resp)
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when creating client: %v", err)
|
||||
continue
|
||||
}
|
||||
defer srv.Close()
|
||||
|
||||
got, err := cl.Resource(resource, tc.namespace).Get(tc.name)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when getting %q: %v", tc.name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(got, tc.want) {
|
||||
t.Errorf("Get(%q) want: %v\ngot: %v", tc.name, tc.want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
statusOK := &metav1.Status{
|
||||
TypeMeta: metav1.TypeMeta{Kind: "Status"},
|
||||
Status: metav1.StatusSuccess,
|
||||
}
|
||||
tcs := []struct {
|
||||
namespace string
|
||||
name string
|
||||
path string
|
||||
}{
|
||||
{
|
||||
name: "normal_delete",
|
||||
path: "/api/gtest/vtest/rtest/normal_delete",
|
||||
},
|
||||
{
|
||||
namespace: "nstest",
|
||||
name: "namespaced_delete",
|
||||
path: "/api/gtest/vtest/namespaces/nstest/rtest/namespaced_delete",
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"}
|
||||
resource := &metav1.APIResource{Name: "rtest", Namespaced: len(tc.namespace) != 0}
|
||||
cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "DELETE" {
|
||||
t.Errorf("Delete(%q) got HTTP method %s. wanted DELETE", tc.name, r.Method)
|
||||
}
|
||||
|
||||
if r.URL.Path != tc.path {
|
||||
t.Errorf("Delete(%q) got path %s. wanted %s", tc.name, r.URL.Path, tc.path)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", runtime.ContentTypeJSON)
|
||||
unstructured.UnstructuredJSONScheme.Encode(statusOK, w)
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when creating client: %v", err)
|
||||
continue
|
||||
}
|
||||
defer srv.Close()
|
||||
|
||||
err = cl.Resource(resource, tc.namespace).Delete(tc.name, nil)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when deleting %q: %v", tc.name, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteCollection(t *testing.T) {
|
||||
statusOK := &metav1.Status{
|
||||
TypeMeta: metav1.TypeMeta{Kind: "Status"},
|
||||
Status: metav1.StatusSuccess,
|
||||
}
|
||||
tcs := []struct {
|
||||
namespace string
|
||||
name string
|
||||
path string
|
||||
}{
|
||||
{
|
||||
name: "normal_delete_collection",
|
||||
path: "/api/gtest/vtest/rtest",
|
||||
},
|
||||
{
|
||||
namespace: "nstest",
|
||||
name: "namespaced_delete_collection",
|
||||
path: "/api/gtest/vtest/namespaces/nstest/rtest",
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"}
|
||||
resource := &metav1.APIResource{Name: "rtest", Namespaced: len(tc.namespace) != 0}
|
||||
cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "DELETE" {
|
||||
t.Errorf("DeleteCollection(%q) got HTTP method %s. wanted DELETE", tc.name, r.Method)
|
||||
}
|
||||
|
||||
if r.URL.Path != tc.path {
|
||||
t.Errorf("DeleteCollection(%q) got path %s. wanted %s", tc.name, r.URL.Path, tc.path)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", runtime.ContentTypeJSON)
|
||||
unstructured.UnstructuredJSONScheme.Encode(statusOK, w)
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when creating client: %v", err)
|
||||
continue
|
||||
}
|
||||
defer srv.Close()
|
||||
|
||||
err = cl.Resource(resource, tc.namespace).DeleteCollection(nil, &metav1.ListOptions{})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when deleting collection %q: %v", tc.name, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreate(t *testing.T) {
|
||||
tcs := []struct {
|
||||
name string
|
||||
namespace string
|
||||
obj *unstructured.Unstructured
|
||||
path string
|
||||
}{
|
||||
{
|
||||
name: "normal_create",
|
||||
path: "/api/gtest/vtest/rtest",
|
||||
obj: getObject("vTest", "rTest", "normal_create"),
|
||||
},
|
||||
{
|
||||
name: "namespaced_create",
|
||||
namespace: "nstest",
|
||||
path: "/api/gtest/vtest/namespaces/nstest/rtest",
|
||||
obj: getObject("vTest", "rTest", "namespaced_create"),
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"}
|
||||
resource := &metav1.APIResource{Name: "rtest", Namespaced: len(tc.namespace) != 0}
|
||||
cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "POST" {
|
||||
t.Errorf("Create(%q) got HTTP method %s. wanted POST", tc.name, r.Method)
|
||||
}
|
||||
|
||||
if r.URL.Path != tc.path {
|
||||
t.Errorf("Create(%q) got path %s. wanted %s", tc.name, r.URL.Path, tc.path)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", runtime.ContentTypeJSON)
|
||||
data, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Errorf("Create(%q) unexpected error reading body: %v", tc.name, err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Write(data)
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when creating client: %v", err)
|
||||
continue
|
||||
}
|
||||
defer srv.Close()
|
||||
|
||||
got, err := cl.Resource(resource, tc.namespace).Create(tc.obj)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when creating %q: %v", tc.name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(got, tc.obj) {
|
||||
t.Errorf("Create(%q) want: %v\ngot: %v", tc.name, tc.obj, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdate(t *testing.T) {
|
||||
tcs := []struct {
|
||||
name string
|
||||
namespace string
|
||||
obj *unstructured.Unstructured
|
||||
path string
|
||||
}{
|
||||
{
|
||||
name: "normal_update",
|
||||
path: "/api/gtest/vtest/rtest/normal_update",
|
||||
obj: getObject("vTest", "rTest", "normal_update"),
|
||||
},
|
||||
{
|
||||
name: "namespaced_update",
|
||||
namespace: "nstest",
|
||||
path: "/api/gtest/vtest/namespaces/nstest/rtest/namespaced_update",
|
||||
obj: getObject("vTest", "rTest", "namespaced_update"),
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"}
|
||||
resource := &metav1.APIResource{Name: "rtest", Namespaced: len(tc.namespace) != 0}
|
||||
cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "PUT" {
|
||||
t.Errorf("Update(%q) got HTTP method %s. wanted PUT", tc.name, r.Method)
|
||||
}
|
||||
|
||||
if r.URL.Path != tc.path {
|
||||
t.Errorf("Update(%q) got path %s. wanted %s", tc.name, r.URL.Path, tc.path)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", runtime.ContentTypeJSON)
|
||||
data, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Errorf("Update(%q) unexpected error reading body: %v", tc.name, err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Write(data)
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when creating client: %v", err)
|
||||
continue
|
||||
}
|
||||
defer srv.Close()
|
||||
|
||||
got, err := cl.Resource(resource, tc.namespace).Update(tc.obj)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when updating %q: %v", tc.name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(got, tc.obj) {
|
||||
t.Errorf("Update(%q) want: %v\ngot: %v", tc.name, tc.obj, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestWatch(t *testing.T) {
|
||||
tcs := []struct {
|
||||
name string
|
||||
namespace string
|
||||
events []watch.Event
|
||||
path string
|
||||
}{
|
||||
{
|
||||
name: "normal_watch",
|
||||
path: "/api/gtest/vtest/watch/rtest",
|
||||
events: []watch.Event{
|
||||
{Type: watch.Added, Object: getObject("vTest", "rTest", "normal_watch")},
|
||||
{Type: watch.Modified, Object: getObject("vTest", "rTest", "normal_watch")},
|
||||
{Type: watch.Deleted, Object: getObject("vTest", "rTest", "normal_watch")},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "namespaced_watch",
|
||||
namespace: "nstest",
|
||||
path: "/api/gtest/vtest/watch/namespaces/nstest/rtest",
|
||||
events: []watch.Event{
|
||||
{Type: watch.Added, Object: getObject("vTest", "rTest", "namespaced_watch")},
|
||||
{Type: watch.Modified, Object: getObject("vTest", "rTest", "namespaced_watch")},
|
||||
{Type: watch.Deleted, Object: getObject("vTest", "rTest", "namespaced_watch")},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"}
|
||||
resource := &metav1.APIResource{Name: "rtest", Namespaced: len(tc.namespace) != 0}
|
||||
cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" {
|
||||
t.Errorf("Watch(%q) got HTTP method %s. wanted GET", tc.name, r.Method)
|
||||
}
|
||||
|
||||
if r.URL.Path != tc.path {
|
||||
t.Errorf("Watch(%q) got path %s. wanted %s", tc.name, r.URL.Path, tc.path)
|
||||
}
|
||||
|
||||
enc := restclientwatch.NewEncoder(streaming.NewEncoder(w, dynamicCodec{}), dynamicCodec{})
|
||||
for _, e := range tc.events {
|
||||
enc.Encode(&e)
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when creating client: %v", err)
|
||||
continue
|
||||
}
|
||||
defer srv.Close()
|
||||
|
||||
watcher, err := cl.Resource(resource, tc.namespace).Watch(&metav1.ListOptions{})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when watching %q: %v", tc.name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, want := range tc.events {
|
||||
got := <-watcher.ResultChan()
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("Watch(%q) want: %v\ngot: %v", tc.name, want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPatch(t *testing.T) {
|
||||
tcs := []struct {
|
||||
name string
|
||||
namespace string
|
||||
patch []byte
|
||||
want *unstructured.Unstructured
|
||||
path string
|
||||
}{
|
||||
{
|
||||
name: "normal_patch",
|
||||
path: "/api/gtest/vtest/rtest/normal_patch",
|
||||
patch: getJSON("vTest", "rTest", "normal_patch"),
|
||||
want: getObject("vTest", "rTest", "normal_patch"),
|
||||
},
|
||||
{
|
||||
name: "namespaced_patch",
|
||||
namespace: "nstest",
|
||||
path: "/api/gtest/vtest/namespaces/nstest/rtest/namespaced_patch",
|
||||
patch: getJSON("vTest", "rTest", "namespaced_patch"),
|
||||
want: getObject("vTest", "rTest", "namespaced_patch"),
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"}
|
||||
resource := &metav1.APIResource{Name: "rtest", Namespaced: len(tc.namespace) != 0}
|
||||
cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "PATCH" {
|
||||
t.Errorf("Patch(%q) got HTTP method %s. wanted PATCH", tc.name, r.Method)
|
||||
}
|
||||
|
||||
if r.URL.Path != tc.path {
|
||||
t.Errorf("Patch(%q) got path %s. wanted %s", tc.name, r.URL.Path, tc.path)
|
||||
}
|
||||
|
||||
content := r.Header.Get("Content-Type")
|
||||
if content != string(types.StrategicMergePatchType) {
|
||||
t.Errorf("Patch(%q) got Content-Type %s. wanted %s", tc.name, content, types.StrategicMergePatchType)
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Errorf("Patch(%q) unexpected error reading body: %v", tc.name, err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(data)
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when creating client: %v", err)
|
||||
continue
|
||||
}
|
||||
defer srv.Close()
|
||||
|
||||
got, err := cl.Resource(resource, tc.namespace).Patch(tc.name, types.StrategicMergePatchType, tc.patch)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when patching %q: %v", tc.name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(got, tc.want) {
|
||||
t.Errorf("Patch(%q) want: %v\ngot: %v", tc.name, tc.want, got)
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package dynamic
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// VersionInterfaces provides an object converter and metadata
|
||||
// accessor appropriate for use with unstructured objects.
|
||||
func VersionInterfaces(schema.GroupVersion) (*meta.VersionInterfaces, error) {
|
||||
return &meta.VersionInterfaces{
|
||||
ObjectConvertor: &unstructured.UnstructuredObjectConverter{},
|
||||
MetadataAccessor: meta.NewAccessor(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewDiscoveryRESTMapper returns a RESTMapper based on discovery information.
|
||||
func NewDiscoveryRESTMapper(resources []*metav1.APIResourceList, versionFunc meta.VersionInterfacesFunc) (*meta.DefaultRESTMapper, error) {
|
||||
rm := meta.NewDefaultRESTMapper(nil, versionFunc)
|
||||
for _, resourceList := range resources {
|
||||
gv, err := schema.ParseGroupVersion(resourceList.GroupVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, resource := range resourceList.APIResources {
|
||||
gvk := gv.WithKind(resource.Kind)
|
||||
scope := meta.RESTScopeRoot
|
||||
if resource.Namespaced {
|
||||
scope = meta.RESTScopeNamespace
|
||||
}
|
||||
rm.Add(gvk, scope)
|
||||
}
|
||||
}
|
||||
return rm, nil
|
||||
}
|
||||
|
||||
// ObjectTyper provides an ObjectTyper implementation for
|
||||
// unstructured.Unstructured object based on discovery information.
|
||||
type ObjectTyper struct {
|
||||
registered map[schema.GroupVersionKind]bool
|
||||
}
|
||||
|
||||
// NewObjectTyper constructs an ObjectTyper from discovery information.
|
||||
func NewObjectTyper(resources []*metav1.APIResourceList) (runtime.ObjectTyper, error) {
|
||||
ot := &ObjectTyper{registered: make(map[schema.GroupVersionKind]bool)}
|
||||
for _, resourceList := range resources {
|
||||
gv, err := schema.ParseGroupVersion(resourceList.GroupVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, resource := range resourceList.APIResources {
|
||||
ot.registered[gv.WithKind(resource.Kind)] = true
|
||||
}
|
||||
}
|
||||
return ot, nil
|
||||
}
|
||||
|
||||
// ObjectKinds returns a slice of one element with the
|
||||
// group,version,kind of the provided object, or an error if the
|
||||
// object is not *unstructured.Unstructured or has no group,version,kind
|
||||
// information.
|
||||
func (ot *ObjectTyper) ObjectKinds(obj runtime.Object) ([]schema.GroupVersionKind, bool, error) {
|
||||
if _, ok := obj.(*unstructured.Unstructured); !ok {
|
||||
return nil, false, fmt.Errorf("type %T is invalid for dynamic object typer", obj)
|
||||
}
|
||||
return []schema.GroupVersionKind{obj.GetObjectKind().GroupVersionKind()}, false, nil
|
||||
}
|
||||
|
||||
// Recognizes returns true if the provided group,version,kind was in
|
||||
// the discovery information.
|
||||
func (ot *ObjectTyper) Recognizes(gvk schema.GroupVersionKind) bool {
|
||||
return ot.registered[gvk]
|
||||
}
|
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package dynamic
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
func TestDiscoveryRESTMapper(t *testing.T) {
|
||||
resources := []*metav1.APIResourceList{
|
||||
{
|
||||
GroupVersion: "test/beta1",
|
||||
APIResources: []metav1.APIResource{
|
||||
{
|
||||
Name: "test_kinds",
|
||||
Namespaced: true,
|
||||
Kind: "test_kind",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
gvk := schema.GroupVersionKind{
|
||||
Group: "test",
|
||||
Version: "beta1",
|
||||
Kind: "test_kind",
|
||||
}
|
||||
|
||||
mapper, err := NewDiscoveryRESTMapper(resources, VersionInterfaces)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error creating mapper: %s", err)
|
||||
}
|
||||
|
||||
for _, res := range []schema.GroupVersionResource{
|
||||
{
|
||||
Group: "test",
|
||||
Version: "beta1",
|
||||
Resource: "test_kinds",
|
||||
},
|
||||
{
|
||||
Version: "beta1",
|
||||
Resource: "test_kinds",
|
||||
},
|
||||
{
|
||||
Group: "test",
|
||||
Resource: "test_kinds",
|
||||
},
|
||||
{
|
||||
Resource: "test_kinds",
|
||||
},
|
||||
} {
|
||||
got, err := mapper.KindFor(res)
|
||||
if err != nil {
|
||||
t.Errorf("KindFor(%#v) unexpected error: %s", res, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if got != gvk {
|
||||
t.Errorf("KindFor(%#v) = %#v; want %#v", res, got, gvk)
|
||||
}
|
||||
}
|
||||
}
|
@@ -19,7 +19,6 @@ go_library(
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/client/typed/dynamic:go_default_library",
|
||||
"//pkg/controller/garbagecollector/metaonly:go_default_library",
|
||||
"//pkg/util/metrics:go_default_library",
|
||||
"//pkg/util/workqueue:go_default_library",
|
||||
@@ -38,6 +37,7 @@ go_library(
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/sets",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/wait",
|
||||
"//vendor:k8s.io/apimachinery/pkg/watch",
|
||||
"//vendor:k8s.io/client-go/dynamic",
|
||||
"//vendor:k8s.io/client-go/tools/cache",
|
||||
"//vendor:k8s.io/client-go/util/clock",
|
||||
],
|
||||
@@ -52,7 +52,6 @@ go_test(
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/install:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/client/typed/dynamic:go_default_library",
|
||||
"//pkg/controller/garbagecollector/metaonly:go_default_library",
|
||||
"//pkg/util/workqueue:go_default_library",
|
||||
"//vendor:github.com/stretchr/testify/assert",
|
||||
@@ -62,6 +61,7 @@ go_test(
|
||||
"//vendor:k8s.io/apimachinery/pkg/types",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/json",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/sets",
|
||||
"//vendor:k8s.io/client-go/dynamic",
|
||||
"//vendor:k8s.io/client-go/rest",
|
||||
"//vendor:k8s.io/client-go/util/clock",
|
||||
],
|
||||
|
@@ -35,10 +35,10 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/util/clock"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
||||
"k8s.io/kubernetes/pkg/controller/garbagecollector/metaonly"
|
||||
"k8s.io/kubernetes/pkg/util/workqueue"
|
||||
)
|
||||
|
@@ -33,11 +33,11 @@ import (
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/json"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/client-go/dynamic"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/util/clock"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
||||
"k8s.io/kubernetes/pkg/controller/garbagecollector/metaonly"
|
||||
"k8s.io/kubernetes/pkg/util/workqueue"
|
||||
)
|
||||
|
@@ -22,7 +22,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/kubernetes/pkg/util/metrics"
|
||||
)
|
||||
|
||||
|
@@ -19,8 +19,6 @@ go_library(
|
||||
deps = [
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/client/clientset_generated/clientset:go_default_library",
|
||||
"//pkg/client/typed/discovery:go_default_library",
|
||||
"//pkg/client/typed/dynamic:go_default_library",
|
||||
"//pkg/controller:go_default_library",
|
||||
"//pkg/util/metrics:go_default_library",
|
||||
"//pkg/util/workqueue:go_default_library",
|
||||
@@ -34,6 +32,8 @@ go_library(
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/sets",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/wait",
|
||||
"//vendor:k8s.io/apimachinery/pkg/watch",
|
||||
"//vendor:k8s.io/client-go/discovery",
|
||||
"//vendor:k8s.io/client-go/dynamic",
|
||||
"//vendor:k8s.io/client-go/tools/cache",
|
||||
],
|
||||
)
|
||||
@@ -49,13 +49,13 @@ go_test(
|
||||
"//pkg/client/clientset_generated/clientset:go_default_library",
|
||||
"//pkg/client/clientset_generated/clientset/fake:go_default_library",
|
||||
"//pkg/client/testing/core:go_default_library",
|
||||
"//pkg/client/typed/discovery:go_default_library",
|
||||
"//pkg/client/typed/dynamic:go_default_library",
|
||||
"//vendor:k8s.io/apimachinery/pkg/api/errors",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/sets",
|
||||
"//vendor:k8s.io/client-go/discovery",
|
||||
"//vendor:k8s.io/client-go/dynamic",
|
||||
"//vendor:k8s.io/client-go/rest",
|
||||
],
|
||||
)
|
||||
|
@@ -26,10 +26,10 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
||||
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
||||
"k8s.io/kubernetes/pkg/controller"
|
||||
"k8s.io/kubernetes/pkg/util/metrics"
|
||||
"k8s.io/kubernetes/pkg/util/workqueue"
|
||||
|
@@ -30,14 +30,14 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/client-go/discovery"
|
||||
"k8s.io/client-go/dynamic"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset/fake"
|
||||
"k8s.io/kubernetes/pkg/client/testing/core"
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
||||
)
|
||||
|
||||
func TestFinalized(t *testing.T) {
|
||||
|
@@ -28,10 +28,10 @@ import (
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/client-go/discovery"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
||||
)
|
||||
|
||||
// contentRemainingError is used to inform the caller that content is not fully removed from the namespace
|
||||
|
@@ -72,7 +72,6 @@ go_library(
|
||||
"//pkg/apis/policy:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library",
|
||||
"//pkg/client/typed/discovery:go_default_library",
|
||||
"//pkg/client/unversioned:go_default_library",
|
||||
"//pkg/client/unversioned/portforward:go_default_library",
|
||||
"//pkg/client/unversioned/remotecommand:go_default_library",
|
||||
@@ -122,6 +121,7 @@ go_library(
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/yaml",
|
||||
"//vendor:k8s.io/apimachinery/pkg/watch",
|
||||
"//vendor:k8s.io/apiserver/pkg/util/flag",
|
||||
"//vendor:k8s.io/client-go/discovery",
|
||||
"//vendor:k8s.io/client-go/rest",
|
||||
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||
],
|
||||
@@ -181,7 +181,6 @@ go_test(
|
||||
"//pkg/apis/batch:go_default_library",
|
||||
"//pkg/apis/extensions:go_default_library",
|
||||
"//pkg/apis/policy:go_default_library",
|
||||
"//pkg/client/typed/dynamic:go_default_library",
|
||||
"//pkg/kubectl:go_default_library",
|
||||
"//pkg/kubectl/cmd/testing:go_default_library",
|
||||
"//pkg/kubectl/cmd/util:go_default_library",
|
||||
@@ -202,6 +201,7 @@ go_test(
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/strategicpatch",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/wait",
|
||||
"//vendor:k8s.io/apimachinery/pkg/watch",
|
||||
"//vendor:k8s.io/client-go/dynamic",
|
||||
"//vendor:k8s.io/client-go/rest",
|
||||
"//vendor:k8s.io/client-go/rest/fake",
|
||||
"//vendor:k8s.io/client-go/rest/watch",
|
||||
|
@@ -21,9 +21,9 @@ import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
)
|
||||
|
||||
|
@@ -26,10 +26,10 @@ import (
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/dynamic"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
|
@@ -22,9 +22,9 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
)
|
||||
|
||||
|
@@ -31,11 +31,11 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/discovery"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
batchv1 "k8s.io/kubernetes/pkg/apis/batch/v1"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||
coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
conditions "k8s.io/kubernetes/pkg/client/unversioned"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
|
@@ -17,7 +17,6 @@ go_library(
|
||||
"//pkg/api/testapi:go_default_library",
|
||||
"//pkg/api/validation:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
||||
"//pkg/client/typed/discovery:go_default_library",
|
||||
"//pkg/kubectl:go_default_library",
|
||||
"//pkg/kubectl/cmd/util:go_default_library",
|
||||
"//pkg/kubectl/resource:go_default_library",
|
||||
@@ -29,6 +28,7 @@ go_library(
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime/serializer",
|
||||
"//vendor:k8s.io/client-go/discovery",
|
||||
"//vendor:k8s.io/client-go/rest",
|
||||
"//vendor:k8s.io/client-go/rest/fake",
|
||||
],
|
||||
|
@@ -30,6 +30,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/client-go/discovery"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/rest/fake"
|
||||
fedclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_internalclientset"
|
||||
@@ -37,7 +38,6 @@ import (
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
"k8s.io/kubernetes/pkg/api/validation"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
|
@@ -34,8 +34,6 @@ go_library(
|
||||
"//pkg/apis/extensions:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library",
|
||||
"//pkg/client/typed/discovery:go_default_library",
|
||||
"//pkg/client/typed/dynamic:go_default_library",
|
||||
"//pkg/client/unversioned:go_default_library",
|
||||
"//pkg/controller:go_default_library",
|
||||
"//pkg/kubectl:go_default_library",
|
||||
@@ -61,6 +59,8 @@ go_library(
|
||||
"//vendor:k8s.io/apimachinery/pkg/version",
|
||||
"//vendor:k8s.io/apimachinery/pkg/watch",
|
||||
"//vendor:k8s.io/apiserver/pkg/util/flag",
|
||||
"//vendor:k8s.io/client-go/discovery",
|
||||
"//vendor:k8s.io/client-go/dynamic",
|
||||
"//vendor:k8s.io/client-go/rest",
|
||||
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||
"//vendor:k8s.io/client-go/util/homedir",
|
||||
@@ -89,7 +89,6 @@ go_test(
|
||||
"//pkg/apis/extensions:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset/fake:go_default_library",
|
||||
"//pkg/client/testing/core:go_default_library",
|
||||
"//pkg/client/typed/discovery:go_default_library",
|
||||
"//pkg/controller:go_default_library",
|
||||
"//pkg/kubectl:go_default_library",
|
||||
"//pkg/kubectl/resource:go_default_library",
|
||||
@@ -106,6 +105,7 @@ go_test(
|
||||
"//vendor:k8s.io/apimachinery/pkg/version",
|
||||
"//vendor:k8s.io/apimachinery/pkg/watch",
|
||||
"//vendor:k8s.io/apiserver/pkg/util/flag",
|
||||
"//vendor:k8s.io/client-go/discovery",
|
||||
"//vendor:k8s.io/client-go/rest",
|
||||
"//vendor:k8s.io/client-go/rest/fake",
|
||||
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||
|
@@ -31,9 +31,9 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/version"
|
||||
"k8s.io/client-go/discovery"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
)
|
||||
|
||||
// CachedDiscoveryClient implements the functions that discovery server-supported API groups,
|
||||
|
@@ -29,9 +29,9 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/version"
|
||||
"k8s.io/client-go/discovery"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
)
|
||||
|
||||
func TestCachedDiscoveryClient_Fresh(t *testing.T) {
|
||||
|
@@ -20,12 +20,12 @@ import (
|
||||
"sync"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/discovery"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
fedclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_internalclientset"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
oldclient "k8s.io/kubernetes/pkg/client/unversioned"
|
||||
)
|
||||
|
||||
|
@@ -40,6 +40,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/json"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/discovery"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
fedclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_internalclientset"
|
||||
@@ -48,7 +49,6 @@ import (
|
||||
"k8s.io/kubernetes/pkg/api/validation"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/registry/extensions/thirdpartyresourcedata"
|
||||
|
@@ -36,6 +36,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
utilflag "k8s.io/apiserver/pkg/util/flag"
|
||||
"k8s.io/client-go/discovery"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
"k8s.io/client-go/util/homedir"
|
||||
@@ -46,7 +47,6 @@ import (
|
||||
"k8s.io/kubernetes/pkg/apis/batch"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/registry/extensions/thirdpartyresourcedata"
|
||||
|
@@ -34,6 +34,8 @@ import (
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/discovery"
|
||||
"k8s.io/client-go/dynamic"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/kubernetes/federation/apis/federation"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
@@ -41,8 +43,6 @@ import (
|
||||
"k8s.io/kubernetes/pkg/api/validation"
|
||||
"k8s.io/kubernetes/pkg/apis/batch"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
||||
client "k8s.io/kubernetes/pkg/client/unversioned"
|
||||
"k8s.io/kubernetes/pkg/controller"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
|
@@ -21,7 +21,7 @@ import (
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
"k8s.io/client-go/discovery"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
)
|
||||
|
||||
|
@@ -69,6 +69,8 @@ function save() {
|
||||
}
|
||||
|
||||
# save everything for which the staging directory is the source of truth
|
||||
save "discovery"
|
||||
save "dynamic"
|
||||
save "rest"
|
||||
save "tools/auth"
|
||||
save "tools/cache"
|
||||
@@ -93,7 +95,6 @@ mkcp "/pkg/client/record" "/pkg/client"
|
||||
mkcp "/pkg/client/testing" "/pkg/client"
|
||||
# remove this test because it imports the internal clientset
|
||||
rm "${CLIENT_REPO_TEMP}"/pkg/client/testing/core/fake_test.go
|
||||
mkcp "/pkg/client/typed" "/pkg/client"
|
||||
|
||||
mkcp "/pkg/client/unversioned/portforward" "/pkg/client/unversioned"
|
||||
|
||||
@@ -182,20 +183,16 @@ function mvfolder {
|
||||
}
|
||||
|
||||
mvfolder "pkg/client/clientset_generated/${CLIENTSET}" kubernetes
|
||||
mvfolder pkg/client/typed/discovery discovery
|
||||
mvfolder pkg/client/typed/dynamic dynamic
|
||||
mvfolder pkg/client/record tools/record
|
||||
mvfolder pkg/client/unversioned/portforward tools/portforward
|
||||
mvfolder pkg/client/testing/core testing
|
||||
mvfolder pkg/client/testing/cache tools/cache/testing
|
||||
mvfolder cmd/kubeadm/app/apis/kubeadm pkg/apis/kubeadm
|
||||
if [ "$(find "${CLIENT_REPO_TEMP}"/pkg/client -type f -name "*.go")" ]; then
|
||||
echo "${CLIENT_REPO_TEMP}/pkg/client is expected to be empty"
|
||||
exit 1
|
||||
else
|
||||
rm -r "${CLIENT_REPO_TEMP}"/pkg/client
|
||||
fi
|
||||
mvfolder federation pkg/federation
|
||||
|
||||
echo "running gofmt"
|
||||
find "${CLIENT_REPO_TEMP}" -type f -name "*.go" -print0 | xargs -0 gofmt -w
|
||||
|
@@ -50,8 +50,6 @@ go_library(
|
||||
"//pkg/client/clientset_generated/clientset/typed/rbac/v1beta1:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
||||
"//pkg/client/conditions:go_default_library",
|
||||
"//pkg/client/typed/discovery:go_default_library",
|
||||
"//pkg/client/typed/dynamic:go_default_library",
|
||||
"//pkg/client/unversioned/remotecommand:go_default_library",
|
||||
"//pkg/cloudprovider:go_default_library",
|
||||
"//pkg/cloudprovider/providers/gce:go_default_library",
|
||||
@@ -105,6 +103,8 @@ go_library(
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/validation",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/wait",
|
||||
"//vendor:k8s.io/apimachinery/pkg/watch",
|
||||
"//vendor:k8s.io/client-go/discovery",
|
||||
"//vendor:k8s.io/client-go/dynamic",
|
||||
"//vendor:k8s.io/client-go/kubernetes",
|
||||
"//vendor:k8s.io/client-go/rest",
|
||||
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||
|
@@ -32,6 +32,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/client-go/dynamic"
|
||||
staging "k8s.io/client-go/kubernetes"
|
||||
clientreporestclient "k8s.io/client-go/rest"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
@@ -39,7 +40,6 @@ import (
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
||||
"k8s.io/kubernetes/pkg/metrics"
|
||||
"k8s.io/kubernetes/pkg/util/intstr"
|
||||
testutils "k8s.io/kubernetes/test/utils"
|
||||
|
@@ -63,6 +63,8 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/uuid"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/discovery"
|
||||
"k8s.io/client-go/dynamic"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
@@ -76,8 +78,6 @@ import (
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
"k8s.io/kubernetes/pkg/client/conditions"
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
||||
gcecloud "k8s.io/kubernetes/pkg/cloudprovider/providers/gce"
|
||||
"k8s.io/kubernetes/pkg/controller"
|
||||
deploymentutil "k8s.io/kubernetes/pkg/controller/deployment/util"
|
||||
|
@@ -26,7 +26,6 @@ go_library(
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/client/clientset_generated/clientset:go_default_library",
|
||||
"//pkg/client/typed/dynamic:go_default_library",
|
||||
"//pkg/controller/namespace:go_default_library",
|
||||
"//test/e2e/framework:go_default_library",
|
||||
"//test/e2e_node/builder:go_default_library",
|
||||
@@ -38,6 +37,7 @@ go_library(
|
||||
"//vendor:github.com/golang/glog",
|
||||
"//vendor:github.com/kardianos/osext",
|
||||
"//vendor:k8s.io/apiserver/pkg/util/feature",
|
||||
"//vendor:k8s.io/client-go/dynamic",
|
||||
"//vendor:k8s.io/client-go/rest",
|
||||
],
|
||||
)
|
||||
|
@@ -19,11 +19,11 @@ package services
|
||||
import (
|
||||
"time"
|
||||
|
||||
"k8s.io/client-go/dynamic"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
||||
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
||||
namespacecontroller "k8s.io/kubernetes/pkg/controller/namespace"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
)
|
||||
|
@@ -25,12 +25,12 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/dynamic"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
||||
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
||||
"k8s.io/kubernetes/test/integration/framework"
|
||||
)
|
||||
|
||||
|
@@ -34,12 +34,12 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/client-go/discovery"
|
||||
"k8s.io/client-go/dynamic"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
||||
"k8s.io/kubernetes/pkg/controller/garbagecollector"
|
||||
"k8s.io/kubernetes/pkg/controller/garbagecollector/metaonly"
|
||||
"k8s.io/kubernetes/test/integration"
|
||||
|
19
vendor/BUILD
vendored
19
vendor/BUILD
vendored
@@ -13947,25 +13947,6 @@ go_library(
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "k8s.io/client-go/tools/cache_xtest",
|
||||
srcs = ["k8s.io/client-go/tools/cache/listwatch_test.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/testapi:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
"//vendor:k8s.io/apimachinery/pkg/fields",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||
"//vendor:k8s.io/apimachinery/pkg/watch",
|
||||
"//vendor:k8s.io/client-go/rest",
|
||||
"//vendor:k8s.io/client-go/tools/cache",
|
||||
"//vendor:k8s.io/client-go/util/testing",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "k8s.io/apimachinery/pkg/util/strategicpatch_test",
|
||||
srcs = ["k8s.io/apimachinery/pkg/util/strategicpatch/patch_test.go"],
|
||||
|
Reference in New Issue
Block a user