stores

package
v0.1.0-alpha.12 Latest Latest
Warning

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

Go to latest
Published: Feb 27, 2026 License: Apache-2.0 Imports: 4 Imported by: 0

Documentation

Overview

Package stores provides abstractions for accessing and composing resource stores.

Package stores provides abstractions for accessing and composing resource stores.

This package defines:

  • StoreProvider: Interface for accessing stores by name
  • RealStoreProvider: Implementation that returns actual stores
  • CompositeStoreProvider: Implementation that overlays proposed changes on real stores
  • ValidationContext: Unified container for K8s and HTTP overlays
  • OverlayStoreProvider: Implementation that applies ValidationContext overlays

These abstractions enable "what if" scenarios by allowing components to render and validate configurations with proposed changes without modifying actual state.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type CompositeStore

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

CompositeStore wraps a base store with an overlay, providing a unified view that reflects both the actual state and proposed changes.

Read operations (Get, List) return the merged view. Write operations are not supported and will return an error.

Thread Safety

CompositeStore itself is not thread-safe, but this is by design:

  • A new CompositeStore is created for each validation request (not shared across goroutines)
  • The base store must be thread-safe (k8s.Store uses sync.RWMutex internally)
  • The overlay must not be modified after construction (immutable during validation)

This design avoids synchronization overhead since each request gets its own instance.

func NewCompositeStore

func NewCompositeStore(base Store, overlay *StoreOverlay) *CompositeStore

NewCompositeStore creates a new CompositeStore.

Parameters:

  • base: The underlying store with actual state
  • overlay: The proposed changes to apply on top

func NewCompositeStoreWithKeyExtractor

func NewCompositeStoreWithKeyExtractor(base Store, overlay *StoreOverlay, keyExtractor KeyExtractor) *CompositeStore

NewCompositeStoreWithKeyExtractor creates a new CompositeStore with a key extractor.

The key extractor is needed for stores that use multi-key indexing. Without it, additions and modifications cannot be properly matched with Get() queries.

func (*CompositeStore) Add

func (s *CompositeStore) Add(_ interface{}, _ []string) error

Add is not supported on CompositeStore. CompositeStore is read-only; modifications should be made through the overlay.

func (*CompositeStore) Clear

func (s *CompositeStore) Clear() error

Clear is not supported on CompositeStore. CompositeStore is read-only; modifications should be made through the overlay.

func (*CompositeStore) Delete

func (s *CompositeStore) Delete(_ ...string) error

Delete is not supported on CompositeStore. CompositeStore is read-only; modifications should be made through the overlay.

func (*CompositeStore) Get

func (s *CompositeStore) Get(keys ...string) ([]interface{}, error)

Get returns resources matching the given keys.

The result includes:

  • Resources from the base store (excluding deletions)
  • Modifications (replacing base resources with same keys)
  • Additions that match the keys

func (*CompositeStore) List

func (s *CompositeStore) List() ([]interface{}, error)

List returns all resources from the merged view.

func (*CompositeStore) Update

func (s *CompositeStore) Update(_ interface{}, _ []string) error

Update is not supported on CompositeStore. CompositeStore is read-only; modifications should be made through the overlay.

type CompositeStoreProvider

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

CompositeStoreProvider wraps a base StoreProvider with overlays.

When GetStore is called, if an overlay exists for that store name, a CompositeStore is returned that applies the overlay on top of the base store. Otherwise, the base store is returned unchanged.

This enables "what if" scenarios: render and validate with proposed changes without modifying the actual stores.

func NewCompositeStoreProvider

func NewCompositeStoreProvider(base StoreProvider, overlays map[string]*StoreOverlay) *CompositeStoreProvider

NewCompositeStoreProvider creates a new CompositeStoreProvider.

Parameters:

  • base: The underlying store provider
  • overlays: Map of store name to overlay (proposed changes)

func (*CompositeStoreProvider) GetStore

func (p *CompositeStoreProvider) GetStore(name string) Store

GetStore returns a store for the given name.

If an overlay exists for this store, returns a CompositeStore that applies the overlay on top of the base store. Otherwise, returns the base store unchanged.

func (*CompositeStoreProvider) StoreNames

func (p *CompositeStoreProvider) StoreNames() []string

StoreNames returns the names of all available stores. This includes stores from the base provider plus any overlay-only stores.

func (*CompositeStoreProvider) Validate

func (p *CompositeStoreProvider) Validate() error

Validate checks that all overlays reference valid stores. Returns an error if any overlay references a store that doesn't exist in the base provider.

