common

package
v0.24.0 Latest Latest
Warning

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

Go to latest
Published: Jan 19, 2026 License: Apache-2.0 Imports: 20 Imported by: 0

Documentation

Overview

Package common provides base infrastructure for Sync Controllers. Sync Controllers are responsible for: - Watching CloudflareSyncState resources - Aggregating configuration from multiple sources - Debouncing rapid changes - Syncing to Cloudflare API with incremental detection - Updating SyncState status

Index

Constants

View Source
const DefaultDebounceDelay = 500 * time.Millisecond

DefaultDebounceDelay is the default delay before executing debounced operations. This allows multiple rapid changes to be coalesced into a single API call.

View Source
const PendingIDPrefix = "pending-"

PendingIDPrefix is the prefix used for Cloudflare IDs that haven't been created yet. When a SyncState is first created, the CloudflareID is set to "pending-<resource-name>" to indicate that the resource needs to be created in Cloudflare.

Variables

This section is empty.

Functions

func ComputeConfigHash

func ComputeConfigHash(config interface{}) (string, error)

ComputeConfigHash computes a SHA256 hash of the given configuration. The hash is used to detect changes and avoid unnecessary API calls. Returns a hex-encoded string of the hash.

func ComputeConfigHashDeterministic

func ComputeConfigHashDeterministic(config interface{}) (string, error)

ComputeConfigHashDeterministic computes a deterministic hash by normalizing the JSON. This handles cases where map iteration order differs.

func CreateAPIClient

func CreateAPIClient(
	ctx context.Context,
	c client.Client,
	syncState *v1alpha2.CloudflareSyncState,
) (*cf.API, error)

CreateAPIClient creates a Cloudflare API client from the credentials reference in a SyncState. This is the standard pattern used by all Sync Controllers.

func ExtractFirstSourceConfig

func ExtractFirstSourceConfig[T any](syncState *v1alpha2.CloudflareSyncState) (*T, error)

ExtractFirstSourceConfig extracts configuration from the first source in a SyncState. This is the standard pattern for 1:1 mapping resources (DNS, Gateway, Device, etc.) where each Kubernetes resource maps to exactly one Cloudflare resource.

Returns an error if: - No sources are present - JSON unmarshaling fails - Configuration is empty/nil

func FilterSourcesByKind

func FilterSourcesByKind(sources []v1alpha2.ConfigSource, kinds ...string) []v1alpha2.ConfigSource

FilterSourcesByKind returns sources matching the specified kinds.

func GeneratePendingID

func GeneratePendingID(resourceName string) string

GeneratePendingID creates a pending ID for a new resource. The resource name is appended to distinguish between multiple pending resources.

func HandleNotFoundOnUpdate

func HandleNotFoundOnUpdate(err error) bool

HandleNotFoundOnUpdate is a helper for the common pattern where an update fails because the resource was deleted externally. It returns true if the error indicates the resource was not found, allowing the caller to recreate it.

func HashChanged

func HashChanged(previous, current string) bool

HashChanged compares two hashes and returns true if they differ. An empty previous hash always indicates a change.

func IsManagedByOperator added in v0.24.0

func IsManagedByOperator(description string) bool

IsManagedByOperator checks if a description indicates operator management

func IsPendingID

func IsPendingID(cloudflareID string) bool

IsPendingID checks if the given Cloudflare ID indicates a resource that hasn't been created yet. Resources start with a pending ID and are updated with the real Cloudflare ID after successful creation.

func MustComputeHash

func MustComputeHash(config interface{}) string

MustComputeHash computes a hash, panicking on error. Only use this for known-good configurations during initialization.

func ParseSourceConfig

func ParseSourceConfig[T any](source *v1alpha2.ConfigSource) (*T, error)

ParseSourceConfig parses a source's configuration into the target struct. This is a helper for Sync Controllers to extract typed configuration.

func PredicateForResourceType

func PredicateForResourceType(resourceType v1alpha2.SyncResourceType) predicate.Predicate

PredicateForResourceType creates a predicate that filters CloudflareSyncState events by resource type. This is the standard predicate used by all Sync Controllers to ensure they only process SyncStates of their specific type.

Usage:

