Expand description
Kopia identity resolution (ADR §4.2).
Kopia records every snapshot under username@hostname:sourcePath. Kopiur makes
that identity an explicit, overridable part of the API rather than an accident
of metadata.name/metadata.namespace (ADR §2.2 principle 9). This module is
the single place the defaulting + templating rules live. The webhook calls it
at admission (so a bad expression/component is rejected on kubectl apply) and
the controller calls it again on every reconcile, resolving from the LIVE
SnapshotPolicy.spec.identity and the LIVE referenced repository’s
identityDefaults — not a value pinned once and frozen. status.resolved.identity
mirrors the most recent resolution for observability; it is not the source of
truth a later run reads back. What actually keeps an already-snapshotted policy
stable is the fork guard (ValidationError::IdentityWouldFork/
RepositoryIdentityWouldFork): an edit that would change the resolved identity
on a policy (or repository) with existing history is rejected at admission
unless acknowledged with the allow-identity-change annotation.
§Defaults (ADR §4.2)
username←SnapshotPolicy.metadata.namehostname← namespacesourcePath←/pvc/<pvcName>
§Repository/ClusterRepository identity expressions (CEL)
A crate::common::IdentityDefaults (Repository.spec.identityDefaults or
ClusterRepository.spec.identityDefaults) supplies hostnameExpr/
usernameExpr, CEL expressions ([cel]) validated (compiled + trial-evaluated
via validate_identity_expr) at admission, then actually rendered against the
LIVE consumer + LIVE repository on every reconcile (ADR-0004 §5) — so editing
identityDefaults re-renders every consumer that resolves through it on its
next backup (guarded by ValidationError::RepositoryIdentityWouldFork, see
the module intro above). A consumer’s explicit Identity override always
wins over the expression.
§CEL environment
Each expression returns a string and is evaluated against:
namespace (the consumer’s namespace), policyName (the SnapshotPolicy’s
name), labels and annotations (its metadata maps), and cluster
(IdentityDefaults::cluster, or "" when unset — see [identity_context]).
Examples: hostnameExpr: "namespace",
usernameExpr: "namespace + '-' + policyName",
"'team' in labels ? labels['team'] : namespace",
"namespace + '.' + cluster". CEL is sandboxed (no I/O, no arbitrary code); a
syntax error or out-of-scope variable is rejected at kubectl apply via
validate_identity_expr, and a non-string result is a typed error.
Expressions are length-capped (MAX_EXPR_LEN) as the cost-budget surrogate.
§Multi-cluster hostname default
When a repository’s IdentityDefaults::cluster is set, the default
(no override, no hostnameExpr) kopia identity hostname becomes
<namespace>.<cluster> instead of bare <namespace>, so N clusters sharing one
repository never collide on a same-named namespace. classify_hostname
recovers the namespace/cluster split on the read path (retention, discovered
Snapshot placement).
Structs§
- Identity
Inputs - Inputs to identity resolution. Grouped into a struct so call sites are readable and future inputs slot in without churning the signature.
Enums§
- Host
Class - Classification of a snapshot identity hostname relative to THIS cluster.
Kubernetes namespace names cannot contain
., so the FIRST.unambiguously ends the namespace part of a<namespace>.<cluster>hostname. Total: with no cluster identity every hostname isBare; an empty namespace part (“.east”) or empty suffix (“ns.”) also classifiesBare(never a panic, never an invalid empty namespace). Suffix comparison is case-sensitive.
Constants§
- MAX_
EXPR_ LEN - Maximum CEL expression length accepted at admission (the cost-budget surrogate;
cel0.13 has no built-in cost API). 1 KiB is far beyond any real identity expression and bounds parse/eval work on adversarial input.
Functions§
- classify_
hostname - Classify a kopia identity
hostnameagainstmy_cluster(IdentityDefaults::cluster, resolved from the consuming repository), so a reader (retention pruning, discovered-Snapshotplacement) can tell whether a hostname it sees was written by this cluster, another cluster sharing the same repository, or predates cluster identity entirely. - identity_
string - Format a kopia identity string. With a source path:
username@hostname:path; without one:username@hostname(kopia’s identity-only form, used for catalog queries that aren’t pinned to a path). - resolve_
identity - Resolve a
ResolvedIdentityfrom defaults, an optionalRepository/ClusterRepositoryidentity expression set, and explicit consumer overrides (ADR §4.2 / ADR-0004 §5). - validate_
identity_ expr - Validate a
Repository/ClusterRepositoryidentityDefaultsCEL expression at admission (ADR-0004 §5): it must compile, and — because CEL reports an out-of-scope variable only at evaluation time — it must also evaluate against a representative context without referencing an undeclared variable. A non-string result is rejected. Missing map keys (e.g.labels['env']when the trial data lacksenv) are tolerated: they are data-dependent, not a structural error.