typed

package
v0.9.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 18, 2023 License: Apache-2.0 Imports: 11 Imported by: 2

Documentation

Overview

Package typed converts (dynamic) kube informers, listers, and indexers into typed counterparts via generics.

It can be useful to access the informer cache of one controller from another place, so that multiple controllers in the same binary don't need to open separate connections against the kube apiserver and maintain separate caches of the same objects.

The `typed` package also provides a `Registry` that synchronizes access to shared informer factories across multiple controllers.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func IndexerListToTypedList

func IndexerListToTypedList[K runtime.Object](objs []any) []K

IndexerListToTypedList is a helper that converts a list of unstructured to a particular type.

func ObjToUnstructuredObj added in v0.9.0

func ObjToUnstructuredObj(typedObj runtime.Object) (*unstructured.Unstructured, error)

ObjToUnstructuredObj is a helper that converts a typed object to unstructured.

func UnstructuredListToTypeList

func UnstructuredListToTypeList[K runtime.Object](objs []runtime.Object) ([]K, error)

UnstructuredListToTypeList is a helper that converts a list of unstructured to a particular type.

func UnstructuredObjToTypedObj

func UnstructuredObjToTypedObj[K runtime.Object](obj runtime.Object) (K, error)

UnstructuredObjToTypedObj is a helper that converts an unstructured object to a particular type.

Types

type FactoryKey

type FactoryKey string

FactoryKey gives a name to a SharedInformerFactory. SharedInformerFactories can be instantiated against different kube apis or with different filters; the key should uniquely identify the factory in the registry.

For example, one factory might be watching all objects in a namespace, while another might be watching all objects in a cluster with a specific label.

It's a good idea to include the name of the controller doing initialization.

func NewFactoryKey

func NewFactoryKey(controllerName, clusterName, id string) FactoryKey

NewFactoryKey generates a simple FactoryKey from an id for the controller, the cluster it watches, and an extra value.

type Indexer

type Indexer[K runtime.Object] struct {
	// contains filtered or unexported fields
}

Indexer provides a generically typed interface for cache.Index It assumes the objects are unstructured.Unstructured, as you would get from a dynamic informer.

Example
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

client := fake.NewSimpleDynamicClient(runtime.NewScheme())
informerFactory := dynamicinformer.NewDynamicSharedInformerFactory(client, 0)
informerFactory.Start(ctx.Done())
informerFactory.WaitForCacheSync(ctx.Done())

indexer := NewIndexer[*corev1.Secret](informerFactory.ForResource(corev1.SchemeGroupVersion.WithResource("secrets")).Informer().GetIndexer())

secrets, _ := indexer.ByIndex("indexName", "indexValue")
fmt.Printf("%T", secrets)
Output:

[]*v1.Secret

func IndexerFor

func IndexerFor[K runtime.Object](r *Registry, key RegistryKey) *Indexer[K]

IndexerFor returns a typed Indexer from a Registry

Example
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

secretGVR := corev1.SchemeGroupVersion.WithResource("secrets")
secret := corev1.Secret{ObjectMeta: metav1.ObjectMeta{
	Namespace: "example",
	Name:      "mysecret",
	Labels: map[string]string{
		"my-controller.com/related-to": "myobjecttype",
	},
}}
scheme := runtime.NewScheme()
if err := corev1.AddToScheme(scheme); err != nil {
	panic(err)
}
client := fake.NewSimpleDynamicClient(scheme, &secret)
registry := NewRegistry()

dependentObjectKey := NewFactoryKey("my-controller", "localCluster", "dependentObjects")
informerFactory := registry.MustNewFilteredDynamicSharedInformerFactory(
	dependentObjectKey,
	client,
	0,
	metav1.NamespaceAll,
	func(options *metav1.ListOptions) {
		options.LabelSelector = "my-controller.com/related-to=myobjecttype"
	},
)

// add an index that indexes all objects with a constant value
const indexName = "ExampleIndex"
const constantIndexValue = "indexVal"
if err := informerFactory.ForResource(secretGVR).Informer().AddIndexers(map[string]cache.IndexFunc{
	indexName: func(obj interface{}) ([]string, error) {
		return []string{constantIndexValue}, nil
	},
}); err != nil {
	panic(err)
}

informerFactory.Start(ctx.Done())
informerFactory.WaitForCacheSync(ctx.Done())

dependentSecretKey := NewRegistryKey(dependentObjectKey, secretGVR)

matchingCachedSecrets, _ := IndexerFor[*corev1.Secret](registry, dependentSecretKey).ByIndex(indexName, constantIndexValue)
fmt.Printf("%T %s/%s", matchingCachedSecrets, matchingCachedSecrets[0].GetNamespace(), matchingCachedSecrets[0].GetName())
Output:

[]*v1.Secret example/mysecret

func NewIndexer

func NewIndexer[K runtime.Object](indexer cache.Indexer) *Indexer[K]

NewIndexer creates an Indexer from a cache.Indexer

func (Indexer[K]) Add

func (t Indexer[K]) Add(obj K) error

func (Indexer[K]) AddIndexers

func (t Indexer[K]) AddIndexers(newIndexers cache.Indexers) error

func (Indexer[K]) ByIndex

func (t Indexer[K]) ByIndex(indexName, indexedValue string) ([]K, error)

func (Indexer[K]) Delete

func (t Indexer[K]) Delete(obj K) error

func (Indexer[K]) Get

func (t Indexer[K]) Get(obj K) (item K, exists bool, err error)

func (Indexer[K]) GetByKey

func (t Indexer[K]) GetByKey(key string) (item interface{}, exists bool, err error)

func (Indexer[K]) GetIndexers

func (t Indexer[K]) GetIndexers() cache.Indexers

func (Indexer[K]) IndexKeys

func (t Indexer[K]) IndexKeys(indexName, indexedValue string) ([]string, error)

func (Indexer[K]) List

func (t Indexer[K]) List() []K

func (Indexer[K]) ListIndexFuncValues

func (t Indexer[K]) ListIndexFuncValues(indexName string) []string

func (Indexer[K]) ListKeys

func (t Indexer[K]) ListKeys() []string

func (Indexer[K]) Update

func (t Indexer[K]) Update(obj K) error

type Lister

type Lister[K runtime.Object] struct {
	// contains filtered or unexported fields
}

Lister provides a generically typed interface for cache.GenericLister It assumes the objects are unstructured.Unstructured, as you would get from a dynamic informer.

Example
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

client := fake.NewSimpleDynamicClient(runtime.NewScheme())
informerFactory := dynamicinformer.NewDynamicSharedInformerFactory(client, 0)
informerFactory.Start(ctx.Done())
informerFactory.WaitForCacheSync(ctx.Done())

lister := NewLister[*corev1.Secret](informerFactory.ForResource(corev1.SchemeGroupVersion.WithResource("secrets")).Lister())

secret, _ := lister.ByNamespace("example").Get("mysecret")
fmt.Printf("%T", secret)
Output:

*v1.Secret

func ListerFor

func ListerFor[K runtime.Object](r *Registry, key RegistryKey) *Lister[K]

ListerFor returns a typed Lister from a Registry

Example
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

secretGVR := corev1.SchemeGroupVersion.WithResource("secrets")
secret := corev1.Secret{ObjectMeta: metav1.ObjectMeta{
	Namespace: "example",
	Name:      "mysecret",
	Labels: map[string]string{
		"my-controller.com/related-to": "myobjecttype",
	},
}}
scheme := runtime.NewScheme()
if err := corev1.AddToScheme(scheme); err != nil {
	panic(err)
}
client := fake.NewSimpleDynamicClient(scheme, &secret)
registry := NewRegistry()

dependentObjectKey := NewFactoryKey("my-controller", "localCluster", "dependentObjects")
informerFactory := registry.MustNewFilteredDynamicSharedInformerFactory(
	dependentObjectKey,
	client,
	0,
	metav1.NamespaceAll,
	func(options *metav1.ListOptions) {
		options.LabelSelector = "my-controller.com/related-to=myobjecttype"
	},
)
informerFactory.ForResource(secretGVR)
informerFactory.Start(ctx.Done())
informerFactory.WaitForCacheSync(ctx.Done())

dependentSecretKey := NewRegistryKey(dependentObjectKey, secretGVR)

cachedSecret, _ := ListerFor[*corev1.Secret](registry, dependentSecretKey).ByNamespace("example").Get("mysecret")
fmt.Printf("%T %s/%s", cachedSecret, cachedSecret.GetNamespace(), cachedSecret.GetName())
Output:

*v1.Secret example/mysecret

func NewLister

func NewLister[K runtime.Object](lister cache.GenericLister) *Lister[K]

NewLister returns a Lister for a cache.GenericLister

func (Lister[K]) ByNamespace

func (t Lister[K]) ByNamespace(namespace string) NamespaceLister[K]

func (Lister[K]) Get

func (t Lister[K]) Get(name string) (K, error)

func (Lister[K]) List

func (t Lister[K]) List(selector labels.Selector) (ret []K, err error)

type NamespaceLister

type NamespaceLister[K runtime.Object] struct {
	// contains filtered or unexported fields
}