type ContentOverlay

type ContentOverlay interface {
	// IsEmpty returns true if the overlay contains no pending changes.
	IsEmpty() bool
}

ContentOverlay is a marker interface for overlay types.

Both K8s overlays (StoreOverlay) and HTTP overlays implement this interface, enabling unified handling in validation pipelines.

type GenericStoreGetter

type GenericStoreGetter interface {
	GetStore(name string) (Store, bool)
}

GenericStoreGetter is an interface for types that can provide stores by name. It matches the signature of resourcestore.Manager.GetStore().

type HTTPContentOverlay

type HTTPContentOverlay interface {
	ContentOverlay

	// GetContent returns content for the given URL.
	// Returns pending content if available, otherwise accepted content.
	GetContent(url string) (string, bool)

	// PendingURLs returns the list of URLs with pending content.
	PendingURLs() []string

	// HasPendingURL returns true if the given URL has pending content.
	HasPendingURL(url string) bool
}

HTTPContentOverlay represents HTTP content changes awaiting validation.

This interface abstracts the HTTP overlay to avoid circular imports between pkg/stores and pkg/httpstore. The httpstore.HTTPOverlay type implements this.

type KeyExtractor

type KeyExtractor func(resource interface{}) ([]string, error)

KeyExtractor extracts index keys from a resource. The keys are used to index resources in the store.

type ModCounter

type ModCounter interface {
	// ModCount returns the modification counter and whether tracking is supported.
	// The counter is incremented on every mutation (Add, Update, Delete, Clear).
	// Returns (count, true) if tracking is supported, (0, false) otherwise.
	ModCount() (uint64, bool)
}

ModCounter is an optional interface for stores that track modifications. Stores implementing this interface enable caching layers to detect changes without polling or re-processing all data.

The bool return value indicates whether modification tracking is supported. If supported=false, callers MUST NOT cache based on the returned count, as the store may change without the count changing.

type OverlayStoreProvider

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

OverlayStoreProvider applies ValidationContext overlays to a base provider.

Unlike CompositeStoreProvider which only handles K8s overlays, this provider also exposes HTTP overlay for use by the render service.

Usage:

ctx := NewValidationContext(k8sOverlays).WithHTTPOverlay(httpOverlay)
provider := NewOverlayStoreProvider(baseProvider, ctx)

// K8s stores automatically have overlays applied
store := provider.GetStore("ingress")  // Returns CompositeStore if overlay exists

// HTTP overlay is accessible for render service
httpOverlay := provider.GetHTTPOverlay()  // Returns HTTPContentOverlay

func NewOverlayStoreProvider

func NewOverlayStoreProvider(base StoreProvider, context *ValidationContext) *OverlayStoreProvider

NewOverlayStoreProvider creates a provider that applies ValidationContext overlays.

Parameters:

  • base: The underlying store provider
  • context: ValidationContext containing K8s and/or HTTP overlays

If context is nil, behaves identically to the base provider.

func (*OverlayStoreProvider) GetHTTPOverlay

func (p *OverlayStoreProvider) GetHTTPOverlay() HTTPContentOverlay

GetHTTPOverlay returns the HTTP content overlay from the ValidationContext.

Returns nil if:

  • ValidationContext is nil
  • No HTTP overlay was set

The render service uses this to determine whether to include pending HTTP content.

func (*OverlayStoreProvider) GetStore

func (p *OverlayStoreProvider) GetStore(name string) Store

GetStore returns a store for the given name.

If a K8s overlay exists for this store in the ValidationContext, returns a CompositeStore that applies the overlay on top of the base store. Otherwise, returns the base store unchanged.

func (*OverlayStoreProvider) IsValidationMode

func (p *OverlayStoreProvider) IsValidationMode() bool

IsValidationMode returns true if this provider has a non-empty ValidationContext.

This can be used by components to detect whether they're rendering for validation (with proposed changes) vs production (with actual state).

func (*OverlayStoreProvider) StoreNames

func (p *OverlayStoreProvider) StoreNames() []string

StoreNames returns the names of all available stores.

func (*OverlayStoreProvider) Validate

func (p *OverlayStoreProvider) Validate() error

Validate checks that all K8s overlays reference valid stores. Returns an error if any overlay references a store that doesn't exist in the base provider.

type ReadOnlyStoreError

type ReadOnlyStoreError struct {
	Operation string
}

ReadOnlyStoreError indicates an attempt to modify a read-only store.

func (*ReadOnlyStoreError) Error

func (e *ReadOnlyStoreError) Error() string

