informer

package
v0.7.9 Latest Latest
Warning

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

Go to latest
Published: Jul 3, 2026 License: Apache-2.0 Imports: 21 Imported by: 0

README

Informer — Developer Documentation

This directory implements Orkestra's shared informer factory: the layer between the Kubernetes API server watch stream and the per-CRD work queues.

Documents

File What it covers
01-architecture.md Factory lifecycle, event routing, how one informer per CRD is created and started
02-namespace-filter.md Three-tier namespace filtering — from cluster-scoped ListerWatcher down to reconciler safety net
03-listerwatch.md How ListerWatchers are built for typed and dynamic CRDs, Tier 1 namespace scoping

Read them in order the first time. When debugging event routing or namespace restriction, jump directly to 02-namespace-filter.md.

Documentation

Overview

pkg/informer/factory.go

pkg/informer/namespace_filter.go

NamespaceFilter — pre-enqueue namespace restriction for the informer factory.

Problem: without this, namespace guards are enforced at the reconciler level. Every event from every namespace hits the queue. Workers dequeue and no-op. Under high event volume in restricted namespaces, the queue fills with items that do no real work, creating false queue pressure.

Solution: two-tier filtering.

Tier 1 — Namespace-scoped ListerWatcher.
  When allowedNamespaces has exactly one entry, the ListerWatcher itself
  is scoped to that namespace. The informer never receives events from
  other namespaces. Cache is clean. Zero overhead.

Tier 2 — Pre-enqueue NamespaceFilter in handleEvent.
  For multiple allowed namespaces or any restricted namespaces, a
  NamespaceFilter is stored per GVK on the factory. handleEvent checks
  it before building the queue key. Items that fail the filter are
  dropped — they never enter the queue.

Tier 3 — Reconciler check.
  Remains as a safety net for race conditions where the filter map
  was not yet populated. Defense in depth.

Priority: allowedNamespaces takes precedence over restrictedNamespaces when both are declared (same semantics as the existing reconciler guard).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NamespaceFilterSummary added in v0.2.5

func NamespaceFilterSummary(f *NamespaceFilter) string

NamespaceFilterSummary returns a human-readable description of the filter for logging. Called once at informer registration, not on the hot path.

Types

type ClientProvider

type ClientProvider interface {
	For(obj runtime.Object) (GenericClient, error)
}

type Factory

type Factory struct {
	// contains filtered or unexported fields
}

All mappings key: gvk

func SharedInformerFactory

func SharedInformerFactory(
	cp ClientProvider,
	restConfig *rest.Config,
	queueRegistry *queue.QueueRegistry,
	defaultWq *queue.Workqueue,
	scheme *runtime.Scheme,
	kfg *konfig.Konfig,
) *Factory

func (*Factory) For

For creates or returns a SharedIndexInformer for the given object type. Uses the client provider to build the ListerWatcher via newListWatch. Each type gets exactly one informer — subsequent calls return the cached one. The informer is not started here — Start() starts all registered informers.

func (*Factory) ForListerWatcher

func (f *Factory) ForListerWatcher(lw cache.ListerWatcher, obj runtime.Object, ctx context.Context, opts Options) cache.SharedIndexInformer

ForListerWatcher creates or returns a SharedIndexInformer using an explicit ListerWatcher. Used for unstructured CRDs where the dynamic client provides the ListerWatcher directly, bypassing the typed client provider entirely. The scheme is never consulted — no conversion errors for unstructured types.

func (*Factory) IsMissing

func (f *Factory) IsMissing(key string) bool

IsMissing CRDs on startup

func (*Factory) IsReady

func (f *Factory) IsReady() bool

IsReady returns true if the factory has been started.

func (*Factory) Missing

func (f *Factory) Missing() map[string]*InformerEntry

Missing CRDs on startup

func (*Factory) Name

func (f *Factory) Name() string

func (*Factory) RegisterNamespaceFilter added in v0.2.5

func (f *Factory) RegisterNamespaceFilter(gvkStr string, filter *NamespaceFilter)

RegisterNamespaceFilter stores a namespace filter for a GVK on the factory. Called during CRD entry registration, before informers are started. Thread-safe — uses the factory's existing mutex.

func (*Factory) Registered

func (f *Factory) Registered() map[string]*InformerEntry

Registered CRDs

func (*Factory) RemoveMissing

