move dynamic and discovery clients

This commit is contained in:
deads2k
2017-01-25 14:00:30 -05:00
parent 2a4fcdf864
commit 2734f8f892
94 changed files with 106 additions and 3882 deletions

View File

@@ -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",

View File

@@ -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 {

View File

@@ -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",
],
)

View File

@@ -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.

View File

@@ -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",

View File

@@ -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 {

View File

@@ -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",
],
)

View File

@@ -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.

View File

@@ -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",

View File

@@ -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"

View File

@@ -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"

View File

@@ -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",
],
)

View File

@@ -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) {

View File

@@ -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",
)

View File

@@ -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)

View File

@@ -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",

View File

@@ -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 {

View File

@@ -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",
],
)

View File

@@ -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.

View File

@@ -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",

View File

@@ -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 {

View File

@@ -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",
],
)

View File

@@ -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.

View File

@@ -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",

View File

@@ -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 {

View File

@@ -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",
],
)

View File

@@ -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.

View File

@@ -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",
],

View File

@@ -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 (

View File

@@ -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",
],

View File

@@ -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 (

View File

@@ -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",

View File

@@ -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",
],

View File

@@ -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"

View File

@@ -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"
)

View File

@@ -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"
)

View File

@@ -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",

View File

@@ -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",

View File

@@ -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 {

View File

@@ -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",
],
)

View File

@@ -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.

View File

@@ -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",

View File

@@ -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 {

View File

@@ -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",
],
)

View File

@@ -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.

View File

@@ -1,15 +0,0 @@
reviewers:
- smarterclayton
- wojtek-t
- deads2k
- derekwaynecarr
- caesarxuchao
- nikhiljindal
- soltysh
- piosz
- hongchaodeng
- krousey
- jdef
- jessfraz
- pweil-
- goltermann

View File

@@ -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"],
)

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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"],
)

View File

@@ -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
}

View File

@@ -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...)
}

View File

@@ -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
}

View File

@@ -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{}

View File

@@ -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
}

View File

@@ -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{}

View File

@@ -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"],
)

View File

@@ -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{}

View File

@@ -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
}

View File

@@ -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)
}
}
}

View File

@@ -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]
}

View File

@@ -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)
}
}
}

View File

@@ -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",
],

View File

@@ -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"
)

View File

@@ -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"
)

View File

@@ -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"
)

View File

@@ -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",
],
)

View File

@@ -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"

View File

@@ -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) {

View File

@@ -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

View File

@@ -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",

View File

@@ -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"
)

View File

@@ -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"

View File

@@ -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"
)

View File

@@ -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"

View File

@@ -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",
],

View File

@@ -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"

View File

@@ -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",

View File

@@ -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,

View File

@@ -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) {

View File

@@ -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"
)

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"
)

View File

@@ -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

View File

@@ -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",

View File

@@ -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"

View File

@@ -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"

View File

@@ -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",
],
)

View File

@@ -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"
)

View File

@@ -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"
)

View File

@@ -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
View File

@@ -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"],