type RealStoreProvider

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

RealStoreProvider provides access to actual (non-overlaid) stores.

This is the default implementation used during normal reconciliation.

func NewRealStoreProvider

func NewRealStoreProvider(stores map[string]Store) *RealStoreProvider

NewRealStoreProvider creates a new RealStoreProvider with the given stores.

func (*RealStoreProvider) GetStore

func (p *RealStoreProvider) GetStore(name string) Store

GetStore returns the store for the given name.

func (*RealStoreProvider) StoreNames

func (p *RealStoreProvider) StoreNames() []string

StoreNames returns the names of all available stores.

type Store

type Store interface {
	// Get retrieves all resources matching the provided index keys.
	Get(keys ...string) ([]interface{}, error)

	// List returns all resources in the store.
	List() ([]interface{}, error)

	// Add inserts a new resource into the store with the provided index keys.
	Add(resource interface{}, keys []string) error

	// Update modifies an existing resource in the store.
	Update(resource interface{}, keys []string) error

	// Delete removes a resource from the store using its index keys.
	Delete(keys ...string) error

	// Clear removes all resources from the store.
	Clear() error
}

Store defines the interface for storing and retrieving indexed resources.

This interface mirrors pkg/k8s/Store but is defined here to maintain package independence. Go's implicit interface satisfaction means any type implementing these methods (like k8s/Store) automatically satisfies this.

type StoreOverlay

type StoreOverlay struct {
	// Additions are new resources to add to the store.
	Additions []runtime.Object

	// Modifications are existing resources with updated content.
	Modifications []runtime.Object

	// Deletions are keys identifying resources to remove.
	// Uses NamespacedName for consistent key format.
	Deletions []ktypes.NamespacedName
	// contains filtered or unexported fields
}

StoreOverlay represents proposed changes to a store.

This enables "what if" scenarios: validate configurations with proposed changes without modifying the actual store state.

Resources are pre-converted to template-friendly format (floats to ints) at construction time to avoid repeated conversion during Get()/List() calls.

func NewStoreOverlay

func NewStoreOverlay() *StoreOverlay

NewStoreOverlay creates a new empty StoreOverlay.

func NewStoreOverlayForCreate

func NewStoreOverlayForCreate(obj runtime.Object) *StoreOverlay

NewStoreOverlayForCreate creates a StoreOverlay for a CREATE operation. The resource is pre-converted to template-friendly format.

func NewStoreOverlayForDelete

func NewStoreOverlayForDelete(namespace, name string) *StoreOverlay

NewStoreOverlayForDelete creates a StoreOverlay for a DELETE operation.

func NewStoreOverlayForUpdate

func NewStoreOverlayForUpdate(obj runtime.Object) *StoreOverlay

NewStoreOverlayForUpdate creates a StoreOverlay for an UPDATE operation. The resource is pre-converted to template-friendly format.

func (*StoreOverlay) AddAddition

func (o *StoreOverlay) AddAddition(obj runtime.Object)

AddAddition adds a resource to the additions list and pre-converts it. Use this method instead of directly modifying the Additions field to ensure the pre-converted slice stays in sync.

func (*StoreOverlay) AddModification

func (o *StoreOverlay) AddModification(obj runtime.Object)

AddModification adds a resource to the modifications list and pre-converts it. Use this method instead of directly modifying the Modifications field to ensure the pre-converted slice stays in sync.

func (*StoreOverlay) IsEmpty

func (o *StoreOverlay) IsEmpty() bool

IsEmpty returns true if the overlay contains no changes.

type StoreProvider

type StoreProvider interface {
	// GetStore returns the store for the given name.
	// Returns nil if no store exists with that name.
	GetStore(name string) Store

	// StoreNames returns the names of all available stores.
	StoreNames() []string
}

StoreProvider provides access to stores by name.

This abstraction decouples consumers from how stores are obtained, enabling composition and overlaying of proposed changes.

func NewStoreProviderFromGetter

func NewStoreProviderFromGetter(getter GenericStoreGetter, storeNames []string) StoreProvider

NewStoreProviderFromGetter creates a StoreProvider from any type that can get stores by name.

This is useful for integrating with resourcestore.Manager which returns k8s/types.Store:

manager := resourcestore.NewManager(...)
provider := stores.NewStoreProviderFromGetter(manager, manager.StoreNames())

type StoreProviderFunc

type StoreProviderFunc func(name string) Store

StoreProviderFunc is a function type that implements StoreProvider. It allows wrapping a function as a StoreProvider.