NamespaceLister provides a generically typed interface for cache.GenericNamespaceLister. It assumes the objects are unstructured.Unstructured, as you would get from a dynamic informer.

func (NamespaceLister[K]) Get

func (t NamespaceLister[K]) Get(name string) (K, error)

func (NamespaceLister[K]) List

func (t NamespaceLister[K]) List(selector labels.Selector) (ret []K, err error)

type Registry

type Registry struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

Registry is a threadsafe map of DynamicSharedInformerFactory By registering informer factories with the registry, handlers from other controllers can easily access the cached resources held by the informer.

Example
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

secretGVR := corev1.SchemeGroupVersion.WithResource("secrets")
secret := corev1.Secret{ObjectMeta: metav1.ObjectMeta{
	Namespace: "example",
	Name:      "mysecret",
	Labels: map[string]string{
		"my-controller.com/related-to": "myobjecttype",
	},
}}
scheme := runtime.NewScheme()
if err := corev1.AddToScheme(scheme); err != nil {
	panic(err)
}
client := fake.NewSimpleDynamicClient(scheme, &secret)
registry := NewRegistry()

dependentObjectKey := NewFactoryKey("my-controller", "localCluster", "dependentObjects")
informerFactory := registry.MustNewFilteredDynamicSharedInformerFactory(
	dependentObjectKey,
	client,
	0,
	metav1.NamespaceAll,
	func(options *metav1.ListOptions) {
		options.LabelSelector = "my-controller.com/related-to=myobjecttype"
	},
)
informerFactory.ForResource(secretGVR)
informerFactory.Start(ctx.Done())
informerFactory.WaitForCacheSync(ctx.Done())

dependentSecretKey := NewRegistryKey(dependentObjectKey, secretGVR)

// the registry can be passed around, and other controllers can get direct
// access to the cache's contents
anotherController := func(r *Registry) {
	cachedSecret, _ := r.ListerFor(dependentSecretKey).ByNamespace("example").Get("mysecret")
	fmt.Printf("%s/%s", cachedSecret.(metav1.Object).GetNamespace(), cachedSecret.(metav1.Object).GetName())
}
anotherController(registry)
Output:

example/mysecret

func NewRegistry

func NewRegistry() *Registry

NewRegistry returns a new, empty Registry

func (*Registry) Add

Add adds a factory to the registry under the given FactoryKey

func (*Registry) IndexerFor

func (r *Registry) IndexerFor(key RegistryKey) cache.Indexer

IndexerFor returns the GVR-specific Indexer from the Registry

func (*Registry) InformerFactoryFor

func (r *Registry) InformerFactoryFor(key RegistryKey) informers.GenericInformer

InformerFactoryFor returns GVR-specific InformerFactory from the Registry.

func (*Registry) InformerFor

func (r *Registry) InformerFor(key RegistryKey) cache.SharedIndexInformer

InformerFor returns the GVR-specific Informer from the Registry

func (*Registry) ListerFor

func (r *Registry) ListerFor(key RegistryKey) cache.GenericLister

ListerFor returns the GVR-specific Lister from the Registry

func (*Registry) MustNewFilteredDynamicSharedInformerFactory

func (r *Registry) MustNewFilteredDynamicSharedInformerFactory(key FactoryKey, client dynamic.Interface, defaultResync time.Duration, namespace string, tweakListOptions dynamicinformer.TweakListOptionsFunc) dynamicinformer.DynamicSharedInformerFactory

MustNewFilteredDynamicSharedInformerFactory creates a new SharedInformerFactory and registers it under the given FactoryKey. It panics if there is already an entry with that key.

func (*Registry) NewFilteredDynamicSharedInformerFactory

func (r *Registry) NewFilteredDynamicSharedInformerFactory(key FactoryKey, client dynamic.Interface, defaultResync time.Duration, namespace string, tweakListOptions dynamicinformer.TweakListOptionsFunc) (dynamicinformer.DynamicSharedInformerFactory, error)

NewFilteredDynamicSharedInformerFactory creates a new SharedInformerFactory and registers it under the given FactoryKey

func (*Registry) Remove added in v0.2.0

func (r *Registry) Remove(key FactoryKey)

Remove removes a factory from the registry. Note that it does not stop any informers that were started via the factory; they should be stopped via context cancellation.

type RegistryKey

type RegistryKey struct {
	schema.GroupVersionResource
	FactoryKey
}

RegistryKey identifies a specific GVR within a factory provided by a Registry

func NewRegistryKey

func NewRegistryKey(key FactoryKey, gvr schema.GroupVersionResource) RegistryKey

NewRegistryKey creates a RegistryKey from a FactoryKey

func (RegistryKey) String

func (k RegistryKey) String() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL