Merge pull request #35227 from deads2k/controller-13-generic-infromer

Automatic merge from submit-queue

add generic shared informer backed by existing informer

Adds the ability to get an informer and lister that returns `[]runtime.Object` methods with the "normal" filtering capabilities based on a `GroupResource`. Right now, it only works on known types (and re-uses those caches for efficiency by having a different skin on the `Index`).  It should be extended in the future.

@derekwaynecarr I think this gives you the types you were looking for to avoid the ugly array copies.
pull/6/head
Kubernetes Submit Queue 2016-10-21 08:39:09 -07:00 committed by GitHub
commit 6bda989d54
3 changed files with 169 additions and 5 deletions

View File

@ -31,6 +31,7 @@ import (
"k8s.io/kubernetes/pkg/apis/policy" "k8s.io/kubernetes/pkg/apis/policy"
"k8s.io/kubernetes/pkg/apis/storage" "k8s.io/kubernetes/pkg/apis/storage"
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/runtime"
) )
// AppendFunc is used to add a matching item to whatever list the caller is using // AppendFunc is used to add a matching item to whatever list the caller is using
@ -92,6 +93,79 @@ func ListAllByNamespace(indexer Indexer, namespace string, selector labels.Selec
return nil return nil
} }
// GenericLister is a lister skin on a generic Indexer
type GenericLister interface {
// List will return all objects across namespaces
List(selector labels.Selector) (ret []runtime.Object, err error)
// Get will attempt to retrieve assuming that name==key
Get(name string) (runtime.Object, error)
// ByNamespace will give you a GenericNamespaceLister for one namespace
ByNamespace(namespace string) GenericNamespaceLister
}
// GenericNamespaceLister is a lister skin on a generic Indexer
type GenericNamespaceLister interface {
// List will return all objects in this namespace
List(selector labels.Selector) (ret []runtime.Object, err error)
// Get will attempt to retrieve by namespace and name
Get(name string) (runtime.Object, error)
}
func NewGenericLister(indexer Indexer, resource unversioned.GroupResource) GenericLister {
return &genericLister{indexer: indexer, resource: resource}
}
type genericLister struct {
indexer Indexer
resource unversioned.GroupResource
}
func (s *genericLister) List(selector labels.Selector) (ret []runtime.Object, err error) {
err = ListAll(s.indexer, selector, func(m interface{}) {
ret = append(ret, m.(runtime.Object))
})
return ret, err
}
func (s *genericLister) ByNamespace(namespace string) GenericNamespaceLister {
return &genericNamespaceLister{indexer: s.indexer, namespace: namespace, resource: s.resource}
}
func (s *genericLister) Get(name string) (runtime.Object, error) {
obj, exists, err := s.indexer.GetByKey(name)
if err != nil {
return nil, err
}
if !exists {
return nil, errors.NewNotFound(s.resource, name)
}
return obj.(runtime.Object), nil
}
type genericNamespaceLister struct {
indexer Indexer
namespace string
resource unversioned.GroupResource
}
func (s *genericNamespaceLister) List(selector labels.Selector) (ret []runtime.Object, err error) {
err = ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
ret = append(ret, m.(runtime.Object))
})
return ret, err
}
func (s *genericNamespaceLister) Get(name string) (runtime.Object, error) {
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
if err != nil {
return nil, err
}
if !exists {
return nil, errors.NewNotFound(s.resource, name)
}
return obj.(runtime.Object), nil
}
// TODO: generate these classes and methods for all resources of interest using // TODO: generate these classes and methods for all resources of interest using
// a script. Can use "go generate" once 1.4 is supported by all users. // a script. Can use "go generate" once 1.4 is supported by all users.

View File