func (StoreProviderFunc) GetStore

func (f StoreProviderFunc) GetStore(name string) Store

GetStore implements StoreProvider by calling the function.

func (StoreProviderFunc) StoreNames

func (f StoreProviderFunc) StoreNames() []string

StoreNames is not implemented for function providers.

type TypesStoreAdapter

type TypesStoreAdapter struct {
	// Inner is the underlying store to delegate to.
	// It must implement Get, List, Add, Update, Delete, Clear methods
	// with the same signatures as stores.Store.
	Inner interface {
		Get(keys ...string) ([]interface{}, error)
		List() ([]interface{}, error)
		Add(resource interface{}, keys []string) error
		Update(resource interface{}, keys []string) error
		Delete(keys ...string) error
		Clear() error
	}
}

TypesStoreAdapter wraps any type implementing the Store interface methods.

This adapter is needed because k8s/types.Store and stores.Store are identical interfaces defined in different packages. Go's structural typing means concrete types implement both, but interface VALUES cannot be directly assigned across package boundaries.

Example:

typesStore := someManager.GetStore("ingresses") // returns types.Store
storesStore := &TypesStoreAdapter{Inner: typesStore} // now implements stores.Store

func (*TypesStoreAdapter) Add

func (a *TypesStoreAdapter) Add(resource interface{}, keys []string) error

Add implements Store by delegating to Inner.

func (*TypesStoreAdapter) Clear

func (a *TypesStoreAdapter) Clear() error

Clear implements Store by delegating to Inner.

func (*TypesStoreAdapter) Delete

func (a *TypesStoreAdapter) Delete(keys ...string) error

Delete implements Store by delegating to Inner.

func (*TypesStoreAdapter) Get

func (a *TypesStoreAdapter) Get(keys ...string) ([]interface{}, error)

Get implements Store by delegating to Inner.

func (*TypesStoreAdapter) List

func (a *TypesStoreAdapter) List() ([]interface{}, error)

List implements Store by delegating to Inner.

func (*TypesStoreAdapter) ModCount

func (a *TypesStoreAdapter) ModCount() (uint64, bool)

ModCount implements ModCounter by delegating to Inner if it supports ModCount. Returns (0, false) if the inner store does not support modification tracking, which signals to callers that they MUST NOT cache based on the count.

func (*TypesStoreAdapter) Update

func (a *TypesStoreAdapter) Update(resource interface{}, keys []string) error

Update implements Store by delegating to Inner.

type ValidationContext

type ValidationContext struct {
	// K8sOverlays maps store names to their proposed changes.
	K8sOverlays map[string]*StoreOverlay

	// HTTPOverlay contains pending HTTP content changes.
	// Nil means no HTTP content changes to validate.
	HTTPOverlay HTTPContentOverlay
}

ValidationContext is a unified container for all overlay types.

It holds both K8s store overlays and HTTP content overlays, enabling the render pipeline to apply proposed changes transparently during validation.

Usage:

// For K8s-only validation (webhook admission)
ctx := NewValidationContext(k8sOverlays)

// For HTTP content validation
ctx := NewValidationContext(nil).WithHTTPOverlay(httpOverlay)

// For combined validation
ctx := NewValidationContext(k8sOverlays).WithHTTPOverlay(httpOverlay)

func NewValidationContext

func NewValidationContext(overlays map[string]*StoreOverlay) *ValidationContext

NewValidationContext creates a ValidationContext with K8s overlays.

Parameters:

  • overlays: Map of store name to proposed K8s changes (can be nil)

Returns a ValidationContext ready for use or further configuration.

func (*ValidationContext) HasHTTPOverlay

func (c *ValidationContext) HasHTTPOverlay() bool

HasHTTPOverlay returns true if an HTTP overlay is present.

func (*ValidationContext) HasK8sOverlays

func (c *ValidationContext) HasK8sOverlays() bool

HasK8sOverlays returns true if any K8s overlays are present.

func (*ValidationContext) IsEmpty

func (c *ValidationContext) IsEmpty() bool

IsEmpty returns true if the context contains no overlays.

A context is empty if it has no K8s overlays AND no HTTP overlay.

func (*ValidationContext) WithHTTPOverlay

func (c *ValidationContext) WithHTTPOverlay(overlay HTTPContentOverlay) *ValidationContext

WithHTTPOverlay adds an HTTP overlay to the validation context.

Returns the same ValidationContext for method chaining:

ctx := NewValidationContext(overlays).WithHTTPOverlay(httpOverlay)

Jump to

Keyboard shortcuts

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