pub enum ValidationError {
Show 36 variants
InvalidRunAnnotation {
message: String,
},
ClusterRepoNamespaceForbidden {
namespace: String,
},
ConsumerNamespaceNotAllowed {
namespace: String,
repo: String,
},
DiscoveredMustRetain {
got: String,
},
DiscoveredCannotSetOnScheduleDelete {
origin: &'static str,
got: String,
},
RestoreSourceRepositoryRequired,
InlineRetentionForbidden {
field: String,
},
InvalidCron {
expr: String,
reason: String,
},
InvalidTimezone {
name: String,
},
MutuallyExclusive {
a: String,
b: String,
context: String,
},
MissingRequiredField {
field: String,
},
InvalidFieldValue {
field: String,
reason: String,
},
IdentityExprCompile {
expr: String,
reason: String,
},
IdentityExprEval {
expr: String,
reason: String,
},
IdentityExprType {
expr: String,
got: String,
},
InsecureServerNotAcknowledged,
InvalidServerPort {
port: u16,
},
ServerNamespaceRequired,
SelectorLabelsUnavailable {
namespace: String,
repo: String,
},
Immutable {
field: String,
},
IdentityCollision {
identity: String,
conflict: String,
},
IdentityComponentInvalid {
field: String,
value: String,
reason: String,
},
IdentitySourcePathInvalid {
field: String,
value: String,
reason: String,
},
ClusterNameInvalid {
value: String,
reason: String,
},
IdentityWouldFork {
old: String,
new: String,
},
RepositoryIdentityWouldFork {
consumers: Vec<String>,
},
SuccessExprCompile {
expr: String,
reason: String,
},
SuccessExprEval {
expr: String,
reason: String,
},
SuccessExprType {
expr: String,
got: String,
},
PreflightExprCompile {
expr: String,
reason: String,
},
PreflightExprEval {
expr: String,
reason: String,
},
PreflightExprType {
expr: String,
got: String,
},
ReplicationDestinationSameAsSource {
backend: String,
},
MaintenanceNamespaceOnNamespacedRepo {
namespace: String,
},
ForeignSnapshotsRequiresCluster,
ForeignSnapshotsChoiceRequired,
}Expand description
A single cross-field validation failure. PartialEq so tests can assert the
exact variant; messages are written for an end user reading a rejected apply.
Variants§
InvalidRunAnnotation
The maintenance run-requested/run-mode annotations are malformed
(message produced by crate::maintenance::parse_run_annotations,
already what/why/fix).
ClusterRepoNamespaceForbidden
A Repository/ClusterRepository’s own credential refs, or a consumer’s
repository.namespace, set a namespace that the variant forbids.
For kind: ClusterRepository, repository.namespace MUST be absent
(ADR §3.2/§3.3) — the reference is cluster-scoped by name alone.
ConsumerNamespaceNotAllowed
A consumer namespace is not permitted by the target ClusterRepository’s
allowedNamespaces tenancy gate (ADR §3.2/§4.3).
Fields
DiscoveredMustRetain
A Snapshot with origin: discovered tried to set a deletionPolicy other
than Retain. Discovered snapshots are forced Retain so the operator
never deletes data it did not create (ADR §4.5).
DiscoveredCannotSetOnScheduleDelete
A Snapshot with origin: discovered or origin: adopted set
spec.onScheduleDelete. Neither has an owning SnapshotSchedule for the
field to apply to: a discovered snapshot’s owner is a repository, and an
adopted snapshot’s owner is the SnapshotPolicy it was re-attached to —
a stamped cascade policy on either is meaningless, so it is forbidden,
exactly like a non-Retain deletionPolicy (Self::DiscoveredMustRetain).
Fields
RestoreSourceRepositoryRequired
A Restore with source.identity did not set spec.repository. Identity
sources cannot derive a repository, so it is required (ADR §3.6/§4.6).
InlineRetentionForbidden
A Repository/ClusterRepository spec carried kopia-side (repo-level)
retention policy fields, which conflict with CR-driven GFS retention and
risk double-deletion (ADR §4.4 exclusivity).
InvalidCron
A cron expression failed to parse with the same parser the controller uses at runtime, so it is rejected at apply time rather than at first reconcile (ADR §4.1).
Fields
InvalidTimezone
A schedule’s timezone is not a recognized IANA timezone name (e.g. a typo
like America/Chicgo), rejected at apply time rather than silently falling
back to UTC at reconcile.
MutuallyExclusive
Two fields that may not both be set were both set (e.g. a Source with
both pvc and pvcSelector).
Fields
MissingRequiredField
A required field (or “at least one of” surface) was empty.
InvalidFieldValue
A field was set but its value is malformed (e.g. an NFS export path that is not absolute). The schema can’t express the constraint, so the webhook does.
Fields
IdentityExprCompile
A Repository/ClusterRepository identityDefaults CEL expression
(hostnameExpr / usernameExpr) failed to compile (a syntax error, or
it exceeds the length budget). Surfaced at admission so a bad expression
never reaches status (ADR-0004 §5).
Fields
IdentityExprEval
A Repository/ClusterRepository identityDefaults CEL expression
referenced a variable outside its environment (e.g. a typo), or otherwise
failed to evaluate at admission (ADR-0004 §5). The environment is
namespace, policyName, labels, annotations, cluster.
Fields
IdentityExprType
A Repository/ClusterRepository identityDefaults CEL expression
evaluated to a non-string value. hostnameExpr/usernameExpr must return
a string (ADR-0004 §5).
Fields
InsecureServerNotAcknowledged
spec.server.auth.insecure was selected without acknowledgeInsecure: true.
The no-auth server exposes full read/write/delete of the repository with no
login, so it must be explicitly acknowledged (server addendum).
InvalidServerPort
spec.server.service.port was set to an invalid value (0).
ServerNamespaceRequired
A ClusterRepository.spec.server did not set the required target namespace.
A label selector was supplied as the tenancy gate but the caller could not provide the consumer namespace’s labels to match against. We fail closed (deny) rather than guess (ADR §3.2 — the webhook never trusts unfiltered input).
Immutable
An UPDATE changed a repository field that is fixed at repository-creation
time (encryption, create.splitter, create.hash, create.encryption).
Kopia bakes these into the repository’s on-disk format, so they cannot change
after creation — the webhook rejects the edit rather than silently ignoring it
(ADR-0005 §7).
IdentityCollision
A SnapshotPolicy’s resolved kopia identity (username@hostname[:path])
collides with an already-admitted SnapshotPolicy’s identity in the same
repository. Two recipes interleaving snapshots into one kopia identity corrupts
the snapshot history, so the webhook rejects the second one (ADR-0005 §6).
Fields
IdentityComponentInvalid
A kopia identity component (username or hostname) — whether an explicit
spec.identity override or the value an identityDefaults CEL expression
resolved to — contains a character that breaks kopia’s
username@hostname:path contract. kopia parses a source on the first @
and first : with no escaping, so an embedded @, :, ASCII whitespace,
or control character silently misparses the identity into a different one
(or makes the snapshot un-findable on snapshot list --source). Rejected at
admission/resolution so it never reaches a mover Job. Shape-only — every other
character (dots, dashes, slashes, unicode letters) is allowed.
Fields
IdentitySourcePathInvalid
A kopia identity sourcePath is malformed — empty, or it contains a newline
or an ASCII control character. The path is everything after the first : in
username@hostname:path; it may legitimately contain spaces and further :,
but not control characters, and must be non-empty when set.
Fields
ClusterNameInvalid
A Repository/ClusterRepository identityDefaults.cluster is not a
valid RFC 1123 label, or contains a .. cluster is appended onto the namespace as
<namespace>.<cluster> for the default hostname, and
crate::identity::classify_hostname splits that hostname back apart at
the FIRST . — a cluster value with an embedded dot would just shift
which suffix classifies as “own cluster” rather than error, so the value is
rejected outright at admission instead of letting classification silently
disagree with intent.
Fields
IdentityWouldFork
An UPDATE to a SnapshotPolicy would change its resolved kopia identity
(username@hostname, or a source’s path) while the policy already has snapshot
history. New snapshots would land under the new kopia source: Kopiur’s own GFS
retention pools ALL of a policy’s Snapshot CRs regardless of identity, so the
old and new lineages don’t get independent retention — they compete for the same
keepLatest/keepDaily/etc. buckets in one merged timeline, and restore/verify/
fromPolicy resolve only the new identity (the old lineage stays reachable via
Restore.source.identity). Rejected unless the change is acknowledged with the
kopiur.home-operations.com/allow-identity-change annotation
(crate::consts::ALLOW_IDENTITY_CHANGE_ANNOTATION).
Fields
RepositoryIdentityWouldFork
An UPDATE to a Repository/ClusterRepository’s identityDefaults
(cluster, hostnameExpr, or usernameExpr) would silently re-identify
every consumer SnapshotPolicy that resolves through those defaults —
identity is re-resolved from the LIVE repository on every reconcile/backup
(nothing about a repository’s defaults is pinned the way a policy’s own
spec.identity is), so this edit changes what each affected policy
resolves to on its very next backup with no per-policy edit to
acknowledge it. Exactly like Self::IdentityWouldFork, new snapshots
would land under a new kopia lineage while the old lineage’s Snapshot
CRs keep competing with it in the same merged GFS retention timeline
(Kopiur pools a policy’s CRs regardless of identity, so nothing is
independently retained) — but here it happens fleet-wide in one apply.
Rejected unless the repository carries the
kopiur.home-operations.com/allow-identity-change annotation
(crate::consts::ALLOW_IDENTITY_CHANGE_ANNOTATION).
Fields
SuccessExprCompile
A verification successExpr (ADR-0005 §4/§15) failed to compile (a
syntax error, or it exceeds the length budget). Surfaced at admission.
Fields
SuccessExprEval
A verification successExpr referenced a variable outside its environment
(e.g. a typo), or otherwise failed to evaluate (ADR-0005 §4/§15). The
environment is stats{files,bytes,errors}, snapshot, restored.
Fields
SuccessExprType
A verification successExpr evaluated to a non-bool value. A successExpr
is a pass/fail predicate and must return a bool (ADR-0005 §4/§15).
Fields
PreflightExprCompile
A SnapshotPolicy.spec.preflight check expression failed to compile (CEL
syntax error, or it exceeds the length budget). Surfaced at admission.
Fields
PreflightExprEval
A preflight check expression referenced a variable outside its environment
(e.g. a typo), or otherwise failed to evaluate. The environment is the
repository and maintenance maps.
Fields
PreflightExprType
A preflight check expression evaluated to a non-bool value. A preflight check is a pass/fail predicate and must return a bool.
Fields
ReplicationDestinationSameAsSource
A RepositoryReplication’s destination backend is identical to its
source repository’s backend (ADR-0005 §13(d)) — replicating a repository to
itself is a no-op (or worse, a loop). The webhook rejects it.
MaintenanceNamespaceOnNamespacedRepo
A namespaced Repository set spec.maintenance.namespace, which only
applies to a cluster-scoped ClusterRepository (a namespaced
Repository’s managed Maintenance always lives in the repository’s own
namespace). ADR §3.7.
ForeignSnapshotsRequiresCluster
catalog.foreignSnapshots is set, but there is no cluster identity to
classify a snapshot’s origin against — Ignore/Fallback decide what
to do with a snapshot crate::identity::classify_hostname classifies
as another cluster’s, and that classification is undecidable without
identityDefaults.cluster. Fires on either repository kind (Repository
or ClusterRepository) whose identityDefaults.cluster is unset —
kind-neutral wording, since the rule is identical either way.
ForeignSnapshotsChoiceRequired
A ClusterRepository sets both identityDefaults.cluster and
catalog.fallbackNamespace but leaves catalog.foreignSnapshots
unset. Both being set at once is a strong signal the fallback
collector is actually relied upon, so adopting a cluster identity must
never silently switch it off by defaulting to Ignore — the choice is
forced explicit instead.
Trait Implementations§
Source§impl Clone for ValidationError
impl Clone for ValidationError
Source§fn clone(&self) -> ValidationError
fn clone(&self) -> ValidationError
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for ValidationError
impl Debug for ValidationError
Source§impl Display for ValidationError
impl Display for ValidationError
Source§impl Error for ValidationError
impl Error for ValidationError
1.30.0 · Source§fn source(&self) -> Option<&(dyn Error + 'static)>
fn source(&self) -> Option<&(dyn Error + 'static)>
1.0.0 · Source§fn description(&self) -> &str
fn description(&self) -> &str
use the Display impl or to_string()
Source§impl PartialEq for ValidationError
impl PartialEq for ValidationError
Source§fn eq(&self, other: &ValidationError) -> bool
fn eq(&self, other: &ValidationError) -> bool
self and other values to be equal, and is used by ==.impl Eq for ValidationError
impl StructuralPartialEq for ValidationError
Auto Trait Implementations§
impl Freeze for ValidationError
impl RefUnwindSafe for ValidationError
impl Send for ValidationError
impl Sync for ValidationError
impl Unpin for ValidationError
impl UnsafeUnpin for ValidationError
impl UnwindSafe for ValidationError
Blanket Implementations§
§impl<T> AnyExt for T
impl<T> AnyExt for T
§fn downcast_ref<T>(this: &Self) -> Option<&T>where
T: Any,
fn downcast_ref<T>(this: &Self) -> Option<&T>where
T: Any,
T behind reference§fn downcast_mut<T>(this: &mut Self) -> Option<&mut T>where
T: Any,
fn downcast_mut<T>(this: &mut Self) -> Option<&mut T>where
T: Any,
T behind mutable reference§fn downcast_rc<T>(this: Rc<Self>) -> Result<Rc<T>, Rc<Self>>where
T: Any,
fn downcast_rc<T>(this: Rc<Self>) -> Result<Rc<T>, Rc<Self>>where
T: Any,
T behind Rc pointer§fn downcast_arc<T>(this: Arc<Self>) -> Result<Arc<T>, Arc<Self>>where
T: Any,
fn downcast_arc<T>(this: Arc<Self>) -> Result<Arc<T>, Arc<Self>>where
T: Any,
T behind Arc pointer§fn downcast_box<T>(this: Box<Self>) -> Result<Box<T>, Box<Self>>where
T: Any,
fn downcast_box<T>(this: Box<Self>) -> Result<Box<T>, Box<Self>>where
T: Any,
T behind Box pointer§fn downcast_move<T>(this: Self) -> Option<T>
fn downcast_move<T>(this: Self) -> Option<T>
Self to T,
useful only in generic context as a workaround for specializationSource§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<T, X> CoerceTo<T> for Xwhere
T: CoerceFrom<X> + ?Sized,
impl<T, X> CoerceTo<T> for Xwhere
T: CoerceFrom<X> + ?Sized,
fn coerce_rc_to(self: Rc<X>) -> Rc<T>
fn coerce_box_to(self: Box<X>) -> Box<T>
fn coerce_ref_to(&self) -> &T
fn coerce_mut_to(&mut self) -> &mut T
§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more