ctrl.NewControllerManagedBy(mgr).
    For(&v1alpha2.CloudflareSyncState{}).
    WithEventFilter(common.PredicateForResourceType(v1alpha2.SyncResourceDNSRecord)).
    Complete(r)

func RequeueAfterError

func RequeueAfterError(_ error) time.Duration

RequeueAfterError returns a requeue duration appropriate for the error type. Permanent errors get longer delays, transient errors get shorter delays.

func RequeueAfterSuccess

func RequeueAfterSuccess() time.Duration

RequeueAfterSuccess returns a requeue duration for periodic refresh. Most syncs don't need periodic refresh (they're event-driven), so this returns 0.

func RequireAccountID

func RequireAccountID(syncState *v1alpha2.CloudflareSyncState) (string, error)

RequireAccountID validates that the SyncState has an AccountID specified. This is required for account-scoped resources (Gateway, Device, Access, etc.).

func RequireZoneID

func RequireZoneID(syncState *v1alpha2.CloudflareSyncState) (string, error)

RequireZoneID validates that the SyncState has a ZoneID specified. This is required for zone-scoped resources (DNS, Ruleset, etc.).

func UpdateCloudflareID

func UpdateCloudflareID(
	ctx context.Context,
	c client.Client,
	syncState *v1alpha2.CloudflareSyncState,
	newID string,
)

UpdateCloudflareID updates the CloudflareID in the SyncState spec. This is called after successfully creating a resource in Cloudflare to record the actual ID. Errors are logged but not returned since this is a non-fatal operation that will be corrected on the next reconcile.

Types

type AggregatedEntries added in v0.24.0

type AggregatedEntries struct {
	// Entries is the list of merged entries
	Entries []Entry
	// ByOwner groups entries by their owner for efficient lookup
	ByOwner map[string][]Entry
	// SourceCount is the number of sources that contributed entries
	SourceCount int
}

AggregatedEntries contains the merged entries with ownership information

func (*AggregatedEntries) GetOwnerEntries added in v0.24.0

func (a *AggregatedEntries) GetOwnerEntries(owner v1alpha2.SourceReference) []Entry

GetOwnerEntries returns entries owned by the specified source.

func (*AggregatedEntries) RemoveOwner added in v0.24.0

func (a *AggregatedEntries) RemoveOwner(owner v1alpha2.SourceReference) []Entry

RemoveOwner returns entries without those owned by the specified source. This is used during deletion to remove only the deleted source's entries.

type AggregatedResult added in v0.24.0

type AggregatedResult[T any] struct {
	// Config is the merged configuration
	Config *T
	// SourceCount is the number of sources that contributed to this config
	SourceCount int
	// SourceRefs contains references to all contributing sources
	SourceRefs []v1alpha2.SourceReference
}

AggregatedResult wraps the aggregated configuration with metadata

type Aggregator added in v0.24.0

type Aggregator[T any] struct {
	// MergeFunc defines how to merge a source config into the aggregated result.
	// It receives the current aggregated result and a source config, and returns
	// the updated aggregated result.
	MergeFunc func(aggregated *T, source *T, sourceRef v1alpha2.SourceReference, priority int) *T

	// FinalizeFunc is called after all sources are merged to perform any
	// final processing (e.g., sorting, deduplication, adding defaults).
	// Optional - if nil, no finalization is performed.
	FinalizeFunc func(aggregated *T) *T
}

Aggregator provides common aggregation logic for Sync Controllers. It supports merging configurations from multiple sources with priority ordering.

func (*Aggregator[T]) Aggregate added in v0.24.0

func (a *Aggregator[T]) Aggregate(syncState *v1alpha2.CloudflareSyncState) (*AggregatedResult[T], error)

Aggregate merges all sources in a SyncState using the configured merge function. Sources are processed in priority order (lower priority number = higher precedence).

Algorithm: 1. Sort sources by priority (ascending) 2. Initialize empty aggregated result 3. For each source, parse config and call MergeFunc 4. Call FinalizeFunc if configured 5. Return aggregated result with metadata

func (*Aggregator[T]) AggregateWithFilter added in v0.24.0

func (a *Aggregator[T]) AggregateWithFilter(
	syncState *v1alpha2.CloudflareSyncState,
	kinds ...string,
) (*AggregatedResult[T], error)

AggregateWithFilter aggregates only sources matching the specified kinds.

type BaseSyncController

type BaseSyncController struct {
	Client    client.Client
	Debouncer *Debouncer
}

BaseSyncController provides common functionality for all Sync Controllers. Each resource type (Tunnel, DNS, Access, etc.) extends this with specific aggregation and sync logic.

func NewBaseSyncController

func NewBaseSyncController(c client.Client) *BaseSyncController

NewBaseSyncController creates a new BaseSyncController

func NewBaseSyncControllerWithDelay

func NewBaseSyncControllerWithDelay(c client.Client, delay time.Duration) *BaseSyncController

NewBaseSyncControllerWithDelay creates a BaseSyncController with custom debounce delay

func (*BaseSyncController) GetSyncState

GetSyncState retrieves a CloudflareSyncState by name

func (*BaseSyncController) SetSyncStatus

func (c *BaseSyncController) SetSyncStatus(
	ctx context.Context,
	syncState *v1alpha2.CloudflareSyncState,
	status v1alpha2.SyncStatus,
) error

SetSyncStatus updates the SyncState status to the specified state. This is a convenience method for setting just the status without result.

func (*BaseSyncController) ShouldSync

func (*BaseSyncController) ShouldSync(syncState *v1alpha2.CloudflareSyncState, newHash string) bool

ShouldSync determines if a sync is needed by comparing config hashes. Returns true if the configuration has changed since the last sync.

func (*BaseSyncController) StoreAggregatedConfig

func (*BaseSyncController) StoreAggregatedConfig(
	syncState *v1alpha2.CloudflareSyncState,
	config interface{},
) error

StoreAggregatedConfig stores the aggregated configuration in the SyncState status. This is useful for debugging and observability.

func (*BaseSyncController) UpdateSyncStatus

func (c *BaseSyncController) UpdateSyncStatus(
	ctx context.Context,
	syncState *v1alpha2.CloudflareSyncState,
	status v1alpha2.SyncStatus,
	result *SyncResult,
	syncErr error,
) error

UpdateSyncStatus updates the SyncState status with the sync result. It handles both success and error cases, setting appropriate conditions.

type Debouncer

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

Debouncer coalesces multiple events into a single operation. When an event occurs, it waits for the delay period. If another event occurs during this period, the timer resets. The operation only executes when no new events occur within the delay period.

This is useful for: - Reducing Cloudflare API calls when multiple resources change rapidly - Handling bulk operations (e.g., creating multiple Ingresses) - Avoiding rate limiting from the Cloudflare API

func NewDebouncer

func NewDebouncer(delay time.Duration) *Debouncer

NewDebouncer creates a new Debouncer with the specified delay. Use DefaultDebounceDelay for the standard 500ms delay.

func (*Debouncer) Cancel

func (d *Debouncer) Cancel(key string) bool

Cancel cancels a pending debounced operation. Returns true if an operation was cancelled, false if none was pending.

func (*Debouncer) Debounce

func (d *Debouncer) Debounce(key string, fn func())

Debounce schedules a function to be called after the delay. If called again with the same key before the delay expires, the timer is reset and only the latest function will be called.

The key should uniquely identify the operation (e.g., SyncState name).

func (*Debouncer) DebounceRequest

func (d *Debouncer) DebounceRequest(key string, req ctrl.Request, enqueue func(ctrl.Request)) bool

DebounceRequest schedules a reconciliation request after the delay. Returns true if a new debounce was scheduled, false if one was already pending.

func (*Debouncer) Flush

func (d *Debouncer) Flush()

Flush immediately executes all pending operations. This is useful during shutdown or testing.

func (*Debouncer) GetDelay

func (d *Debouncer) GetDelay() time.Duration

GetDelay returns the debounce delay duration.

func (*Debouncer) IsPending

func (d *Debouncer) IsPending(key string) bool

IsPending checks if a specific key has a pending operation.

func (*Debouncer) PendingCount

func (d *Debouncer) PendingCount() int

PendingCount returns the number of pending debounced operations.

type Entry added in v0.24.0

type Entry struct {
	// Data is the actual entry data (will be type-asserted by the caller)
	Data interface{}
	// Owner identifies the source that contributed this entry
	Owner v1alpha2.SourceReference
	// Priority from the source
	Priority int
}

Entry represents a single entry with ownership tracking

type EntryAggregator added in v0.24.0

type EntryAggregator[T any] struct {
	// ExtractEntries extracts entries from a source config
	ExtractEntries func(config *T) []Entry

	// SetEntries sets entries in the aggregated config
	SetEntries func(config *T, entries []Entry)

	// EntryKey returns a unique key for deduplication (optional)
	// If nil, no deduplication is performed
	EntryKey func(entry Entry) string
}

EntryAggregator provides aggregation for list-based configurations (e.g., split tunnel entries, ruleset rules, DNS records). It tracks ownership of each entry to support incremental deletion.

func (*EntryAggregator[T]) Aggregate added in v0.24.0

func (a *EntryAggregator[T]) Aggregate(syncState *v1alpha2.CloudflareSyncState) (*AggregatedEntries, error)

Aggregate merges entries from all sources, tracking ownership of each entry.

type OwnershipMarker added in v0.24.0

type OwnershipMarker struct {
	Kind      string
	Namespace string
	Name      string
}

OwnershipMarker provides utilities for embedding ownership information in Cloudflare resource descriptions for tracking purposes.

func NewOwnershipMarker added in v0.24.0

func NewOwnershipMarker(ref v1alpha2.SourceReference) OwnershipMarker

NewOwnershipMarker creates a marker from a SourceReference

func (OwnershipMarker) AppendToDescription added in v0.24.0

func (m OwnershipMarker) AppendToDescription(description string) string

AppendToDescription appends the ownership marker to a description

func (OwnershipMarker) IsOwnedBy added in v0.24.0

func (m OwnershipMarker) IsOwnedBy(description string) bool

IsOwnedBy checks if a description contains the ownership marker

func (OwnershipMarker) String added in v0.24.0

func (m OwnershipMarker) String() string

String returns the marker in format "managed-by:Kind/Namespace/Name"

type SettingOwnership added in v0.24.0

type SettingOwnership struct {
	// Settings maps setting key to its value and owner
	Settings map[string]SettingValue
}

SettingOwnership tracks which source owns each setting

func (*SettingOwnership) GetSettingsWithoutOwner added in v0.24.0

func (o *SettingOwnership) GetSettingsWithoutOwner(owner v1alpha2.SourceReference) map[string]interface{}

GetSettingsWithoutOwner returns settings not owned by the specified source. Used during deletion to preserve other sources' settings.

type SettingValue added in v0.24.0

type SettingValue struct {
	Value    interface{}
	Owner    v1alpha2.SourceReference
	Priority int
}

SettingValue contains a setting value with ownership

type SettingsAggregator added in v0.24.0

type SettingsAggregator[T any] struct {
	// GetSettings extracts settings map from config
	GetSettings func(config *T) map[string]interface{}

	// ApplySettings applies merged settings to config
	ApplySettings func(config *T, settings map[string]interface{})
}

SettingsAggregator provides aggregation for key-value settings where higher priority sources override lower priority ones.

func (*SettingsAggregator[T]) Aggregate added in v0.24.0

func (a *SettingsAggregator[T]) Aggregate(syncState *v1alpha2.CloudflareSyncState) (*SettingOwnership, error)

Aggregate merges settings from all sources, with higher priority sources winning.

type SyncError

type SyncError struct {
	Op      string // Operation that failed (e.g., "aggregate", "sync", "updateStatus")
	Err     error  // Underlying error
	Retries int    // Number of retries attempted
}

SyncError wraps an error with additional sync context

func (*SyncError) Error

func (e *SyncError) Error() string

func (*SyncError) Unwrap

func (e *SyncError) Unwrap() error

type SyncResult

type SyncResult struct {
	// ConfigVersion is the version returned by Cloudflare after update
	ConfigVersion int
	// ConfigHash is the hash of the synced configuration
	ConfigHash string
}

SyncResult contains the result of a successful sync operation

Jump to

Keyboard shortcuts

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