Merge pull request #45897 from ncdc/gc-require-list-watch

Automatic merge from submit-queue (batch tested with PRs 46149, 45897, 46293, 46296, 46194)

GC: update required verbs for deletable resources, allow list of ignored resources to be customized

The garbage collector controller currently needs to list, watch, get,
patch, update, and delete resources. Update the criteria for
deletable resources to reflect this.

Also allow the list of resources the garbage collector controller should
ignore to be customizable, so downstream integrators can add their own
resources to the list, if necessary.

cc @caesarxuchao @deads2k @smarterclayton @mfojtik @liggitt @sttts @kubernetes/sig-api-machinery-pr-reviews
This commit is contained in:
Kubernetes Submit Queue 2017-05-23 15:48:57 -07:00 committed by GitHub
commit 45b275d52c
9 changed files with 80 additions and 16 deletions

View File

@ -178,7 +178,7 @@ func startGarbageCollectorController(ctx ControllerContext) (bool, error) {
if err != nil { if err != nil {
return true, fmt.Errorf("failed to get supported resources from server: %v", err) return true, fmt.Errorf("failed to get supported resources from server: %v", err)
} }
deletableResources := discovery.FilteredBy(discovery.SupportsAllVerbs{Verbs: []string{"delete"}}, preferredResources) deletableResources := discovery.FilteredBy(discovery.SupportsAllVerbs{Verbs: []string{"get", "list", "watch", "patch", "update", "delete"}}, preferredResources)
deletableGroupVersionResources, err := discovery.GroupVersionResources(deletableResources) deletableGroupVersionResources, err := discovery.GroupVersionResources(deletableResources)
if err != nil { if err != nil {
return true, fmt.Errorf("Failed to parse resources from server: %v", err) return true, fmt.Errorf("Failed to parse resources from server: %v", err)
@ -189,7 +189,20 @@ func startGarbageCollectorController(ctx ControllerContext) (bool, error) {
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, deletableGroupVersionResources, ctx.InformerFactory)
ignoredResources := make(map[schema.GroupResource]struct{})
for _, r := range ctx.Options.GCIgnoredResources {
ignoredResources[schema.GroupResource{Group: r.Group, Resource: r.Resource}] = struct{}{}
}
garbageCollector, err := garbagecollector.NewGarbageCollector(
metaOnlyClientPool,
clientPool,
restMapper,
deletableGroupVersionResources,
ignoredResources,
ctx.InformerFactory,
)
if err != nil { if err != nil {
return true, fmt.Errorf("Failed to start the generic garbage collector: %v", err) return true, fmt.Errorf("Failed to start the generic garbage collector: %v", err)
} }

View File

@ -14,6 +14,7 @@ go_library(
deps = [ deps = [
"//pkg/apis/componentconfig:go_default_library", "//pkg/apis/componentconfig:go_default_library",
"//pkg/client/leaderelection:go_default_library", "//pkg/client/leaderelection:go_default_library",
"//pkg/controller/garbagecollector:go_default_library",
"//pkg/features:go_default_library", "//pkg/features:go_default_library",
"//pkg/master/ports:go_default_library", "//pkg/master/ports:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library", "//vendor/github.com/spf13/pflag:go_default_library",

View File

@ -29,6 +29,7 @@ import (
utilfeature "k8s.io/apiserver/pkg/util/feature" utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/kubernetes/pkg/apis/componentconfig" "k8s.io/kubernetes/pkg/apis/componentconfig"
"k8s.io/kubernetes/pkg/client/leaderelection" "k8s.io/kubernetes/pkg/client/leaderelection"
"k8s.io/kubernetes/pkg/controller/garbagecollector"
"k8s.io/kubernetes/pkg/master/ports" "k8s.io/kubernetes/pkg/master/ports"
// add the kubernetes feature gates // add the kubernetes feature gates
@ -47,6 +48,11 @@ type CMServer struct {
// NewCMServer creates a new CMServer with a default config. // NewCMServer creates a new CMServer with a default config.
func NewCMServer() *CMServer { func NewCMServer() *CMServer {
gcIgnoredResources := make([]componentconfig.GroupResource, 0, len(garbagecollector.DefaultIgnoredResources()))
for r := range garbagecollector.DefaultIgnoredResources() {
gcIgnoredResources = append(gcIgnoredResources, componentconfig.GroupResource{Group: r.Group, Resource: r.Resource})
}
s := CMServer{ s := CMServer{
KubeControllerManagerConfiguration: componentconfig.KubeControllerManagerConfiguration{ KubeControllerManagerConfiguration: componentconfig.KubeControllerManagerConfiguration{
Controllers: []string{"*"}, Controllers: []string{"*"},
@ -103,6 +109,7 @@ func NewCMServer() *CMServer {
ControllerStartInterval: metav1.Duration{Duration: 0 * time.Second}, ControllerStartInterval: metav1.Duration{Duration: 0 * time.Second},
EnableGarbageCollector: true, EnableGarbageCollector: true,
ConcurrentGCSyncs: 20, ConcurrentGCSyncs: 20,
GCIgnoredResources: gcIgnoredResources,
ClusterSigningCertFile: "/etc/kubernetes/ca/ca.pem", ClusterSigningCertFile: "/etc/kubernetes/ca/ca.pem",
ClusterSigningKeyFile: "/etc/kubernetes/ca/ca.key", ClusterSigningKeyFile: "/etc/kubernetes/ca/ca.key",
ReconcilerSyncLoopPeriod: metav1.Duration{Duration: 60 * time.Second}, ReconcilerSyncLoopPeriod: metav1.Duration{Duration: 60 * time.Second},

View File

@ -691,6 +691,13 @@ type LeaderElectionConfiguration struct {
ResourceLock string ResourceLock string
} }
type GroupResource struct {
// group is the group portion of the GroupResource.
Group string
// resource is the resource portion of the GroupResource.
Resource string
}
type KubeControllerManagerConfiguration struct { type KubeControllerManagerConfiguration struct {
metav1.TypeMeta metav1.TypeMeta
@ -877,6 +884,8 @@ type KubeControllerManagerConfiguration struct {
// concurrentGCSyncs is the number of garbage collector workers that are // concurrentGCSyncs is the number of garbage collector workers that are
// allowed to sync concurrently. // allowed to sync concurrently.
ConcurrentGCSyncs int32 ConcurrentGCSyncs int32
// gcIgnoredResources is the list of GroupResources that garbage collection should ignore.
GCIgnoredResources []GroupResource
// nodeEvictionRate is the number of nodes per second on which pods are deleted in case of node failure when a zone is healthy // nodeEvictionRate is the number of nodes per second on which pods are deleted in case of node failure when a zone is healthy
NodeEvictionRate float32 NodeEvictionRate float32
// secondaryNodeEvictionRate is the number of nodes per second on which pods are deleted in case of node failure when a zone is unhealty // secondaryNodeEvictionRate is the number of nodes per second on which pods are deleted in case of node failure when a zone is unhealty

View File

@ -36,6 +36,7 @@ func init() {
func RegisterDeepCopies(scheme *runtime.Scheme) error { func RegisterDeepCopies(scheme *runtime.Scheme) error {
return scheme.AddGeneratedDeepCopyFuncs( return scheme.AddGeneratedDeepCopyFuncs(
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_componentconfig_ClientConnectionConfiguration, InType: reflect.TypeOf(&ClientConnectionConfiguration{})}, conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_componentconfig_ClientConnectionConfiguration, InType: reflect.TypeOf(&ClientConnectionConfiguration{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_componentconfig_GroupResource, InType: reflect.TypeOf(&GroupResource{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_componentconfig_IPVar, InType: reflect.TypeOf(&IPVar{})}, conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_componentconfig_IPVar, InType: reflect.TypeOf(&IPVar{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_componentconfig_KubeControllerManagerConfiguration, InType: reflect.TypeOf(&KubeControllerManagerConfiguration{})}, conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_componentconfig_KubeControllerManagerConfiguration, InType: reflect.TypeOf(&KubeControllerManagerConfiguration{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_componentconfig_KubeProxyConfiguration, InType: reflect.TypeOf(&KubeProxyConfiguration{})}, conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_componentconfig_KubeProxyConfiguration, InType: reflect.TypeOf(&KubeProxyConfiguration{})},
@ -66,6 +67,16 @@ func DeepCopy_componentconfig_ClientConnectionConfiguration(in interface{}, out
} }
} }
// DeepCopy_componentconfig_GroupResource is an autogenerated deepcopy function.
func DeepCopy_componentconfig_GroupResource(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*GroupResource)
out := out.(*GroupResource)
*out = *in
return nil
}
}
// DeepCopy_componentconfig_IPVar is an autogenerated deepcopy function. // DeepCopy_componentconfig_IPVar is an autogenerated deepcopy function.
func DeepCopy_componentconfig_IPVar(in interface{}, out interface{}, c *conversion.Cloner) error { func DeepCopy_componentconfig_IPVar(in interface{}, out interface{}, c *conversion.Cloner) error {
{ {
@ -92,6 +103,11 @@ func DeepCopy_componentconfig_KubeControllerManagerConfiguration(in interface{},
*out = make([]string, len(*in)) *out = make([]string, len(*in))
copy(*out, *in) copy(*out, *in)
} }
if in.GCIgnoredResources != nil {
in, out := &in.GCIgnoredResources, &out.GCIgnoredResources
*out = make([]GroupResource, len(*in))
copy(*out, *in)
}
return nil return nil
} }
} }

View File

@ -78,6 +78,7 @@ func NewGarbageCollector(
clientPool dynamic.ClientPool, clientPool dynamic.ClientPool,
mapper meta.RESTMapper, mapper meta.RESTMapper,
deletableResources map[schema.GroupVersionResource]struct{}, deletableResources map[schema.GroupVersionResource]struct{},
ignoredResources map[schema.GroupResource]struct{},
sharedInformers informers.SharedInformerFactory, sharedInformers informers.SharedInformerFactory,
) (*GarbageCollector, error) { ) (*GarbageCollector, error) {
attemptToDelete := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "garbage_collector_attempt_to_delete") attemptToDelete := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "garbage_collector_attempt_to_delete")
@ -103,6 +104,7 @@ func NewGarbageCollector(
attemptToOrphan: attemptToOrphan, attemptToOrphan: attemptToOrphan,
absentOwnerCache: absentOwnerCache, absentOwnerCache: absentOwnerCache,
sharedInformers: sharedInformers, sharedInformers: sharedInformers,
ignoredResources: ignoredResources,
} }
if err := gb.monitorsForResources(deletableResources); err != nil { if err := gb.monitorsForResources(deletableResources); err != nil {
return nil, err return nil, err

View File

@ -60,7 +60,7 @@ func TestNewGarbageCollector(t *testing.T) {
client := fake.NewSimpleClientset() client := fake.NewSimpleClientset()
sharedInformers := informers.NewSharedInformerFactory(client, 0) sharedInformers := informers.NewSharedInformerFactory(client, 0)
gc, err := NewGarbageCollector(metaOnlyClientPool, clientPool, api.Registry.RESTMapper(), podResource, sharedInformers) gc, err := NewGarbageCollector(metaOnlyClientPool, clientPool, api.Registry.RESTMapper(), podResource, ignoredResources, sharedInformers)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -131,7 +131,7 @@ func setupGC(t *testing.T, config *restclient.Config) garbageCollector {
podResource := map[schema.GroupVersionResource]struct{}{{Version: "v1", Resource: "pods"}: {}} podResource := map[schema.GroupVersionResource]struct{}{{Version: "v1", Resource: "pods"}: {}}
client := fake.NewSimpleClientset() client := fake.NewSimpleClientset()
sharedInformers := informers.NewSharedInformerFactory(client, 0) sharedInformers := informers.NewSharedInformerFactory(client, 0)
gc, err := NewGarbageCollector(metaOnlyClientPool, clientPool, api.Registry.RESTMapper(), podResource, sharedInformers) gc, err := NewGarbageCollector(metaOnlyClientPool, clientPool, api.Registry.RESTMapper(), podResource, ignoredResources, sharedInformers)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -94,6 +94,7 @@ type GraphBuilder struct {
absentOwnerCache *UIDCache absentOwnerCache *UIDCache
sharedInformers informers.SharedInformerFactory sharedInformers informers.SharedInformerFactory
stopCh <-chan struct{} stopCh <-chan struct{}
ignoredResources map[schema.GroupResource]struct{}
} }
func listWatcher(client *dynamic.Client, resource schema.GroupVersionResource) *cache.ListWatch { func listWatcher(client *dynamic.Client, resource schema.GroupVersionResource) *cache.ListWatch {
@ -193,7 +194,7 @@ func (gb *GraphBuilder) controllerFor(resource schema.GroupVersionResource, kind
func (gb *GraphBuilder) monitorsForResources(resources map[schema.GroupVersionResource]struct{}) error { func (gb *GraphBuilder) monitorsForResources(resources map[schema.GroupVersionResource]struct{}) error {
for resource := range resources { for resource := range resources {
if _, ok := ignoredResources[resource]; ok { if _, ok := gb.ignoredResources[resource.GroupResource()]; ok {
glog.V(5).Infof("ignore resource %#v", resource) glog.V(5).Infof("ignore resource %#v", resource)
continue continue
} }
@ -231,16 +232,24 @@ func (gb *GraphBuilder) Run(stopCh <-chan struct{}) {
gb.stopCh = stopCh gb.stopCh = stopCh
} }
var ignoredResources = map[schema.GroupVersionResource]struct{}{ var ignoredResources = map[schema.GroupResource]struct{}{
{Group: "extensions", Version: "v1beta1", Resource: "replicationcontrollers"}: {}, {Group: "extensions", Resource: "replicationcontrollers"}: {},
{Group: "", Version: "v1", Resource: "bindings"}: {}, {Group: "", Resource: "bindings"}: {},
{Group: "", Version: "v1", Resource: "componentstatuses"}: {}, {Group: "", Resource: "componentstatuses"}: {},
{Group: "", Version: "v1", Resource: "events"}: {}, {Group: "", Resource: "events"}: {},
{Group: "authentication.k8s.io", Version: "v1beta1", Resource: "tokenreviews"}: {}, {Group: "authentication.k8s.io", Resource: "tokenreviews"}: {},
{Group: "authorization.k8s.io", Version: "v1beta1", Resource: "subjectaccessreviews"}: {}, {Group: "authorization.k8s.io", Resource: "subjectaccessreviews"}: {},
{Group: "authorization.k8s.io", Version: "v1beta1", Resource: "selfsubjectaccessreviews"}: {}, {Group: "authorization.k8s.io", Resource: "selfsubjectaccessreviews"}: {},
{Group: "authorization.k8s.io", Version: "v1beta1", Resource: "localsubjectaccessreviews"}: {}, {Group: "authorization.k8s.io", Resource: "localsubjectaccessreviews"}: {},
{Group: "apiregistration.k8s.io", Version: "v1beta1", Resource: "apiservices"}: {}, {Group: "apiregistration.k8s.io", Resource: "apiservices"}: {},
{Group: "apiextensions.k8s.io", Resource: "customresourcedefinitions"}: {},
}
// DefaultIgnoredResources returns the default set of resources that the garbage collector controller
// should ignore. This is exposed so downstream integrators can have access to the defaults, and add
// to them as necessary when constructing the controller.
func DefaultIgnoredResources() map[schema.GroupResource]struct{} {
return ignoredResources
} }
func (gb *GraphBuilder) enqueueChanges(e *event) { func (gb *GraphBuilder) enqueueChanges(e *event) {

View File

@ -148,7 +148,14 @@ func setup(t *testing.T, stop chan struct{}) (*httptest.Server, framework.CloseF
config.ContentConfig.NegotiatedSerializer = nil config.ContentConfig.NegotiatedSerializer = nil
clientPool := dynamic.NewClientPool(config, api.Registry.RESTMapper(), dynamic.LegacyAPIPathResolverFunc) clientPool := dynamic.NewClientPool(config, api.Registry.RESTMapper(), dynamic.LegacyAPIPathResolverFunc)
sharedInformers := informers.NewSharedInformerFactory(clientSet, 0) sharedInformers := informers.NewSharedInformerFactory(clientSet, 0)
gc, err := garbagecollector.NewGarbageCollector(metaOnlyClientPool, clientPool, api.Registry.RESTMapper(), deletableGroupVersionResources, sharedInformers) gc, err := garbagecollector.NewGarbageCollector(
metaOnlyClientPool,
clientPool,
api.Registry.RESTMapper(),
deletableGroupVersionResources,
garbagecollector.DefaultIgnoredResources(),
sharedInformers,
)
if err != nil { if err != nil {
t.Fatalf("Failed to create garbage collector") t.Fatalf("Failed to create garbage collector")
} }