Documentation
¶
Overview ¶
Package k8s resolves cadish `k8s://service.namespace:port` upstream targets to the live set of ready pod IP:port endpoints via the Kubernetes API (EndpointSlices), using a client-go SharedInformer with a warm local cache and event-driven re-resolution. It is built lazily — only when a loaded Cadishfile actually contains a k8s:// target — so a non-Kubernetes cadish pays nothing.
Index ¶
- func NewClientset(opts Options) (kubernetes.Interface, error)
- func RESTConfig(kubeconfig string) (*rest.Config, error)
- type CertPEM
- type Client
- func (c *Client) Cache() *EndpointCache
- func (c *Client) Clientset() kubernetes.Interface
- func (c *Client) Close()
- func (c *Client) Factory() informers.SharedInformerFactory
- func (c *Client) OnServiceChange(fn func(namespace, service string)) (cancel func())
- func (c *Client) Resolver() lb.EndpointResolver
- func (c *Client) Start(ctx context.Context) error
- type EndpointCache
- type Options
- type TLSSecretGate
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func NewClientset ¶
func NewClientset(opts Options) (kubernetes.Interface, error)
NewClientset builds just the typed clientset with real auth (in-cluster, else kubeconfig), without any informers. The ingress controller (which builds its own informer factories from the clientset) uses this to avoid constructing an unused EndpointSlice factory.
func RESTConfig ¶
RESTConfig resolves auth (explicit kubeconfig, else in-cluster, else KUBECONFIG / ~/.kube/config) and returns the rest.Config. The Gateway API controller uses it to build its own gateway-api typed clientset over the SAME auth as the core clientset, keeping this package the single owner of auth resolution.
Types ¶
type CertPEM ¶ added in v0.2.3
type CertPEM struct {
Cert, Key []byte
Leaf *x509.Certificate
}
CertPEM is a validated BYO keypair (the raw Secret bytes) plus the parsed leaf, threaded from the per-reconcile validation gate to injection so the keypair is read and parsed once.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client wraps a clientset and a SharedInformerFactory over EndpointSlices and Services, exposing a warm EndpointCache and an event-poke fan-out. (The Service informer exists to translate a numeric port reference to a multi-port Service into the right EndpointSlice port, which slices key by NAME only — CAD-11.)
func NewClientWithInterface ¶
func NewClientWithInterface(cs kubernetes.Interface, opts Options) *Client
NewClientWithInterface builds a Client over an injected clientset (the test seam for fake.NewSimpleClientset).
func (*Client) Cache ¶
func (c *Client) Cache() *EndpointCache
Cache returns the warm endpoint cache.
func (*Client) Clientset ¶
func (c *Client) Clientset() kubernetes.Interface
Clientset returns the underlying typed clientset. The ingress controller (Layer 2) builds its own SharedInformerFactory from this one clientset to add the networking/secret/configmap informers, reusing Layer 1's API connection.
func (*Client) Factory ¶
func (c *Client) Factory() informers.SharedInformerFactory
Factory returns the EndpointSlice SharedInformerFactory. (The ingress controller builds a SEPARATE factory for its own informers because this one is already started for EndpointSlices and informers must be registered before Start.)
func (*Client) OnServiceChange ¶
OnServiceChange registers fn for endpoint-change pokes and returns a cancel func that DEREGISTERS it (FIX 4). Registration is keyed by an opaque token, so a pool that is rebuilt (k8s:// fingerprint change) can remove its listener instead of leaking it — the append-only registry previously pinned every dead *lb.Upstream forever. Safe to call before or during Start (the RLock/copy in fire keeps the fan-out race-clean); the returned cancel is idempotent.
func (*Client) Resolver ¶
func (c *Client) Resolver() lb.EndpointResolver
Resolver returns an lb.EndpointResolver backed by this client's warm cache and event fan-out.
func (*Client) Start ¶
Start runs the informers and blocks until caches sync or SyncTimeout elapses. It is guarded by a sync.Once: only the first call registers the event handler and starts the factory; a second call is a no-op that replays the first call's error (so re-registering the event handler / re-starting the factory can never double-fire pokes).
type EndpointCache ¶
type EndpointCache struct {
// contains filtered or unexported fields
}
EndpointCache resolves (namespace, service, port) to ready pod endpoints by reading the warm EndpointSlice informer cache (no API call per resolve). Named ports are mapped to numbers from the slices' own port list; a NUMERIC reference to a MULTI-port Service is first translated to the Service port's name via the warm Service informer cache (CAD-11), because slices key ports by name only.
func (*EndpointCache) Endpoints ¶
func (c *EndpointCache) Endpoints(namespace, service, port string) ([]lb.Endpoint, error)
Endpoints returns the ready endpoints for service in namespace at port (a number passed through, or a named port resolved via the slice's port list). It unions across the service's EndpointSlices and de-duplicates by IP:port.
type Options ¶
Options configures the K8s client. Kubeconfig empty ⇒ in-cluster first, then KUBECONFIG, then ~/.kube/config.
type TLSSecretGate ¶ added in v0.2.3
type TLSSecretGate struct {
// contains filtered or unexported fields
}
TLSSecretGate validates each referenced kubernetes.io/tls Secret ONCE per reconcile. It is the single implementation shared by the Ingress and Gateway controllers (formerly a verbatim-duplicated `tlsSecretGate` in each): Usable parses tls.crt/tls.key and reports whether it is a usable keypair; Covers answers per-host SAN coverage (F10) from the cached leaf. A present-but-CORRUPT Secret is reported UNUSABLE, so its host falls through to ACME issuance (design D61: "absent OR unusable → ACME") rather than being classified BYO and left dark. The validated PEM is cached in `good` and reused by injection (no re-read, no re-parse); `bad` records present-but-unparseable Secrets for warning Events.
func NewTLSSecretGate ¶ added in v0.2.3
func NewTLSSecretGate(sec corelisters.SecretLister) *TLSSecretGate
NewTLSSecretGate builds a gate reading Secrets from sec.
func (*TLSSecretGate) Bad ¶ added in v0.2.3
func (g *TLSSecretGate) Bad() map[string]string
Bad returns the map of present-but-corrupt Secrets (ns/name → parse error) so the controller can surface warning Events. The returned map is the gate's own; treat it as read-only.
func (*TLSSecretGate) Covers ¶ added in v0.2.3
func (g *TLSSecretGate) Covers(ns, name, host string) bool
Covers reports whether the Secret ns/name's certificate SANs cover host (F10). It is only ever consulted for a Secret the gate already classified usable (its leaf is in `good`), so a cache miss (or a nil leaf) reports false → the host is treated as not covered and falls back to ACME. x509.Certificate.VerifyHostname implements SAN matching (including single-label "*.suffix" wildcards).
func (*TLSSecretGate) Good ¶ added in v0.2.3
func (g *TLSSecretGate) Good(ns, name string) (CertPEM, bool)
Good returns the validated keypair for ns/name (ok=false when the Secret was never classified usable this reconcile). Injection uses it to avoid a Secret re-read.
func (*TLSSecretGate) Usable ¶ added in v0.2.3
func (g *TLSSecretGate) Usable(ns, name string) bool
Usable reports whether ns/name is an existing Secret carrying a PARSEABLE TLS keypair. It is memoized so a Secret referenced by several Ingresses/listeners is parsed only once. A missing, non-TLS, or corrupt Secret reports false (→ the host falls back to ACME).