configpublisher

package
v0.2.0-alpha.1 Latest Latest
Warning

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

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

README

pkg/controller/configpublisher

Event adapter that turns the controller's TemplateRenderedEvent / ValidationCompletedEvent / deployment lifecycle into CRD writes via pkg/k8s/configpublisher.Publisher.

Overview

This is the leader-only component that publishes the rendered HAProxy configuration as observable Kubernetes CRDs (HAProxyCfg, HAProxyMapFile, HAProxyGeneralFile, HAProxyCRTListFile) plus the SSL Secrets that auxiliary files reference. It also writes per-pod deployment status back onto the published HAProxyCfg so operators can kubectl get haproxycfg <name> and see exactly which pods accepted which version.

The component subscribes only on the leader, holds short-lived per-correlation-ID state to pair TemplateRenderedEvent with the matching ValidationCompletedEvent, and runs three async worker goroutines so K8s API latency doesn't block the event loop.

Quick Start

import (
    "time"

    k8spublisher "gitlab.com/haproxy-haptic/haptic/pkg/k8s/configpublisher"
    "gitlab.com/haproxy-haptic/haptic/pkg/controller/configpublisher"
)

basePublisher := k8spublisher.NewWithListers(k8sClient, crdClient, listers, logger)

component := configpublisher.New(
    basePublisher,
    eventBus,
    logger,
    configpublisher.WithPublishInterval(5 * time.Second), // optional throttle
)
go component.Start(ctx) // blocks; subscribes only when leadership is held

WithPublishInterval enables a leading-edge refractory throttle on CRD writes — every reconciliation still pushes config to HAProxy pods through the deployer, but this throttles the etcd-side observability writes (which carry the full ~500 KB rendered config) to keep API-server pressure manageable during endpoint churn. Pass 0 (the default) for no throttling.

Event Flow

The component is leader-only: the lifecycle registry only invokes Start() once leadership is held, and Start() then subscribes (via SubscribeTypesLeaderOnly, which suppresses the "late subscriber" warning) and spins up the three worker goroutines. There is no subscription to BecameLeaderEvent itself — the leader contract drives the start, not an event handler.

Subscribed event What the component does
ConfigValidatedEvent Cache the validated config (CRD + secret resourceVersions) for upcoming publishes
TemplateRenderedEvent Cache the rendered config + aux files, keyed by correlation ID
ValidationCompletedEvent Match against the cached render; queue a publishWorkItem for the publish worker
ValidationFailedEvent Queue a validationFailedWorkItem so the failure shows up as an -invalid HAProxyCfg
DeployedConfigPublishRequest Publish, as the HAProxyCfg spec, the exact bytes the deployer just applied (deploy-driven publish path; uses a separate pending slot so a validation publish cannot coalesce it away)
ConfigAppliedToPodEvent Coalesce per-pod status updates (last-wins) and signal the status worker
HAProxyPodTerminatedEvent Same channel — clears stale per-pod status when a pod goes away
HAProxyPodsDiscoveredEvent Same channel — refreshes the known-pod set used to scope status writes
LostLeadershipEvent Clear cached configuration state (templateConfig, the per-correlation renderedConfigs map, lastPublishedChecksum). Pending work items in the publish / validation-failed / status channels are not drained here — the workers stop when the lifecycle cancels Start's context, and unprocessed items go with it.

Three Workers, Three Throttles

Worker Channel Purpose
publishWorker publishWork Publisher.PublishConfig (creates/updates the CRDs and Secrets)
validationFailedWorker validationFailedWork Publishes the failure as an invalid HAProxyCfg (suffixed -invalid) so operators can inspect what was rejected
statusWorker triggered via statusWorkTrigger; pending writes coalesce in statusWorkPending keyed by namespace/runtimeConfig/podName Per-pod deployment status updates

Each worker is a single goroutine. The publish worker enforces the leading-edge refractory throttle (when WithPublishInterval is set); the status worker reuses the same interval to throttle the (also expensive) status subresource writes.

See Also

  • pkg/k8s/configpublisher — the underlying Publisher that does the actual CRD writes
  • pkg/controller/deployer — the parallel path that pushes config to HAProxy pods (this package writes the observability artefacts; the deployer writes the live HAProxy configuration)
  • pkg/controller/eventsTemplateRenderedEvent, ValidationCompletedEvent, InstanceDeployedEvent, etc.

License

Apache-2.0 — see root LICENSE.

Documentation

Index

Constants

View Source
const (
	// ComponentName is the unique identifier for this component.
	ComponentName = "config-publisher"

	// EventBufferSize is the buffer size for the event subscription channel.
	// Large buffer to handle burst traffic during startup: ConfigPublisher makes
	// synchronous k8s API calls, so it processes events slowly compared to the
	// rate at which all-replica components publish them.
	EventBufferSize = busevents.PublishingSubscriberBuffer
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Component

type Component struct {
	*component.ReadySignal
	// contains filtered or unexported fields
}

Component is the event adapter for the config publisher. It wraps the pure Publisher component and coordinates it with the event bus.

This component caches information from multiple events (ConfigValidatedEvent, TemplateRenderedEvent) and publishes runtime config resources only after successful HAProxy validation (ValidationCompletedEvent).

Rendered configs are cached by correlation ID to ensure we match the correct TemplateRenderedEvent with its corresponding ValidationCompletedEvent, even when events from multiple reconciliation cycles are interleaved.

The component uses async workers for K8S API operations to prevent blocking the event loop. This ensures new events are processed promptly even when K8S API calls are slow.

func New

func New(
	publisher *configpublisher.Publisher,
	eventBus *busevents.EventBus,
	logger *slog.Logger,
	opts ...Option,
) *Component

New creates a new config publisher component.

func (*Component) Name

func (c *Component) Name() string

Name returns the unique identifier for this component. Implements the lifecycle.Component interface.

func (*Component) Start

func (c *Component) Start(ctx context.Context) error

Start begins the config publisher's event loop.

This method blocks until the context is cancelled or an error occurs. It subscribes to events when called (after leadership is acquired).

Parameters:

  • ctx: Context for cancellation and lifecycle management

Returns:

  • nil when context is cancelled (graceful shutdown)
  • Error only in exceptional circumstances

type Option

type Option func(*Component)

Option configures the Component.

func WithPublishInterval

func WithPublishInterval(d time.Duration) Option

WithPublishInterval sets the throttle interval for CRD publishes. During endpoint churn each reconciliation produces a new config, but writing ~500 KB to etcd every 5 s is excessive. This interval limits CRD updates while deployments to HAProxy pods (event-driven) remain unaffected. A value of 0 disables throttling (every config is published immediately).

Jump to

Keyboard shortcuts

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