Skip to content

Commit

Permalink
Merge pull request kubernetes#35227 from deads2k/controller-13-generi…
Browse files Browse the repository at this point in the history
…c-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.
  • Loading branch information
Kubernetes Submit Queue authored Oct 21, 2016
2 parents 850c586 + a0a0e61 commit 6bda989
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 5 deletions.
74 changes: 74 additions & 0 deletions pkg/client/cache/listers.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"k8s.io/kubernetes/pkg/apis/policy"
"k8s.io/kubernetes/pkg/apis/storage"
"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
Expand Down Expand Up @@ -92,6 +93,79 @@ func ListAllByNamespace(indexer Indexer, namespace string, selector labels.Selec
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
// a script. Can use "go generate" once 1.4 is supported by all users.

Expand Down
14 changes: 9 additions & 5 deletions pkg/controller/informers/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"sync"
"time"

"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/client/cache"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
)
Expand All @@ -31,9 +32,14 @@ type SharedInformerFactory interface {
// Start starts informers that can start AFTER the API server and controllers have started
Start(stopCh <-chan struct{})

ForResource(unversioned.GroupResource) (GenericInformer, error)

// when you update these, update generic.go/ForResource, same package

Pods() PodInformer
Nodes() NodeInformer
LimitRanges() LimitRangeInformer
Namespaces() NamespaceInformer
Nodes() NodeInformer
PersistentVolumeClaims() PVCInformer
PersistentVolumes() PVInformer
ServiceAccounts() ServiceAccountInformer
Expand All @@ -42,12 +48,10 @@ type SharedInformerFactory interface {
Deployments() DeploymentInformer
ReplicaSets() ReplicaSetInformer

ClusterRoles() ClusterRoleInformer
ClusterRoleBindings() ClusterRoleBindingInformer
Roles() RoleInformer
ClusterRoles() ClusterRoleInformer
RoleBindings() RoleBindingInformer

LimitRanges() LimitRangeInformer
Roles() RoleInformer

StorageClasses() StorageClassInformer
}
Expand Down
86 changes: 86 additions & 0 deletions pkg/controller/informers/generic.go
Original file line number Diff line number Diff line change
@@ -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)
}

0 comments on commit 6bda989

Please sign in to comment.