function

package
v0.6.0 Latest Latest
Warning

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

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

Documentation

Overview

Package function is the Function lifecycle reconciler (ADR-0020): the one controller.Reconciler for KindFunction. It stamps immutable Revisions, schedules + provisions workers via the runtime port to the EFFECTIVE desired replica count (honoring the activator's wake Status.Phase, not blindly spec.replicas), validates the shape (materialization gate — no route to a broken function), programs the gateway with the FULL route table (gateway.ProgramRoutes is replace-all), and writes status. It also provides the production activator.Endpoints (the seam ADR-0016 deferred to P-M).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ArtifactResolver

type ArtifactResolver interface {
	Resolve(ctx context.Context, uri string) (digest string, err error)
}

ArtifactResolver resolves an OCI artifact ref (tag) to its digest (ADR-0035), so the reconciler can pin it into the immutable Revision at stamp time instead of the user typing it. The oras driver implements it; the file driver needs none (file:// has no digest). Optional in Deps: nil → no resolution (file/legacy mode).

type CatalogProxies added in v0.4.0

type CatalogProxies interface {
	ProxyURL(ns v1.NamespaceName, name v1.ObjectName) (string, bool)
}

CatalogProxies reports the URL of a CatalogService's PEP proxy listener bound in this daemon run (ADR-0137, ADR-0162), false when none is bound. Satisfied by *cataloggw.Manager.

type Deps

type Deps struct {
	Store     store.Store
	Runtime   runtime.Runtime
	Scheduler scheduler.Scheduler
	Gateway   gateway.Gateway
	Validator ShapeValidator
	Logger    *slog.Logger
	// LogMaxRecordBytes is FUNCD_FUNCLOG_MAX_RECORD_BYTES for every shim and pool host (ADR-0168); 0 sets none.
	LogMaxRecordBytes int
	// Materializer + ShimCommand enable real function execution (ADR-0030): the
	// reconciler materializes the artifact and launches the runtime shim, and gates
	// readiness on the shim's /health/readiness. When Materializer is nil the reconciler
	// runs the legacy long-lived placeholder (ADR-0020) — used by the runtime-port tests.
	Materializer Materializer
	ShimCommand  []string // launch prefix for the DEFAULT shim, e.g. ["node", "/.../shim.mjs"]
	// ShimCommandsByFamily maps a runtime-family prefix → its shim launch prefix (ADR-0049): a
	// function whose spec.runtime starts with the key (e.g. "python") is launched with that
	// command instead of ShimCommand. Empty ⇒ every runtime uses the default ShimCommand (node).
	ShimCommandsByFamily map[string][]string

	// Resolver (ADR-0035) resolves an OCI artifact ref → digest at Revision-stamp time, so
	// the user need not pin the digest. nil → no resolution (file:// dev / legacy mode).
	Resolver ArtifactResolver
	// Platforms (ADR-0145) lists an artifact digest's platforms for the placement gate. nil → no gate.
	Platforms PlatformResolver

	// EndpointMode + ImageFor select container execution (ADR-0032). EndpointLoopback
	// (default) is the process driver: ShimCommand launches the shim, loopback+portfile.
	// EndpointNetnsFixedPort is the containerd driver: the shim is the curated IMAGE's
	// entrypoint (Command empty), the artifact is bind-mounted, and it binds a fixed port
	// on the netns IP. ImageFor maps fn.Spec.Runtime → the curated image ref.
	EndpointMode EndpointMode
	ImageFor     func(runtime string) string

	// PoolShimCommand enables worker pooling (ADR-0046): the launch prefix for the pooled
	// worker_threads host (e.g. ["node", "/.../pool.mjs"]). When set, a function declaring
	// spec.pooling.worker co-locates with same-key peers in one pool worker launched with
	// this command + FUNCD_POOL_MANIFEST. Empty ⇒ pooling is off (every function is solo).
	PoolShimCommand []string
	// PoolShimsByFamily maps a runtime-family prefix → its pool-host launch prefix (ADR-0050): a
	// python* function that opts in co-pools via this host (the subinterpreter pool.py) instead of
	// staying solo. Empty ⇒ only PoolShimCommand (node) pools; a family with no host runs solo.
	PoolShimsByFamily map[string][]string
	// PoolLimit caps handlers per pool worker (ADR-0046 Decision 3); 0 ⇒ the default (16).
	PoolLimit int
	// PoolManifestDir holds the pool workers' manifests, which carry member credentials: a 0700 dir funcd owns,
	// emptied by NewReconciler. Empty ⇒ a private temp dir NewReconciler creates and Close removes.
	PoolManifestDir string

	// Secrets resolves a function's bound Secret names → an env-var map injected into the
	// worker (ADR-0057, F15 last mile). nil ⇒ secret injection disabled: a function declaring
	// spec.secrets fails closed (SecretResolveFailed). Satisfied by *secrets.Resolver.
	Secrets SecretResolver
	// DeveloperFor returns the identity the PDP authorizes for a namespace's secret reads
	// (ADR-0057 Decision 4). Defaulted to the namespace-scoped developer identity when Secrets
	// is set and this is nil; ignored when Secrets is nil.
	DeveloperFor func(ns v1.NamespaceName) auth.Identity

	// InvokeSockets provisions the per-function worker-node local API (ADR-0064) and yields the
	// socket path the reconciler sets as FUNCD_INVOKE_SOCKET. nil ⇒ fn-to-fn links off.
	InvokeSockets InvokeSocketProvider

	// S3Gateway, when Enabled, injects a per-function SigV4 keypair + endpoint into the worker
	// env (ADR-0085) for a function that declares spec.blob — AWS_ACCESS_KEY_ID/
	// AWS_SECRET_ACCESS_KEY (DeriveKeypair over Master), AWS_REGION, AWS_ENDPOINT_URL_S3
	// (ListenAddr). A function without spec.blob, or a disabled gateway, gets nothing.
	S3Gateway S3GatewayInjection

	// CatalogMaster is the node master secret the per-function catalog token is derived from (ADR-0137):
	// resolveCatalogEnv injects FUNCD_CATALOG_<ALIAS>_TOKEN = DeriveCatalogToken(master, ns, fn), a
	// MAC-authenticated bearer the catalog PEP proxy verifies (was the shared QUACK_TOKEN). It is the
	// SAME master the S3 gateway derives keypairs from (loaded once at the compose root). nil/empty ⇒ a
	// still-derivable but unverifiable token (the proxy holds the real master); the master is never logged.
	CatalogMaster []byte

	// CatalogProxies reports the catalog listeners bound in this daemon run (ADR-0137, ADR-0162): a consumer is
	// injected its catalog's bound listener URL, and waits while none is bound. nil ⇒ the catalog's status.endpoint,
	// for harnesses without a Manager.
	CatalogProxies CatalogProxies

	// CatalogExtensionDir, when non-empty, is injected as DUCKDB_EXTENSION_DIRECTORY into a
	// catalog-consumer function's worker env (a function declaring spec.catalogs) so its handler's
	// `LOAD quack`/`ducklake` resolves the curated DuckDB extensions from this dir. It is the dev
	// analogue of the prod bundle's duckdb-ext (ADR-0089): `funcdctl dev` extracts the embedded
	// catalog engine's extensions once and points consumers at them; prod leaves it empty (the
	// bundle carries duckdb-ext under FUNCD_BUNDLE_DIR instead). Empty ⇒ no injection.
	CatalogExtensionDir string

	// SupervisionPeriod is the requeue of a Ready function (ADR-0142); 0 ⇒ controller.SupervisionPeriod.
	SupervisionPeriod time.Duration
	// BootBackoffInitial and BootBackoffMax bound the wait before a replica that crashed while booting is created
	// again (ADR-0160); 0 ⇒ 10 s and max(5 min, initial). Negative, or a set max below initial, is fault.Invalid.
	BootBackoffInitial time.Duration
	BootBackoffMax     time.Duration

	// Calls counts the calls made to each worker (ADR-0143): the resolver records each hand-out and the drain asks
	// whether a demoted revision's worker is idle. nil ⇒ every worker is idle.
	Calls *activator.CallTracker
	// DrainGrace bounds how long a demoted revision's workers drain; 0 ⇒ 30 s (ADR-0143).
	DrainGrace time.Duration
	// HandOutSettle is how long after a hand-out, or after the switch, a worker may still receive a call; 0 ⇒ 2 s.
	HandOutSettle time.Duration
	// DrainPollInterval is the longest gap between drain passes (runtime.drainPollInterval, ADR-0163); 0 ⇒ 1 s.
	DrainPollInterval time.Duration
	// BootTimeout stops a replica not ready this long after creation (runtime.bootTimeout, ADR-0163); 0 ⇒ 1 min.
	BootTimeout time.Duration
	// ReferentPollInterval re-checks a function waiting for a referent (controller.referentPollInterval, ADR-0163),
	// bounded by the supervision period (ADR-0142 Decision 9); 0 ⇒ 2 s.
	ReferentPollInterval time.Duration
	// Clock times the drain from drainingSince; nil ⇒ clock.System().
	Clock clock.Clock
}

Deps configures the Function lifecycle reconciler (internal component, ADR-0002 §1).

type EndpointMode

type EndpointMode int

EndpointMode selects how a worker is ADDRESSED (ADR-0032); it is orthogonal to the Materializer-presence gate that selects the shim path.

const (
	// EndpointLoopback addresses the shim on 127.0.0.1 via the FUNCD_PORTFILE handshake
	// (process driver, ADR-0030).
	EndpointLoopback EndpointMode = iota
	// EndpointNetnsFixedPort addresses the shim on the netns IP at a fixed port (containerd
	// driver, ADR-0032).
	EndpointNetnsFixedPort
)

type FileMaterializer

type FileMaterializer struct{}

FileMaterializer resolves a "file://" (or bare-path) spec.image ref to a local path. It is the no-dependency dev/test driver; production uses the oras driver (ADR-0031).

func NewFileMaterializer

func NewFileMaterializer() *FileMaterializer

NewFileMaterializer builds the local-file Materializer.

func (FileMaterializer) Materialize

func (FileMaterializer) Materialize(_ context.Context, fn *v1.Function) (string, error)

Materialize returns the local filesystem path of the Function's artifact, verifying it exists. It accepts "file:///abs/path", "file://abs/path", or a bare local path.

type InvokeSocketProvider

type InvokeSocketProvider interface {
	SocketFor(ns v1.NamespaceName, name v1.ObjectName) (string, error)
	// PoolSocketFor provisions the one local API socket of pool worker `pool`, on which each call names its member;
	// members is the set it serves, replaced on every call.
	PoolSocketFor(ns v1.NamespaceName, pool v1.ObjectName, members []v1.ObjectName) (string, error)
	// Remove stops + deletes the function's local API listener (called from teardown on delete, so
	// the socket lifecycle tracks the Function resource — controller-driven, not leaked).
	Remove(ns v1.NamespaceName, name v1.ObjectName)
}

InvokeSocketProvider supplies the per-function worker-node local API socket path (ADR-0064): the reconciler sets it as FUNCD_INVOKE_SOCKET in the worker env so the shim can dial context.invoke. nil ⇒ fn-to-fn links are off (the env var is unset; invoke fails closed in the shim).

type Materializer

type Materializer interface {
	Materialize(ctx context.Context, fn *v1.Function) (localPath string, err error)
}

Materializer resolves a Function's artifact to a local path the runtime shim reads (ADR-0030). It is a seam: the local-file driver here serves the dev/e2e process path; the OCI/oras driver (ADR-0031) is the production driver of this same interface.

type PlatformResolver added in v0.2.0

type PlatformResolver interface {
	Platforms(ctx context.Context, uri, digest string) ([]v1.OCIPlatform, error)
}

PlatformResolver lists the platforms an artifact digest provides (ADR-0145): an OCI image index's, an annotated manifest's one, or nil for an artifact that runs anywhere. An artifact that runs nowhere is an error matching scheduler.ErrNoMatchingPlatform. The reconciler gates placement on it.

type Reconciler

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

Reconciler is the one controller.Reconciler for KindFunction.

func NewReconciler

func NewReconciler(d Deps) (*Reconciler, error)

NewReconciler builds the Function lifecycle reconciler. The ports are required; Materializer/ShimCommand are optional (set together to enable execution, ADR-0030).

func (*Reconciler) Close added in v0.5.0

func (r *Reconciler) Close() error

Close removes the pool manifest dir NewReconciler created; a configured one is left in place.

func (*Reconciler) Endpoints

func (r *Reconciler) Endpoints() activator.Endpoints

Endpoints returns the production activator.Endpoints (the seam ADR-0016 deferred to P-M): a function's ready worker upstream.

func (*Reconciler) MapAccess added in v0.5.0

func (r *Reconciler) MapAccess(ctx context.Context, obj v1.Object) []controller.Request

MapAccess maps a KVStore, Bucket, RolesAssignment, EgressPolicy or Policy change to every Function of its namespace that declares a pool worker, Idle included: the change can move each to another pool.

func (*Reconciler) MapCatalogService added in v0.6.0

func (r *Reconciler) MapCatalogService(ctx context.Context, obj v1.Object) []controller.Request

MapCatalogService maps a changed or deleted CatalogService to every Function of its namespace whose spec.catalogs names it, so a consumer's RevisionReady follows its catalog within one pass (ADR-0162 Decision 5). A List error logs and maps nothing.

func (*Reconciler) PoolMembers added in v0.5.0

func (r *Reconciler) PoolMembers(ns v1.NamespaceName, worker v1.ObjectName) (members []v1.ObjectName, isMember func(name string) bool, ok bool)

PoolMembers is a snapshot of the member set last recorded for pool worker `worker` in ns: its names and a lookup over them. ok is false when none is recorded.

func (*Reconciler) Reconcile

func (r *Reconciler) Reconcile(ctx context.Context, req controller.Request) (controller.Result, error)

Reconcile converges one Function to its desired state.

type S3GatewayInjection

type S3GatewayInjection struct {
	Enabled    bool
	ListenAddr string
	// Endpoint is the sandbox-facing S3 URL (ADR-0085): the node address a netns'd worker can reach —
	// the CNI bridge gateway IP under containerd. Empty ⇒ derived as http://<ListenAddr> (loopback dev).
	Endpoint string
	// Derive returns the deterministic per-(kind, ns, name) SigV4 keypair (s3gateway.DeriveKeypair,
	// bound to the node master secret; ADR-0175). Required when Enabled.
	Derive func(kind v1.Kind, ns, name string) (access, secret string)
}

S3GatewayInjection configures the worker-env S3 keypair injection (ADR-0085). Derive computes the per-function (access, secret) from the node master over the Ref — supplied by the wiring (pkg/funcd) so this package stays free of the versitygw dependency the gateway carries; the master secret it closes over is never logged. The zero value (Enabled false) injects nothing.

type SecretResolver

type SecretResolver interface {
	ResolveEnv(ctx context.Context, id auth.Identity, ns v1.NamespaceName, names []string) (map[string]string, error)
}

SecretResolver resolves a function's bound Secret names → an env-var map for worker injection, PDP-authorized for id (ADR-0022/0057). The reconciler depends on this local seam for resolution (ADR-0002 import discipline) — satisfied by *secrets.Resolver, wired in pkg/funcd; it uses internal/secrets only for the pure reserved-key guard (MergeEnvGuarded, no store dep, ADR-0092). A nil resolver on Deps disables secret injection: a function that declares spec.secrets then fails closed (SecretResolveFailed).

type ShapeValidator

type ShapeValidator interface {
	Validate(ctx context.Context, fn *v1.Function) error
}

ShapeValidator validates a Function's artifact conforms to its runtime shape.

func NewBasicValidator

func NewBasicValidator() ShapeValidator

NewBasicValidator returns the V1 spec-well-formedness ShapeValidator (the authoritative load-time materialization is the shim's, on the Linux lane, P-S).

Jump to

Keyboard shortcuts

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