mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-26 21:17:23 +00:00
Add verb support to gc and namespace controllers
This commit is contained in:
parent
458d2b2fe4
commit
24e24fc7bb
@ -36,6 +36,8 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/api/v1"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||||
"k8s.io/kubernetes/pkg/apis/batch"
|
"k8s.io/kubernetes/pkg/apis/batch"
|
||||||
|
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
|
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
|
||||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5"
|
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5"
|
||||||
v1core "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5/typed/core/v1"
|
v1core "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5/typed/core/v1"
|
||||||
"k8s.io/kubernetes/pkg/client/leaderelection"
|
"k8s.io/kubernetes/pkg/client/leaderelection"
|
||||||
@ -393,44 +395,26 @@ func StartControllers(s *options.CMServer, rootClientBuilder, clientBuilder cont
|
|||||||
namespaceKubeClient := clientBuilder.ClientOrDie("namespace-controller")
|
namespaceKubeClient := clientBuilder.ClientOrDie("namespace-controller")
|
||||||
namespaceClientPool := dynamic.NewClientPool(rootClientBuilder.ConfigOrDie("namespace-controller"), restMapper, dynamic.LegacyAPIPathResolverFunc)
|
namespaceClientPool := dynamic.NewClientPool(rootClientBuilder.ConfigOrDie("namespace-controller"), restMapper, dynamic.LegacyAPIPathResolverFunc)
|
||||||
// TODO: consider using a list-watch + cache here rather than polling
|
// TODO: consider using a list-watch + cache here rather than polling
|
||||||
gvrFn := func() (map[schema.GroupVersionResource]struct{}, error) {
|
resources, err := namespaceKubeClient.Discovery().ServerResources()
|
||||||
resources, err := namespaceKubeClient.Discovery().ServerPreferredNamespacedResources()
|
|
||||||
if err != nil {
|
|
||||||
// best effort extraction
|
|
||||||
gvrs, _ := discovery.GroupVersionResources(resources)
|
|
||||||
return gvrs, fmt.Errorf("failed to get supported namespaced resources: %v", err)
|
|
||||||
}
|
|
||||||
gvrs, err := discovery.GroupVersionResources(resources)
|
|
||||||
if err != nil {
|
|
||||||
return gvrs, fmt.Errorf("failed to parse supported namespaced resources: %v", err)
|
|
||||||
}
|
|
||||||
return gvrs, nil
|
|
||||||
}
|
|
||||||
rsrcs, err := namespaceKubeClient.Discovery().ServerResources()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to get group version resources: %v", err)
|
return fmt.Errorf("failed to get preferred server resources: %v", err)
|
||||||
}
|
}
|
||||||
tprFound := false
|
gvrs, err := discovery.GroupVersionResources(resources)
|
||||||
searchThirdPartyResource:
|
if err != nil {
|
||||||
for _, rsrcList := range rsrcs {
|
return fmt.Errorf("failed to parse preferred server resources: %v", err)
|
||||||
for ix := range rsrcList.APIResources {
|
|
||||||
rsrc := &rsrcList.APIResources[ix]
|
|
||||||
if rsrc.Kind == "ThirdPartyResource" {
|
|
||||||
tprFound = true
|
|
||||||
break searchThirdPartyResource
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if !tprFound {
|
discoverResourcesFn := namespaceKubeClient.Discovery().ServerPreferredNamespacedResources
|
||||||
gvr, err := gvrFn()
|
if _, found := gvrs[extensions.SchemeGroupVersion.WithResource("thirdpartyresource")]; found {
|
||||||
|
// make discovery static
|
||||||
|
snapshot, err := discoverResourcesFn()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to get resources: %v", err)
|
return fmt.Errorf("failed to get server resources: %v", err)
|
||||||
}
|
}
|
||||||
gvrFn = func() (map[schema.GroupVersionResource]struct{}, error) {
|
discoverResourcesFn = func() ([]*metav1.APIResourceList, error) {
|
||||||
return gvr, nil
|
return snapshot, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
namespaceController := namespacecontroller.NewNamespaceController(namespaceKubeClient, namespaceClientPool, gvrFn, s.NamespaceSyncPeriod.Duration, v1.FinalizerKubernetes)
|
namespaceController := namespacecontroller.NewNamespaceController(namespaceKubeClient, namespaceClientPool, discoverResourcesFn, s.NamespaceSyncPeriod.Duration, v1.FinalizerKubernetes)
|
||||||
go namespaceController.Run(int(s.ConcurrentNamespaceSyncs), stop)
|
go namespaceController.Run(int(s.ConcurrentNamespaceSyncs), stop)
|
||||||
time.Sleep(wait.Jitter(s.ControllerStartInterval.Duration, ControllerStartJitter))
|
time.Sleep(wait.Jitter(s.ControllerStartInterval.Duration, ControllerStartJitter))
|
||||||
|
|
||||||
@ -567,9 +551,10 @@ searchThirdPartyResource:
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to get supported resources from server: %v", err)
|
return fmt.Errorf("failed to get supported resources from server: %v", err)
|
||||||
}
|
}
|
||||||
groupVersionResources, err := discovery.GroupVersionResources(preferredResources)
|
deletableResources := discovery.FilteredBy(discovery.SupportsAllVerbs{Verbs: []string{"delete"}}, preferredResources)
|
||||||
|
deletableGroupVersionResources, err := discovery.GroupVersionResources(deletableResources)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("Failed to parse supported resources from server: %v", err)
|
glog.Errorf("Failed to parse resources from server: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
config := rootClientBuilder.ConfigOrDie("generic-garbage-collector")
|
config := rootClientBuilder.ConfigOrDie("generic-garbage-collector")
|
||||||
@ -577,7 +562,7 @@ searchThirdPartyResource:
|
|||||||
metaOnlyClientPool := dynamic.NewClientPool(config, restMapper, dynamic.LegacyAPIPathResolverFunc)
|
metaOnlyClientPool := dynamic.NewClientPool(config, restMapper, dynamic.LegacyAPIPathResolverFunc)
|
||||||
config.ContentConfig = dynamic.ContentConfig()
|
config.ContentConfig = dynamic.ContentConfig()
|
||||||
clientPool := dynamic.NewClientPool(config, restMapper, dynamic.LegacyAPIPathResolverFunc)
|
clientPool := dynamic.NewClientPool(config, restMapper, dynamic.LegacyAPIPathResolverFunc)
|
||||||
garbageCollector, err := garbagecollector.NewGarbageCollector(metaOnlyClientPool, clientPool, restMapper, groupVersionResources)
|
garbageCollector, err := garbagecollector.NewGarbageCollector(metaOnlyClientPool, clientPool, restMapper, deletableGroupVersionResources)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("Failed to start the generic garbage collector: %v", err)
|
glog.Errorf("Failed to start the generic garbage collector: %v", err)
|
||||||
} else {
|
} else {
|
||||||
|
@ -537,7 +537,7 @@ var ignoredResources = map[schema.GroupVersionResource]struct{}{
|
|||||||
schema.GroupVersionResource{Group: "authorization.k8s.io", Version: "v1beta1", Resource: "localsubjectaccessreviews"}: {},
|
schema.GroupVersionResource{Group: "authorization.k8s.io", Version: "v1beta1", Resource: "localsubjectaccessreviews"}: {},
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGarbageCollector(metaOnlyClientPool dynamic.ClientPool, clientPool dynamic.ClientPool, mapper meta.RESTMapper, resources map[schema.GroupVersionResource]struct{}) (*GarbageCollector, error) {
|
func NewGarbageCollector(metaOnlyClientPool dynamic.ClientPool, clientPool dynamic.ClientPool, mapper meta.RESTMapper, deletableResources map[schema.GroupVersionResource]struct{}) (*GarbageCollector, error) {
|
||||||
gc := &GarbageCollector{
|
gc := &GarbageCollector{
|
||||||
metaOnlyClientPool: metaOnlyClientPool,
|
metaOnlyClientPool: metaOnlyClientPool,
|
||||||
clientPool: clientPool,
|
clientPool: clientPool,
|
||||||
@ -545,8 +545,8 @@ func NewGarbageCollector(metaOnlyClientPool dynamic.ClientPool, clientPool dynam
|
|||||||
clock: clock.RealClock{},
|
clock: clock.RealClock{},
|
||||||
dirtyQueue: workqueue.NewTimedWorkQueue(),
|
dirtyQueue: workqueue.NewTimedWorkQueue(),
|
||||||
orphanQueue: workqueue.NewTimedWorkQueue(),
|
orphanQueue: workqueue.NewTimedWorkQueue(),
|
||||||
registeredRateLimiter: NewRegisteredRateLimiter(resources),
|
registeredRateLimiter: NewRegisteredRateLimiter(deletableResources),
|
||||||
registeredRateLimiterForMonitors: NewRegisteredRateLimiter(resources),
|
registeredRateLimiterForMonitors: NewRegisteredRateLimiter(deletableResources),
|
||||||
absentOwnerCache: NewUIDCache(500),
|
absentOwnerCache: NewUIDCache(500),
|
||||||
}
|
}
|
||||||
gc.propagator = &Propagator{
|
gc.propagator = &Propagator{
|
||||||
@ -557,7 +557,7 @@ func NewGarbageCollector(metaOnlyClientPool dynamic.ClientPool, clientPool dynam
|
|||||||
},
|
},
|
||||||
gc: gc,
|
gc: gc,
|
||||||
}
|
}
|
||||||
for resource := range resources {
|
for resource := range deletableResources {
|
||||||
if _, ok := ignoredResources[resource]; ok {
|
if _, ok := ignoredResources[resource]; ok {
|
||||||
glog.V(6).Infof("ignore resource %#v", resource)
|
glog.V(6).Infof("ignore resource %#v", resource)
|
||||||
continue
|
continue
|
||||||
|
@ -49,7 +49,7 @@ func TestNewGarbageCollector(t *testing.T) {
|
|||||||
metaOnlyClientPool := dynamic.NewClientPool(config, registered.RESTMapper(), dynamic.LegacyAPIPathResolverFunc)
|
metaOnlyClientPool := dynamic.NewClientPool(config, registered.RESTMapper(), dynamic.LegacyAPIPathResolverFunc)
|
||||||
config.ContentConfig.NegotiatedSerializer = nil
|
config.ContentConfig.NegotiatedSerializer = nil
|
||||||
clientPool := dynamic.NewClientPool(config, registered.RESTMapper(), dynamic.LegacyAPIPathResolverFunc)
|
clientPool := dynamic.NewClientPool(config, registered.RESTMapper(), dynamic.LegacyAPIPathResolverFunc)
|
||||||
podResource := []schema.GroupVersionResource{{Version: "v1", Resource: "pods"}}
|
podResource := map[schema.GroupVersionResource]struct{}{schema.GroupVersionResource{Version: "v1", Resource: "pods"}: {}}
|
||||||
gc, err := NewGarbageCollector(metaOnlyClientPool, clientPool, registered.RESTMapper(), podResource)
|
gc, err := NewGarbageCollector(metaOnlyClientPool, clientPool, registered.RESTMapper(), podResource)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@ -113,7 +113,7 @@ func setupGC(t *testing.T, config *restclient.Config) *GarbageCollector {
|
|||||||
metaOnlyClientPool := dynamic.NewClientPool(config, registered.RESTMapper(), dynamic.LegacyAPIPathResolverFunc)
|
metaOnlyClientPool := dynamic.NewClientPool(config, registered.RESTMapper(), dynamic.LegacyAPIPathResolverFunc)
|
||||||
config.ContentConfig.NegotiatedSerializer = nil
|
config.ContentConfig.NegotiatedSerializer = nil
|
||||||
clientPool := dynamic.NewClientPool(config, registered.RESTMapper(), dynamic.LegacyAPIPathResolverFunc)
|
clientPool := dynamic.NewClientPool(config, registered.RESTMapper(), dynamic.LegacyAPIPathResolverFunc)
|
||||||
podResource := []schema.GroupVersionResource{{Version: "v1", Resource: "pods"}}
|
podResource := map[schema.GroupVersionResource]struct{}{schema.GroupVersionResource{Version: "v1", Resource: "pods"}: {}}
|
||||||
gc, err := NewGarbageCollector(metaOnlyClientPool, clientPool, registered.RESTMapper(), podResource)
|
gc, err := NewGarbageCollector(metaOnlyClientPool, clientPool, registered.RESTMapper(), podResource)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api/v1"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
|
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
|
||||||
"k8s.io/kubernetes/pkg/client/cache"
|
"k8s.io/kubernetes/pkg/client/cache"
|
||||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5"
|
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5"
|
||||||
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
||||||
@ -28,6 +29,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/runtime/schema"
|
"k8s.io/kubernetes/pkg/runtime/schema"
|
||||||
"k8s.io/kubernetes/pkg/util/metrics"
|
"k8s.io/kubernetes/pkg/util/metrics"
|
||||||
utilruntime "k8s.io/kubernetes/pkg/util/runtime"
|
utilruntime "k8s.io/kubernetes/pkg/util/runtime"
|
||||||
|
"k8s.io/kubernetes/pkg/util/sets"
|
||||||
"k8s.io/kubernetes/pkg/util/wait"
|
"k8s.io/kubernetes/pkg/util/wait"
|
||||||
"k8s.io/kubernetes/pkg/util/workqueue"
|
"k8s.io/kubernetes/pkg/util/workqueue"
|
||||||
"k8s.io/kubernetes/pkg/watch"
|
"k8s.io/kubernetes/pkg/watch"
|
||||||
@ -57,8 +59,8 @@ type NamespaceController struct {
|
|||||||
controller *cache.Controller
|
controller *cache.Controller
|
||||||
// namespaces that have been queued up for processing by workers
|
// namespaces that have been queued up for processing by workers
|
||||||
queue workqueue.RateLimitingInterface
|
queue workqueue.RateLimitingInterface
|
||||||
// function to list of preferred group versions and their corresponding resource set for namespace deletion
|
// function to list of preferred resources for namespace deletion
|
||||||
groupVersionResourcesFn func() (map[schema.GroupVersionResource]struct{}, error)
|
discoverResourcesFn func() ([]*metav1.APIResourceList, error)
|
||||||
// opCache is a cache to remember if a particular operation is not supported to aid dynamic client.
|
// opCache is a cache to remember if a particular operation is not supported to aid dynamic client.
|
||||||
opCache *operationNotSupportedCache
|
opCache *operationNotSupportedCache
|
||||||
// finalizerToken is the finalizer token managed by this controller
|
// finalizerToken is the finalizer token managed by this controller
|
||||||
@ -69,36 +71,55 @@ type NamespaceController struct {
|
|||||||
func NewNamespaceController(
|
func NewNamespaceController(
|
||||||
kubeClient clientset.Interface,
|
kubeClient clientset.Interface,
|
||||||
clientPool dynamic.ClientPool,
|
clientPool dynamic.ClientPool,
|
||||||
groupVersionResourcesFn func() (map[schema.GroupVersionResource]struct{}, error),
|
discoverResourcesFn func() ([]*metav1.APIResourceList, error),
|
||||||
resyncPeriod time.Duration,
|
resyncPeriod time.Duration,
|
||||||
finalizerToken v1.FinalizerName) *NamespaceController {
|
finalizerToken v1.FinalizerName) *NamespaceController {
|
||||||
|
|
||||||
// the namespace deletion code looks at the discovery document to enumerate the set of resources on the server.
|
|
||||||
// it then finds all namespaced resources, and in response to namespace deletion, will call delete on all of them.
|
|
||||||
// unfortunately, the discovery information does not include the list of supported verbs/methods. if the namespace
|
|
||||||
// controller calls LIST/DELETECOLLECTION for a resource, it will get a 405 error from the server and cache that that was the case.
|
|
||||||
// we found in practice though that some auth engines when encountering paths they don't know about may return a 50x.
|
|
||||||
// until we have verbs, we pre-populate resources that do not support list or delete for well-known apis rather than
|
|
||||||
// probing the server once in order to be told no.
|
|
||||||
opCache := &operationNotSupportedCache{
|
opCache := &operationNotSupportedCache{
|
||||||
m: make(map[operationKey]bool),
|
m: make(map[operationKey]bool),
|
||||||
}
|
}
|
||||||
ignoredGroupVersionResources := []schema.GroupVersionResource{
|
|
||||||
{Group: "", Version: "v1", Resource: "bindings"},
|
// pre-fill opCache with the discovery info
|
||||||
|
//
|
||||||
|
// TODO(sttts): get rid of opCache and http 405 logic around it and trust discovery info
|
||||||
|
resources, err := discoverResourcesFn()
|
||||||
|
if err != nil {
|
||||||
|
glog.Fatalf("Failed to get supported resources: %v", err)
|
||||||
}
|
}
|
||||||
for _, ignoredGroupVersionResource := range ignoredGroupVersionResources {
|
deletableGroupVersionResources := []schema.GroupVersionResource{}
|
||||||
opCache.setNotSupported(operationKey{op: operationDeleteCollection, gvr: ignoredGroupVersionResource})
|
for _, rl := range resources {
|
||||||
opCache.setNotSupported(operationKey{op: operationList, gvr: ignoredGroupVersionResource})
|
gv, err := schema.ParseGroupVersion(rl.GroupVersion)
|
||||||
|
if err != nil {
|
||||||
|
glog.Errorf("Failed to parse GroupVersion %q, skipping: %v", rl.GroupVersion, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, r := range rl.APIResources {
|
||||||
|
gvr := schema.GroupVersionResource{Group: gv.Group, Version: gv.Version, Resource: r.Name}
|
||||||
|
verbs := sets.NewString([]string(r.Verbs)...)
|
||||||
|
|
||||||
|
if !verbs.Has("delete") {
|
||||||
|
glog.V(6).Infof("Skipping resource %v because it cannot be deleted.", gvr)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, op := range []operation{operationList, operationDeleteCollection} {
|
||||||
|
if !verbs.Has(string(op)) {
|
||||||
|
opCache.setNotSupported(operationKey{op: op, gvr: gvr})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deletableGroupVersionResources = append(deletableGroupVersionResources, gvr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the controller so we can inject the enqueue function
|
// create the controller so we can inject the enqueue function
|
||||||
namespaceController := &NamespaceController{
|
namespaceController := &NamespaceController{
|
||||||
kubeClient: kubeClient,
|
kubeClient: kubeClient,
|
||||||
clientPool: clientPool,
|
clientPool: clientPool,
|
||||||
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "namespace"),
|
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "namespace"),
|
||||||
groupVersionResourcesFn: groupVersionResourcesFn,
|
discoverResourcesFn: discoverResourcesFn,
|
||||||
opCache: opCache,
|
opCache: opCache,
|
||||||
finalizerToken: finalizerToken,
|
finalizerToken: finalizerToken,
|
||||||
}
|
}
|
||||||
|
|
||||||
if kubeClient != nil && kubeClient.Core().RESTClient().GetRateLimiter() != nil {
|
if kubeClient != nil && kubeClient.Core().RESTClient().GetRateLimiter() != nil {
|
||||||
@ -203,7 +224,7 @@ func (nm *NamespaceController) syncNamespaceFromKey(key string) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
namespace := obj.(*v1.Namespace)
|
namespace := obj.(*v1.Namespace)
|
||||||
return syncNamespace(nm.kubeClient, nm.clientPool, nm.opCache, nm.groupVersionResourcesFn, namespace, nm.finalizerToken)
|
return syncNamespace(nm.kubeClient, nm.clientPool, nm.opCache, nm.discoverResourcesFn, namespace, nm.finalizerToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run starts observing the system with the specified number of workers.
|
// Run starts observing the system with the specified number of workers.
|
||||||
|
@ -34,6 +34,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5/fake"
|
"k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5/fake"
|
||||||
"k8s.io/kubernetes/pkg/client/restclient"
|
"k8s.io/kubernetes/pkg/client/restclient"
|
||||||
"k8s.io/kubernetes/pkg/client/testing/core"
|
"k8s.io/kubernetes/pkg/client/testing/core"
|
||||||
|
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||||
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
||||||
"k8s.io/kubernetes/pkg/runtime"
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
"k8s.io/kubernetes/pkg/runtime/schema"
|
"k8s.io/kubernetes/pkg/runtime/schema"
|
||||||
@ -113,8 +114,9 @@ func testSyncNamespaceThatIsTerminating(t *testing.T, versions *metav1.APIVersio
|
|||||||
|
|
||||||
// when doing a delete all of content, we will do a GET of a collection, and DELETE of a collection by default
|
// when doing a delete all of content, we will do a GET of a collection, and DELETE of a collection by default
|
||||||
dynamicClientActionSet := sets.NewString()
|
dynamicClientActionSet := sets.NewString()
|
||||||
groupVersionResources := testGroupVersionResources()
|
resources := testResources()
|
||||||
for _, groupVersionResource := range groupVersionResources {
|
groupVersionResources, _ := discovery.GroupVersionResources(resources)
|
||||||
|
for groupVersionResource := range groupVersionResources {
|
||||||
urlPath := path.Join([]string{
|
urlPath := path.Join([]string{
|
||||||
dynamic.LegacyAPIPathResolverFunc(schema.GroupVersionKind{Group: groupVersionResource.Group, Version: groupVersionResource.Version}),
|
dynamic.LegacyAPIPathResolverFunc(schema.GroupVersionKind{Group: groupVersionResource.Group, Version: groupVersionResource.Version}),
|
||||||
groupVersionResource.Group,
|
groupVersionResource.Group,
|
||||||
@ -170,8 +172,8 @@ func testSyncNamespaceThatIsTerminating(t *testing.T, versions *metav1.APIVersio
|
|||||||
mockClient := fake.NewSimpleClientset(testInput.testNamespace)
|
mockClient := fake.NewSimpleClientset(testInput.testNamespace)
|
||||||
clientPool := dynamic.NewClientPool(clientConfig, registered.RESTMapper(), dynamic.LegacyAPIPathResolverFunc)
|
clientPool := dynamic.NewClientPool(clientConfig, registered.RESTMapper(), dynamic.LegacyAPIPathResolverFunc)
|
||||||
|
|
||||||
fn := func() ([]schema.GroupVersionResource, error) {
|
fn := func() ([]*metav1.APIResourceList, error) {
|
||||||
return groupVersionResources, nil
|
return resources, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
err := syncNamespace(mockClient, clientPool, &operationNotSupportedCache{m: make(map[operationKey]bool)}, fn, testInput.testNamespace, v1.FinalizerKubernetes)
|
err := syncNamespace(mockClient, clientPool, &operationNotSupportedCache{m: make(map[operationKey]bool)}, fn, testInput.testNamespace, v1.FinalizerKubernetes)
|
||||||
@ -243,8 +245,8 @@ func TestSyncNamespaceThatIsActive(t *testing.T) {
|
|||||||
Phase: v1.NamespaceActive,
|
Phase: v1.NamespaceActive,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
fn := func() ([]schema.GroupVersionResource, error) {
|
fn := func() ([]*metav1.APIResourceList, error) {
|
||||||
return testGroupVersionResources(), nil
|
return testResources(), nil
|
||||||
}
|
}
|
||||||
err := syncNamespace(mockClient, nil, &operationNotSupportedCache{m: make(map[operationKey]bool)}, fn, testNamespace, v1.FinalizerKubernetes)
|
err := syncNamespace(mockClient, nil, &operationNotSupportedCache{m: make(map[operationKey]bool)}, fn, testNamespace, v1.FinalizerKubernetes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -295,11 +297,37 @@ func (f *fakeActionHandler) ServeHTTP(response http.ResponseWriter, request *htt
|
|||||||
response.Write([]byte("{\"kind\": \"List\",\"items\":null}"))
|
response.Write([]byte("{\"kind\": \"List\",\"items\":null}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// testGroupVersionResources returns a mocked up set of resources across different api groups for testing namespace controller.
|
// testResources returns a mocked up set of resources across different api groups for testing namespace controller.
|
||||||
func testGroupVersionResources() []schema.GroupVersionResource {
|
func testResources() []*metav1.APIResourceList {
|
||||||
results := []schema.GroupVersionResource{}
|
results := []*metav1.APIResourceList{
|
||||||
results = append(results, schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"})
|
{
|
||||||
results = append(results, schema.GroupVersionResource{Group: "", Version: "v1", Resource: "services"})
|
GroupVersion: "v1",
|
||||||
results = append(results, schema.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "deployments"})
|
APIResources: []metav1.APIResource{
|
||||||
|
{
|
||||||
|
Name: "pods",
|
||||||
|
Namespaced: true,
|
||||||
|
Kind: "Pod",
|
||||||
|
Verbs: []string{"get", "list", "delete", "deletecollection", "create", "update"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "services",
|
||||||
|
Namespaced: true,
|
||||||
|
Kind: "Service",
|
||||||
|
Verbs: []string{"get", "list", "delete", "deletecollection", "create", "update"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GroupVersion: "extensions/v1beta1",
|
||||||
|
APIResources: []metav1.APIResource{
|
||||||
|
{
|
||||||
|
Name: "deployments",
|
||||||
|
Namespaced: true,
|
||||||
|
Kind: "Deployment",
|
||||||
|
Verbs: []string{"get", "list", "delete", "deletecollection", "create", "update"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
return results
|
return results
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/api/v1"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
|
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
|
||||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5"
|
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5"
|
||||||
|
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||||
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
||||||
"k8s.io/kubernetes/pkg/runtime"
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
"k8s.io/kubernetes/pkg/runtime/schema"
|
"k8s.io/kubernetes/pkg/runtime/schema"
|
||||||
@ -367,7 +368,7 @@ func syncNamespace(
|
|||||||
kubeClient clientset.Interface,
|
kubeClient clientset.Interface,
|
||||||
clientPool dynamic.ClientPool,
|
clientPool dynamic.ClientPool,
|
||||||
opCache *operationNotSupportedCache,
|
opCache *operationNotSupportedCache,
|
||||||
groupVersionResourcesFn func() (map[schema.GroupVersionResource]struct{}, error),
|
discoverResourcesFn func() ([]*metav1.APIResourceList, error),
|
||||||
namespace *v1.Namespace,
|
namespace *v1.Namespace,
|
||||||
finalizerToken v1.FinalizerName,
|
finalizerToken v1.FinalizerName,
|
||||||
) error {
|
) error {
|
||||||
@ -418,7 +419,13 @@ func syncNamespace(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// there may still be content for us to remove
|
// there may still be content for us to remove
|
||||||
groupVersionResources, err := groupVersionResourcesFn()
|
resources, err := discoverResourcesFn()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// TODO(sttts): get rid of opCache and pass the verbs (especially "deletecollection") down into the deleter
|
||||||
|
deletableResources := discovery.FilteredBy(discovery.SupportsAllVerbs{Verbs: []string{"delete"}}, resources)
|
||||||
|
groupVersionResources, err := discovery.GroupVersionResources(deletableResources)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -56,8 +56,8 @@ func (n *NamespaceController) Start() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
clientPool := dynamic.NewClientPool(config, registered.RESTMapper(), dynamic.LegacyAPIPathResolverFunc)
|
clientPool := dynamic.NewClientPool(config, registered.RESTMapper(), dynamic.LegacyAPIPathResolverFunc)
|
||||||
gvrFn := client.Discovery().ServerPreferredNamespacedResources
|
discoverResourcesFn := client.Discovery().ServerPreferredNamespacedResources
|
||||||
nc := namespacecontroller.NewNamespaceController(client, clientPool, gvrFn, ncResyncPeriod, v1.FinalizerKubernetes)
|
nc := namespacecontroller.NewNamespaceController(client, clientPool, discoverResourcesFn, ncResyncPeriod, v1.FinalizerKubernetes)
|
||||||
go nc.Run(ncConcurrency, n.stopCh)
|
go nc.Run(ncConcurrency, n.stopCh)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -29,12 +29,14 @@ import (
|
|||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
dto "github.com/prometheus/client_model/go"
|
dto "github.com/prometheus/client_model/go"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/v1"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||||
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
|
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
|
||||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5"
|
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5"
|
||||||
"k8s.io/kubernetes/pkg/client/restclient"
|
"k8s.io/kubernetes/pkg/client/restclient"
|
||||||
|
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||||
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
||||||
"k8s.io/kubernetes/pkg/controller/garbagecollector"
|
"k8s.io/kubernetes/pkg/controller/garbagecollector"
|
||||||
"k8s.io/kubernetes/pkg/controller/garbagecollector/metaonly"
|
"k8s.io/kubernetes/pkg/controller/garbagecollector/metaonly"
|
||||||
@ -128,16 +130,21 @@ func setup(t *testing.T) (*httptest.Server, *garbagecollector.GarbageCollector,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error in create clientset: %v", err)
|
t.Fatalf("Error in create clientset: %v", err)
|
||||||
}
|
}
|
||||||
groupVersionResources, err := clientSet.Discovery().ServerPreferredResources()
|
preferredResources, err := clientSet.Discovery().ServerPreferredResources()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to get supported resources from server: %v", err)
|
t.Fatalf("Failed to get supported resources from server: %v", err)
|
||||||
}
|
}
|
||||||
|
deletableResources := discovery.FilteredBy(discovery.SupportsAllVerbs{Verbs: []string{"delete"}}, preferredResources)
|
||||||
|
deletableGroupVersionResources, err := discovery.GroupVersionResources(deletableResources)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to parse supported resources from server: %v", err)
|
||||||
|
}
|
||||||
config := &restclient.Config{Host: s.URL}
|
config := &restclient.Config{Host: s.URL}
|
||||||
config.ContentConfig.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: metaonly.NewMetadataCodecFactory()}
|
config.ContentConfig.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: metaonly.NewMetadataCodecFactory()}
|
||||||
metaOnlyClientPool := dynamic.NewClientPool(config, registered.RESTMapper(), dynamic.LegacyAPIPathResolverFunc)
|
metaOnlyClientPool := dynamic.NewClientPool(config, registered.RESTMapper(), dynamic.LegacyAPIPathResolverFunc)
|
||||||
config.ContentConfig.NegotiatedSerializer = nil
|
config.ContentConfig.NegotiatedSerializer = nil
|
||||||
clientPool := dynamic.NewClientPool(config, registered.RESTMapper(), dynamic.LegacyAPIPathResolverFunc)
|
clientPool := dynamic.NewClientPool(config, registered.RESTMapper(), dynamic.LegacyAPIPathResolverFunc)
|
||||||
gc, err := garbagecollector.NewGarbageCollector(metaOnlyClientPool, clientPool, registered.RESTMapper(), groupVersionResources)
|
gc, err := garbagecollector.NewGarbageCollector(metaOnlyClientPool, clientPool, registered.RESTMapper(), deletableGroupVersionResources)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create garbage collector")
|
t.Fatalf("Failed to create garbage collector")
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user