Documentation
¶
Overview ¶
Package funcd is the platform-as-a-library facade (ADR-0014): the composition root that wires every port into a *Platform and owns its start/stop lifecycle. Run serves the control-plane API and runs the controller (ADR-0028); cmd/funcd is a thin shell over it; e2e tests embed it with the InMemory() preset — no daemon, no root, no network beyond the ephemeral control-plane listener.
Index ¶
- Constants
- type LogLine
- type LogObserver
- type Option
- func InMemory() Option
- func Production() Option
- func WithArtifactStore(dir string) Option
- func WithAuthorizer(a auth.Authorizer) Option
- func WithBlob(b blob.Bucket) Option
- func WithBlobPollInterval(d time.Duration) Option
- func WithBus(b bus.Bus) Option
- func WithCatalogExtensionDir(dir string) Option
- func WithCatalogProviderRuntime(r provider.Runtime) Option
- func WithCatalogProxyHost(host string) Option
- func WithContainerExecution(imageFor func(runtime string) string) Option
- func WithDataPlaneAddr(addr string) Option
- func WithDeadLetterQueue(dataDir string, deliveryAttempts int, retention time.Duration, maxEntries int) Option
- func WithDevAuth(token string, namespaces ...string) Option
- func WithEdgeAuth() Option
- func WithEdgeObservability(cfg observ.Config) Option
- func WithEdgeShaping(cfg shape.Config) Option
- func WithEgressGateway(gatewayPort, dnsForwarderPort uint16, dnsUpstream netip.AddrPort) Option
- func WithEgressIsolation(mgr network.Manager, p network.Policy) Option
- func WithFunclog(segmentMaxAge time.Duration, segmentMaxBytes int) Option
- func WithGateway(g gateway.Gateway) Option
- func WithInvokeSocketDir(dir string) Option
- func WithKVStore(kv kvstore.KV) Option
- func WithKVStoreQuota(maxPerNamespace int) Option
- func WithLimits(cfg limit.Config) Option
- func WithListenAddr(addr string) Option
- func WithLogCompaction(window, interval, retention time.Duration) Option
- func WithLogObserver(obs LogObserver) Option
- func WithLogger(l *slog.Logger) Option
- func WithMaterializer(m function.Materializer) Option
- func WithNodePlatform(p v1.OCIPlatform) Option
- func WithPoolLimit(limit int) Option
- func WithPoolShim(cmd ...string) Option
- func WithPoolShimFor(runtimeFamily string, cmd ...string) Option
- func WithRuntime(r runtime.Runtime) Option
- func WithRuntimeShim(cmd ...string) Option
- func WithRuntimeShimFor(runtimeFamily string, cmd ...string) Option
- func WithS3Gateway(listenAddr, endpoint string, maxUploadBytes int64, ...) Option
- func WithSiteDefaultIndex(index string) Option
- func WithStore(s store.Store) Option
- func WithTLS(spec edgetls.Spec) Option
- func WithTelemetry(t *observability.Telemetry) Option
- func WithWorkflow(dataDir string, defaultStepTimeout, retention time.Duration, defaultRetry int, ...) Option
- func WithWorkflowContractResolver(r workflow.ContractResolver) Option
- func WithoutFunclog() Option
- func WithoutFunclogTraces() Option
- func WithoutLogCompaction() Option
- type Platform
Constants ¶
const DevToken = "funcd-dev-token"
DevToken is the default control-plane credential token wired by InMemory(). It lets a test/tool authenticate against an embedded platform; it is NOT a production identity story (Production() wires no default token — ADR-0028).
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type LogLine ¶
type LogLine struct {
Namespace string
Function string
Replica string
Invocation string // per-invocation id (may be empty for pre-invocation lines)
Time time.Time // real event time
Severity string // TRACE | DEBUG | INFO | WARN | ERROR | FATAL
Body string // the log message
Attrs map[string]string // structured attributes
}
LogLine is one structured function-log record surfaced to a LogObserver — a stable projection of the internal funclog Entry, so the public option leaks no internal type. Attrs is read-only.
type LogObserver ¶
type LogObserver func(LogLine)
LogObserver receives every captured function log line as it happens, IN ADDITION to the normal blob-persisted capture. `funcdctl dev` uses it to stream logs to the terminal in real time. It runs on the log-routing goroutine and must not block.
type Option ¶
type Option func(*config) error
Option configures the platform. Each With* function returns an Option that injects one dependency. Options are validated by New before the platform is returned (ADR-0002 functional-options facade).
func InMemory ¶
func InMemory() Option
InMemory returns an Option that wires the real in-memory drivers for every port — memory store, gocloud mem bucket, embedded memory-storage NATS, process runtime, embedded reverse-proxy gateway, a stdout text logger, and the no-op telemetry pipeline. No root, no containerd, no network: the e2e-harness preset every later feature embeds. Drivers that need a context at construction use context.Background() (the facade's New is ctx-free, ADR-0002/ADR-0014); they are released by Shutdown.
func Production ¶
func Production() Option
Production returns an Option that wires the pure-Go production drivers that do NOT vary by deployment: the embedded reverse-proxy gateway, a JSON logger, and the no-op telemetry pipeline (an OTLP endpoint is supplied via WithTelemetry when configured), plus the public control-plane bind, RBAC, and deliberately NO default credential. The **store** (badger, pure-Go, ADR-0065), **runtime** (containerd, Linux), and **blob + bus** (file vs memory — the daemon's `--memory` substrate choice, ADR-0043) are deployment-injected via WithStore / WithRuntime / WithBlob / WithBus — so Production() is composed as funcd.New(funcd.Production(), WithBlob(...), WithBus(...), WithStore(...), WithRuntime(...)).
func WithArtifactStore ¶
WithArtifactStore enables the OCI artifact Materializer (ADR-0031): functions are pulled by digest from their `spec.image` into a per-digest cache under dir. When a runtime shim is configured and no explicit Materializer is set, this selects the oras driver over the local-file stand-in.
func WithAuthorizer ¶
func WithAuthorizer(a auth.Authorizer) Option
WithAuthorizer injects the authorization PDP. Defaults to rbac.New().
func WithBlobPollInterval ¶
WithBlobPollInterval sets the platform-wide cadence at which a `blob:` EventSource's prefixes are List-polled for new objects (ADR-0119, F83). A duration ≤ 0 ⇒ the 15s default. One cadence for all blob sources in V1 (a per-source override is an open question).
func WithCatalogExtensionDir ¶
WithCatalogExtensionDir points catalog-consumer functions at a local DuckDB extension directory, injected into their worker env as DUCKDB_EXTENSION_DIRECTORY so a handler's `LOAD quack`/`ducklake` resolves the curated extensions. It is the `funcdctl dev` (ADR-0125) analogue of the prod bundle's duckdb-ext (ADR-0089): dev extracts the embedded catalog engine's extensions once and points consumers at them, since a dev handler runs from source with no bundle. Empty ⇒ no injection (prod).
func WithCatalogProviderRuntime ¶
WithCatalogProviderRuntime overrides the CatalogService add-on-provider runtime (ADR-0087). The production runtime supervises the curated duckdb CONTAINER image; `funcdctl dev` (ADR-0125) injects a process-mode driver that runs the embedded DuckDB+Quack engine as a host subprocess, since process-dev runs no containers.
func WithCatalogProxyHost ¶
WithCatalogProxyHost sets the netns-reachable host the per-CatalogService catalog PEP proxies publish (ADR-0137) — the query-path analog of the S3 gateway's sandbox-facing Endpoint host. Under containerd a worker runs in its OWN netns and cannot reach the daemon's 127.0.0.1, so set this to the CNI bridge gateway IP (e.g. "10.63.0.1"): the proxy then binds 0.0.0.0 and publishes that host in FUNCD_CATALOG_<ALIAS>_URL. Empty (the default / process-runtime / funcdctl dev) ⇒ 127.0.0.1, where the daemon and the worker share the loopback.
func WithContainerExecution ¶
WithContainerExecution enables curated-image container execution (ADR-0032): functions run in the containerd worker from the image imageFor(fn.Spec.Runtime) returns, with the shim as the image entrypoint, the artifact bind-mounted, and a fixed netns port. Used with the containerd runtime driver (prod); WithRuntimeShim is the process-driver path.
func WithDataPlaneAddr ¶
WithDataPlaneAddr sets the data-plane (function-invocation) listen address (ADR-0033). Default is 0.0.0.0:8081 (Production); InMemory() uses an ephemeral 127.0.0.1:0.
func WithDeadLetterQueue ¶
func WithDeadLetterQueue(dataDir string, deliveryAttempts int, retention time.Duration, maxEntries int) Option
WithDeadLetterQueue tunes the eventing DLQ + bounded action-delivery retry (ADR-0118, F85). The DLQ is always wired; this option sets its persistence + tunables: dataDir is the dedicated Badger directory (empty ⇒ in-memory, the InMemory-preset / memory-storage path), deliveryAttempts is the bounded-retry cap before a failed workflow:/function: delivery is dead-lettered (< 1 ⇒ 3), retention is how long parked entries survive the periodic sweep (0 ⇒ never), and maxEntries is the per-namespace count cap (0 ⇒ unbounded). cmd/funcd derives dataDir as <dataDir>/deadletter from config.
func WithDevAuth ¶
WithDevAuth wires a single developer-role credential for token, scoped to the given namespaces (ADR-0028). It is the V1 dev/test credential mechanism — not a production identity story (multi-role/issuance is V2) — and lets a public-surface caller authenticate without importing internal/auth. InMemory() applies a default (DevToken in "default"); Production() sets none (the operator supplies one).
func WithEdgeAuth ¶
func WithEdgeAuth() Option
WithEdgeAuth enables the edge authn PEP (ADR-0113, F77) on the data plane: for a target whose stance is `authenticated`, the caller's bearer is authenticated (reusing the control-plane credentials) and the decision delegated to the authorizer, rejecting 401/403 before the activator. Without it, an `authenticated` stance fails closed (401); `open` targets are unaffected.
func WithEdgeObservability ¶
WithEdgeObservability enables edge observability (ADR-0114, F76): RED metrics + an edge trace span (traceparent) + an access log. Uses the injected Telemetry (no-op by default). Zero Config ⇒ off.
func WithEdgeShaping ¶
WithEdgeShaping enables edge shaping (ADR-0114, F78): CORS, response header inject/strip, and gzip compression (skipping streaming/upgrades). Zero Config ⇒ off (pass-through).
func WithEgressGateway ¶
WithEgressGateway wires the ADR-0117 (F81) transparent egress PEP + DNS forwarder: when enabled on Linux, funcd starts a gateway on gatewayPort (F80's REDIRECT target) that authorizes every outbound worker connection against its namespace's EgressPolicy via the cedar PDP (egress::connect over a forwarder-attested NetDestination), and a DNS forwarder on dnsForwarderPort (the domain trust anchor + the only reachable resolver). dnsUpstream is the node resolver the forwarder forwards to. Disabled or non-Linux ⇒ no-op (egress open). Pairs with WithEgressIsolation (same server.network.egress flag).
func WithEgressIsolation ¶
WithEgressIsolation enables the worker network-isolation substrate (ADR-0115, FEAT-0007/F80): funcd programs an nftables policy (over the funcd0 CNI bridge) that default-denies worker egress and redirects remaining external TCP into the egress gateway (F81). mgr is the platform-specific Manager (network.New — a no-op when disabled or non-Linux); p is the ruleset frame. Applied at Run start (before workers serve), removed at Shutdown.
func WithFunclog ¶
WithFunclog tunes structured function-log capture (ADR-0081): the segment seal age and size (either 0 keeps the sink default — 10s / 8 MiB). Capture is on by default when the runtime supports it; use WithoutFunclog to disable.
func WithGateway ¶
WithGateway injects the ingress / API gateway port.
func WithInvokeSocketDir ¶
WithInvokeSocketDir sets the directory for the per-function worker-node local API sockets (ADR-0064, fn-to-fn invoke). cmd/funcd sets it to <dataDir>/invoke from config; unset (InMemory()/tests) ⇒ a temp dir.
func WithKVStore ¶
WithKVStore injects the function-facing KV driver (ADR-0066/0069). Absent ⇒ the in-memory driver.
func WithKVStoreQuota ¶
WithKVStoreQuota sets the per-namespace KVStore count cap enforced at admission (ADR-0072, kvstore.maxStoresPerNamespace). 0 ⇒ the default (100); a negative value disables the quota.
func WithLimits ¶
WithLimits enables the ingress-protection middleware (ADR-0112, F75) on the data-plane chain: a token-bucket rate limit (429), a Content-Length body-size cap (413), and an in-flight concurrency ceiling (503), all rejecting BEFORE the activator (zero wake). A zero Config is a pass-through.
func WithListenAddr ¶
WithListenAddr sets the control-plane bind address (host:port). Default is the preset's (InMemory: an ephemeral "127.0.0.1:0"; Production: "0.0.0.0:8080").
func WithLogCompaction ¶
WithLogCompaction tunes function-log compacted compaction (ADR-0083): the window (bucket size + close threshold), the pass interval, and the compacted retention. A zero window/interval keeps the default (1h / 5m); retention <= 0 keeps compacted forever. Compaction is on by default when a blob substrate is present; use WithoutLogCompaction to disable.
func WithLogObserver ¶
func WithLogObserver(obs LogObserver) Option
WithLogObserver streams every captured function log line to obs as it happens, in addition to the normal blob-persisted capture — `funcdctl dev` uses it to print logs to the terminal in real time. obs runs on the log-routing goroutine and must not block.
func WithLogger ¶
WithLogger injects the root logger. If not set, a stdout text logger is built.
func WithMaterializer ¶
func WithMaterializer(m function.Materializer) Option
WithMaterializer overrides the artifact Materializer (ADR-0030). When a shim is configured but no Materializer is supplied, the local-file driver is used (the OCI driver is P-V-A). Has no effect unless a runtime shim is also configured.
func WithNodePlatform ¶ added in v0.2.0
func WithNodePlatform(p v1.OCIPlatform) Option
WithNodePlatform sets the platform this node runs (ADR-0145): the scheduler refuses an artifact built for other platforms, and the materializer pulls an image index's manifest for this one. Default: the daemon's own GOOS/GOARCH (v1.HostPlatform), which is right whenever funcd runs on the node it schedules.
func WithPoolLimit ¶
WithPoolLimit caps handlers per pool worker (ADR-0046 Decision 3): over-cap members declaring one worker id are held NotReady with a PoolFull condition. 0 ⇒ the default (16).
func WithPoolShim ¶
WithPoolShim enables worker pooling (ADR-0046): cmd is the launch prefix for the pooled worker_threads host (e.g. "node", "/opt/funcd/pool.mjs"). A function declaring spec.pooling.worker then co-locates with same-(namespace, runtime, worker-id) peers in one pool worker, launched with this command + the FUNCD_POOL_MANIFEST of its admitted members. With no pool shim configured pooling is off and every function runs solo (the default).
func WithPoolShimFor ¶
WithPoolShimFor registers a pooled-host launch prefix for one runtime family (ADR-0050): a python* function that opts into spec.pooling.worker co-pools via this host (the subinterpreter pool.py) instead of staying solo. WithPoolShim remains the node default. A runtime family with no pool host runs solo — so this is additive and host-gated. Used as WithPoolShimFor("python", "python3.14", "/opt/funcd/pool.py").
func WithRuntime ¶
WithRuntime injects the function runtime (worker) port.
func WithRuntimeShim ¶
WithRuntimeShim enables real function execution (ADR-0030): cmd is the launch prefix for the runtime shim (e.g. "node", "/opt/funcd/shim.mjs"), to which the reconciler appends the artifact + handler via the environment. With no shim configured the reconciler runs the legacy placeholder (no execution).
func WithRuntimeShimFor ¶
WithRuntimeShimFor registers a shim launch prefix for one runtime family (ADR-0049): a function whose spec.runtime starts with runtimeFamily (e.g. "python") is launched with cmd instead of the default WithRuntimeShim. Lets one daemon run several curated languages — e.g. node by default plus WithRuntimeShimFor("python", "python3", "/opt/funcd/shim.py"). The rest of execution (artifact + handler env, portfile handshake, readiness) is identical per language.
func WithS3Gateway ¶
func WithS3Gateway(listenAddr, endpoint string, maxUploadBytes int64, masterSecretFile, dataDir string) Option
WithS3Gateway enables the opt-in S3-protocol frontend over the blob substrate (ADR-0080/0085): a node-private TCP listener serving GET(+range)/PUT(+multipart)/ HEAD/DELETE/ListObjectsV2 governed by the cedar spec.blob binding-as-grant PEP, with per-function SigV4 keypairs derived from a node master secret and injected into a spec.blob function's worker env. listenAddr is node-private (e.g. 127.0.0.1:9000); maxUploadBytes (0 ⇒ 1 GiB) caps a single buffered object; masterSecretFile (empty ⇒ generate+persist 0600 under dataDir/s3gateway/master.key) supplies the node master. Without this option no listener, IAM, or keypair injection exists.
func WithSiteDefaultIndex ¶
WithSiteDefaultIndex sets the document a Site serves for "/" (and asserts present before Ready) when its spec.index is empty (ADR-0139, F103). "" ⇒ "index.html". A relative path, never a leading '/'.
func WithTLS ¶
WithTLS enables TLS termination (ADR-0111, F74) on BOTH listeners (control-plane + data-plane) via ServeTLS — funcd keeps its own http.Servers (no handover). The zero Mode defaults to `selfsigned` (stdlib, offline, generated+persisted). Omit it entirely for plaintext (the back-compat default).
func WithTelemetry ¶
func WithTelemetry(t *observability.Telemetry) Option
WithTelemetry injects the OTel telemetry pipeline. If not set, the no-op pipeline is used (no collector required).
func WithWorkflow ¶
func WithWorkflow(dataDir string, defaultStepTimeout, retention time.Duration, defaultRetry int, payloadLimit int64) Option
WithWorkflow tunes the workflow engine (ADR-0094). The engine is always wired; this option sets its persistence + tunables: dataDir is the Badger run-state directory (empty ⇒ in-memory, the default / InMemory-preset path), defaultStepTimeout bounds a single step invocation (0 ⇒ none), retention is how long terminal runs survive before the periodic sweep reclaims them (0 ⇒ never), defaultRetry is the per-step attempt cap when a step declares no retry (< 1 ⇒ 1), and payloadLimit caps a run's input (at admission) and a step's output in bytes (0 ⇒ unbounded). cmd/funcd derives dataDir as <dataDir>/workflow from config.
func WithWorkflowContractResolver ¶
func WithWorkflowContractResolver(r workflow.ContractResolver) Option
WithWorkflowContractResolver overrides the workflow F65 typed-edge ContractResolver (ADR-0098). The production resolver reads a step image's I/O contract from OCI metadata; `funcdctl dev` (ADR-0125) injects a resolver for from-source steps, whose file:// bundles carry no OCI artifact to inspect.
func WithoutFunclog ¶
func WithoutFunclog() Option
WithoutFunclog disables structured function-log capture (Path B); raw stdout/stderr still flows.
func WithoutFunclogTraces ¶
func WithoutFunclogTraces() Option
WithoutFunclogTraces disables the traces signal (ADR-0101, per-invocation spans) while keeping the logs signal. Subordinate to WithoutFunclog: with the whole funclog channel off, there is no channel and this is moot. With the channel on but traces off, the host's trace sink is nil and span lines are read off the channel and dropped. Traces are on by default when the runtime supports capture.
func WithoutLogCompaction ¶
func WithoutLogCompaction() Option
WithoutLogCompaction disables compacted compaction: no compactor goroutine runs and raw OTLP-JSONL is left untouched (capture itself still runs).
type Platform ¶
type Platform struct {
// contains filtered or unexported fields
}
Platform is the assembled funcd runtime — the composition root built by New.
func New ¶
New assembles the platform from opts, validates every required dependency, builds the control plane (controller + reconcilers + API server), and binds the control-plane listener (so Addr() is ready before Run). It returns a typed fault (and a nil *Platform) on a missing dep or a build/bind failure — never a partial platform, never a panic.
func (*Platform) Addr ¶
Addr returns the bound control-plane address (host:port), available after New.
func (*Platform) DataPlaneAddr ¶
DataPlaneAddr returns the bound data-plane (function-invocation) address, available after New (ADR-0033).
func (*Platform) EgressWorkerIndex ¶
func (p *Platform) EgressWorkerIndex() *egress.MemoryWorkerIndex
EgressWorkerIndex returns the egress WorkerIndex the containerd runtime populates at worker provisioning (ADR-0117 §5): on worker-up it records the funcd0 IP → the worker's (namespace, function) Ref so the gateway can authenticate the caller by source IP. nil ⇒ egress is not enabled.
func (*Platform) Providers ¶
Providers returns the platform's provider catalog (ADR-0082), available after New.
func (*Platform) Run ¶
Run starts the control loops + the control-plane server and blocks until ctx is cancelled, then shuts down gracefully and returns nil. It owns the crash-only lifecycle (ADR-0028).
func (*Platform) Shutdown ¶
Shutdown closes the platform's components (the control-plane listener, the five ports, telemetry). It is concurrency-safe and idempotent (sync.Once so Run's shutdown-on-ctx and a caller's explicit Shutdown cannot race or double-close) and best-effort (joins errors, closing all even if one fails).