func (f *Factory) RemoveMissing(gvkStr string)

RemoveMissing CRDs in between runs

func (*Factory) SetMissingOnStartup

func (f *Factory) SetMissingOnStartup(missing map[string]*InformerEntry)

SetMissing CRDs on startup

func (*Factory) Shutdown

func (f *Factory) Shutdown(ctx context.Context)

func (*Factory) Start

func (f *Factory) Start(ctx context.Context) error

Start signals readiness and starts all registered informers. Must be called exactly once — enforced by ErrFactoryAlreadyStarted.

func (*Factory) Started

func (f *Factory) Started() bool

func (*Factory) Status

func (f *Factory) Status() string

Status returns a summary of all informers and their sync state. Used by the health server /katalog endpoint.

func (*Factory) WaitForCacheSync

func (f *Factory) WaitForCacheSync(ctx context.Context) bool

WaitForCacheSync blocks until all informer caches have synced or ctx is done. It only waits on informers that were successfully created and started. Informers for missing CRDs (where ListWatch failed) should never be added to the factory, so they are naturally excluded here.

type GenericClient

type GenericClient interface {
	List(ctx context.Context, opts metav1.ListOptions) (runtime.Object, error)
	Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error)
	// ListInNamespace and WatchInNamespace scope the request to a single namespace.
	// Used by Tier 1 (namespace-scoped ListerWatcher) when IsSingleNamespace() is true.
	ListInNamespace(ctx context.Context, namespace string, opts metav1.ListOptions) (runtime.Object, error)
	WatchInNamespace(ctx context.Context, namespace string, opts metav1.ListOptions) (watch.Interface, error)
}

type InformerEntry

type InformerEntry struct {
	Informer cache.SharedIndexInformer
	Name     string
	Resync   time.Duration
	Missing  bool
	GVK      *schema.GroupVersionKind

	// Store the context and cancel function
	Ctx             context.Context    // stored context
	Cancel          context.CancelFunc // stored cancel function
	WasNeverStarted bool
}

InformerEntry holds an informer and its metadata — avoids storing a single shared opts on the factory which caused the name bug.

type NamespaceFilter added in v0.2.5

type NamespaceFilter struct {
	// AllowedNamespaces — when non-empty, only events from these namespaces
	// are enqueued. Everything else is dropped before reaching the queue.
	// Takes precedence over RestrictedNamespaces when both are set.
	AllowedNamespaces []string

	// RestrictedNamespaces — when non-empty, events from these namespaces
	// are dropped before reaching the queue. All other namespaces pass.
	RestrictedNamespaces []string
}

NamespaceFilter holds the namespace restriction configuration for one GVK. Stored on the Factory keyed by GVK string. Checked in handleEvent before the item enters the queue.

func (*NamespaceFilter) Allows added in v0.2.5

func (f *NamespaceFilter) Allows(namespace string) bool

Allows returns true when the namespace passes this filter.

Logic (mirrors the existing CheckNamespace in pkg/reconciler):

  1. If AllowedNamespaces is declared — namespace must be in the list.
  2. Else if RestrictedNamespaces is declared — namespace must NOT be in the list.
  3. Otherwise — allow all.

func (*NamespaceFilter) IsActive added in v0.2.5

func (f *NamespaceFilter) IsActive() bool

IsActive returns true when this filter has any namespace restrictions. Filters with no restrictions are no-ops and can be skipped.

func (*NamespaceFilter) IsSingleNamespace added in v0.2.5

func (f *NamespaceFilter) IsSingleNamespace() bool

IsSingleNamespace returns true when the filter allows exactly one namespace. Used to decide whether to use a namespace-scoped ListerWatcher (Tier 1).

func (*NamespaceFilter) SingleNamespace added in v0.2.5

func (f *NamespaceFilter) SingleNamespace() string

SingleNamespace returns the single allowed namespace when IsSingleNamespace is true.

type Options

type Options struct {
	Name          string
	Resync        time.Duration
	Wq            *queue.Workqueue
	LabelSelector string
	FieldSelector string
	// Namespace scopes the ListerWatcher to a single namespace (Tier 1 filter).
	// "" means cluster-scoped watch (all namespaces). Set by RegisterNamespaceFilter
	// when IsSingleNamespace() is true.
	Namespace string
}

Jump to

Keyboard shortcuts

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