@ -21,6 +21,7 @@ import (
"sync" "sync"
"time" "time"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/client/cache" "k8s.io/kubernetes/pkg/client/cache"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
) )
@ -31,9 +32,14 @@ type SharedInformerFactory interface {
// Start starts informers that can start AFTER the API server and controllers have started // Start starts informers that can start AFTER the API server and controllers have started
Start(stopCh <-chan struct{}) Start(stopCh <-chan struct{})
ForResource(unversioned.GroupResource) (GenericInformer, error)
// when you update these, update generic.go/ForResource, same package
Pods() PodInformer Pods() PodInformer
Nodes() NodeInformer LimitRanges() LimitRangeInformer
Namespaces() NamespaceInformer Namespaces() NamespaceInformer
Nodes() NodeInformer
PersistentVolumeClaims() PVCInformer PersistentVolumeClaims() PVCInformer
PersistentVolumes() PVInformer PersistentVolumes() PVInformer
ServiceAccounts() ServiceAccountInformer ServiceAccounts() ServiceAccountInformer
@ -42,12 +48,10 @@ type SharedInformerFactory interface {
Deployments() DeploymentInformer Deployments() DeploymentInformer
ReplicaSets() ReplicaSetInformer ReplicaSets() ReplicaSetInformer
ClusterRoles() ClusterRoleInformer
ClusterRoleBindings() ClusterRoleBindingInformer ClusterRoleBindings() ClusterRoleBindingInformer
Roles() RoleInformer ClusterRoles() ClusterRoleInformer
RoleBindings() RoleBindingInformer RoleBindings() RoleBindingInformer
Roles() RoleInformer
LimitRanges() LimitRangeInformer
StorageClasses() StorageClassInformer StorageClasses() StorageClassInformer
} }

View File

@ -0,0 +1,86 @@
/*
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 informers
import (
"fmt"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/apis/rbac"
"k8s.io/kubernetes/pkg/client/cache"
)
// GenericInformer is type of SharedIndexInformer which will locate and delegate to other
// sharedInformers based on type
type GenericInformer interface {
Informer() cache.SharedIndexInformer
Lister() cache.GenericLister
}
// ForResource gives generic access to a shared informer of the matching type
// TODO extend this to unknown resources with a client pool
func (f *sharedInformerFactory) ForResource(resource unversioned.GroupResource) (GenericInformer, error) {
switch resource {
case api.Resource("pods"):
return &genericInformer{resource: resource, informer: f.Pods().Informer()}, nil
case api.Resource("limitranges"):
return &genericInformer{resource: resource, informer: f.LimitRanges().Informer()}, nil
case api.Resource("namespaces"):
return &genericInformer{resource: resource, informer: f.Namespaces().Informer()}, nil
case api.Resource("nodes"):
return &genericInformer{resource: resource, informer: f.Nodes().Informer()}, nil
case api.Resource("persistentvolumeclaims"):
return &genericInformer{resource: resource, informer: f.PersistentVolumeClaims().Informer()}, nil
case api.Resource("persistentvolumes"):
return &genericInformer{resource: resource, informer: f.PersistentVolumes().Informer()}, nil
case api.Resource("serviceaccounts"):
return &genericInformer{resource: resource, informer: f.ServiceAccounts().Informer()}, nil
case extensions.Resource("daemonsets"):
return &genericInformer{resource: resource, informer: f.DaemonSets().Informer()}, nil
case extensions.Resource("deployments"):
return &genericInformer{resource: resource, informer: f.Deployments().Informer()}, nil
case extensions.Resource("replicasets"):
return &genericInformer{resource: resource, informer: f.ReplicaSets().Informer()}, nil
case rbac.Resource("clusterrolebindings"):
return &genericInformer{resource: resource, informer: f.ClusterRoleBindings().Informer()}, nil
case rbac.Resource("clusterroles"):
return &genericInformer{resource: resource, informer: f.ClusterRoles().Informer()}, nil
case rbac.Resource("rolebindings"):
return &genericInformer{resource: resource, informer: f.RoleBindings().Informer()}, nil
case rbac.Resource("roles"):
return &genericInformer{resource: resource, informer: f.Roles().Informer()}, nil
}
return nil, fmt.Errorf("no informer found for %v", resource)
}
type genericInformer struct {
informer cache.SharedIndexInformer
resource unversioned.GroupResource
}
func (f *genericInformer) Informer() cache.SharedIndexInformer {
return f.informer
}
func (f *genericInformer) Lister() cache.GenericLister {
return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource)
}