Skip to main content

Crate kopiur_api

Crate kopiur_api 

Source
Expand description

§kopiur-api

Strongly-typed CRD definitions and shared, controller-free logic for Kopiur, the Kopia-native Kubernetes backup operator (ADR-0003).

§Role in the workspace

This crate holds the 7 CRD types in API group kopiur.home-operations.com, version v1alpha1Repository (ns), ClusterRepository (cluster), SnapshotPolicy, Snapshot, SnapshotSchedule, Restore, and Maintenance — together with the shared pure logic every consumer needs: validation (validate), identity resolution (resolve_identity), schedule jitter (jitter), and GFS retention (select_kept).

It deliberately has no controller-runtime dependencies — no kube::Client, no tokio. Downstream tools (a custom backup-triggering controller, a CI linter for SnapshotPolicy manifests, a dashboard) can depend on the API types and shared logic alone, without pulling in the async runtime or the cluster client (ADR §5.1). The webhook and the controller both import the same validate/ identity/retention functions, so validation and resolution behave identically across call sites (“one validator, two callers”).

§The load-bearing idea: type-safety end-to-end (ADR §5.5)

Every discriminated union in the CRD surface is a Rust enum: Backend, AllowedNamespaces, DeletionPolicy, RestoreSource, Hook, and friends.

A deserialized value is always exactly one variant — an invalid “two backends at once” or “no backend” state is unrepresentable — and reconcilers match exhaustively. A new variant added later cannot compile until every handler accounts for it. For backup software, where a silently-unhandled case can lose user data, this eliminates the highest-severity class of “controller silently dropped data” bugs. This is the whole reason Kopiur is Rust and not Go; preserve this property in every change (prefer an enum + exhaustive match over if let / _ => catch-alls).

§Key types

TypePurpose
Repository / ClusterRepositoryThe kopia repository as a first-class resource (namespaced / cluster-scoped).
BackendThe storage backend union (s3, azure, gcs, b2, filesystem, sftp, webDav, rclone).
SnapshotPolicyThe backup recipe (sources, retention, hooks).
SnapshotA single backup invocation, owning its snapshot via finalizer.
SnapshotScheduleThe schedule that emits Snapshots on a cron.
RestoreA restore request (RestoreSource / RestoreTarget).
Maintenancekopia maintenance as a first-class, default-managed concern.
DeletionPolicyDelete / Retain / Orphan — ties snapshot lifecycle to the CR.

Shared pure logic (no controller deps):

FunctionPurpose
resolve_identityRender the kopia username@hostname:path identity, pinned to status at admission.
select_keptGFS retention: decide which backups to keep.
jitter_offset / substitute_hDeterministic H/jitter from (scheduleUID, slot).

§Conventions

Before editing this crate, read docs/dev/api-conventions.md. The load-bearing rules:

  • Discriminated unions are externally-tagged enums (backend: { s3: {...} }), not #[serde(tag = "...")] — internally-tagged enums break Kubernetes structural-schema generation.
  • No Eq on structs that embed k8s-openapi types (LabelSelector, ResourceRequirements, SecurityContext, …) — they are PartialEq only.
  • Sub-objects, not leaf fields, for every credential/policy/identity/schedule surface, so future fields slot in without API breakage.

§Usage

Construct or deserialize a Backend the way the API server does (JSON value → typed) and match it exhaustively:

use kopiur_api::Backend;

// External tagging: the variant key selects exactly one backend.
let backend: Backend = serde_json::from_value(serde_json::json!({
    "s3": { "bucket": "my-backups", "region": "us-east-1" }
}))
.unwrap();

// A deserialized Backend is always exactly one variant -> exhaustive match.
let summary = match &backend {
    Backend::S3(s3) => format!("s3://{}", s3.bucket),
    Backend::Azure(_) => "azure".into(),
    Backend::Gcs(_) => "gcs".into(),
    Backend::B2(_) => "b2".into(),
    Backend::Filesystem(_) => "filesystem".into(),
    Backend::Sftp(_) => "sftp".into(),
    Backend::WebDav(_) => "webdav".into(),
    Backend::Rclone(_) => "rclone".into(),
    Backend::Gdrive(_) => "gdrive".into(),
};
assert_eq!(summary, "s3://my-backups");

// The stable discriminant is independent of the camelCase wire key.
assert_eq!(backend.kind_str(), "S3");

Note: deserialize via serde_json (the API-server path), never serde_yaml directly into a typed value — serde_yaml 0.9 mis-encodes externally-tagged enums. For YAML tests, go YAML → serde_json::Value → typed.

§See also

Re-exports§

pub use backend::Backend;
pub use backend::NfsVolume;
pub use backend::PvcVolume;
pub use backend::RepoVolume;
pub use cluster_repository::AllowedNamespaces;
pub use cluster_repository::ClusterRepoCredentialProjection;
pub use cluster_repository::ClusterRepository;
pub use cluster_repository::ClusterRepositorySpec;
pub use cluster_repository::ClusterRepositoryStatus;
pub use common::CacheDefaults;
pub use common::CacheVolumeMode;
pub use common::CronSpec;
pub use common::DeletionPolicy;
pub use common::IdentityDefaults;
pub use common::InheritSecurityContextFrom;
pub use common::MoverDefaults;
pub use common::NamespaceDeletePolicy;
pub use common::ObjectRef;
pub use common::PhaseLabel;
pub use common::PodSelector;
pub use common::PolicyRef;
pub use common::PvcConsumerInherit;
pub use common::ResolvedMover;
pub use common::SourceColocation;
pub use common::SourceColocationMode;
pub use common::effective_run_as_group;
pub use common::effective_run_as_user;
pub use common::hardened_security_context;
pub use common::merge_context_pair;
pub use common::merge_pod_security_context;
pub use common::merge_resources;
pub use common::merge_security_context;
pub use common::resolve_mover;
pub use maintenance::LeaseAction;
pub use maintenance::Maintenance;
pub use maintenance::MaintenanceSchedule;
pub use maintenance::MaintenanceSpec;
pub use maintenance::MaintenanceStatus;
pub use maintenance::ManualRunMode;
pub use maintenance::ManualRunPhase;
pub use maintenance::ManualRunStatus;
pub use maintenance::Ownership;
pub use maintenance::RepositoryMaintenanceSpec;
pub use maintenance::TakeoverPolicy;
pub use maintenance::default_maintenance_schedule;
pub use maintenance::kopia_lease_identity;
pub use maintenance::kopia_owner_for_lease;
pub use maintenance::lease_action;
pub use maintenance::lease_held_by_other;
pub use maintenance::managed_lease;
pub use maintenance::parse_run_annotations;
pub use repository::Repository;
pub use repository::RepositoryPhase;
pub use repository::RepositorySpec;
pub use repository::RepositoryStatus;
pub use repository_replication::RepositoryReplication;
pub use repository_replication::RepositoryReplicationPhase;
pub use repository_replication::RepositoryReplicationSpec;
pub use repository_replication::RepositoryReplicationStatus;
pub use restore::OnMissingSnapshot;
pub use restore::PopulatorTarget;
pub use restore::ResolutionOutcome;
pub use restore::Restore;
pub use restore::RestorePhase;
pub use restore::RestoreSource;
pub use restore::RestoreSpec;
pub use restore::RestoreStatus;
pub use restore::RestoreTarget;
pub use server::ClusterServerSpec;
pub use server::ServerAuth;
pub use server::ServerService;
pub use server::ServerSpec;
pub use server::ServerStatus;
pub use server::ServiceType;
pub use snapshot::Origin;
pub use snapshot::Snapshot;
pub use snapshot::SnapshotPhase;
pub use snapshot::SnapshotSpec;
pub use snapshot::SnapshotStats;
pub use snapshot::SnapshotStatus;
pub use snapshot::SnapshotTiming;
pub use snapshot::StagedSources;
pub use snapshot_policy::CopyMethod;
pub use snapshot_policy::DeepVerification;
pub use snapshot_policy::GroupBy;
pub use snapshot_policy::Hook;
pub use snapshot_policy::SnapshotPolicy;
pub use snapshot_policy::SnapshotPolicySpec;
pub use snapshot_policy::SnapshotPolicyStatus;
pub use snapshot_policy::SourcePathStrategy;
pub use snapshot_policy::StagingSpec;
pub use snapshot_policy::Verification;
pub use snapshot_schedule::ConcurrencyPolicy;
pub use snapshot_schedule::ScheduleSpec;
pub use snapshot_schedule::SnapshotSchedule;
pub use snapshot_schedule::SnapshotScheduleSpec;
pub use snapshot_schedule::SnapshotScheduleStatus;
pub use duration::parse_go_duration;
pub use duration::render_go_duration;
pub use duration::resolve_timeout;
pub use error::ValidationError;
pub use error::ValidationResult;
pub use identity::HostClass;
pub use identity::IdentityInputs;
pub use identity::classify_hostname;
pub use identity::identity_string;
pub use identity::resolve_identity;
pub use identity::validate_identity_expr;
pub use jitter::offset as jitter_offset;
pub use jitter::substitute_h;
pub use preflight::PreflightCheck;
pub use preflight::PreflightInputs;
pub use preflight::PreflightSpec;
pub use preflight::eval_preflight_expr;
pub use preflight::validate_preflight_expr;
pub use recorded::KOPIUR_META_SCHEMA_V1;
pub use recorded::KOPIUR_META_TAG;
pub use recorded::MetaTagDecode;
pub use recorded::RecordedSnapshotMeta;
pub use recorded::RecordedSrc;
pub use recorded::decode_meta_tag;
pub use recorded::encode_meta_tag;
pub use retention::KeptSet;
pub use retention::SnapshotLike;
pub use retention::select_kept;
pub use success_expr::RestoredStats;
pub use success_expr::SuccessExprInputs;
pub use success_expr::VerifyStats;
pub use success_expr::eval_success_expr;
pub use success_expr::validate_success_expr;

Modules§

backend
Storage backends for a kopia repository.
cluster_repository
The ClusterRepository CRD — a cluster-scoped, shared kopia repository operated by a platform team. ADR-0001 §3.2, ADR-0003 §3.2.
common
Shared sub-objects reused across multiple CRDs.
consts
Well-known wire-contract strings: the finalizer, labels, annotations, and condition types that form kopiur’s public Kubernetes surface (ADR §4.5, ADR-0005 §2/§14(c)).
creds
Pure credential/volume metadata over the CRD types: which Secrets a repository’s mover needs. Shared by the controller (envFrom projection, referent watches) and external tooling (kubectl kopiur doctor), so the “what credentials does this backend reference” answer cannot fork.
duration
Go-style duration strings used across the CRDs (30m, 1h, 90s).
error
Typed validation errors shared by the admission webhook and the controller.
identity
Kopia identity resolution (ADR §4.2).
invariants
Security-context invariants for the resolved mover pod.
jitter
Deterministic schedule jitter and Jenkins-style H substitution (ADR §4.1).
maintenance
The Maintenance CRD — schedules kopia maintenance run quick + full and manages the ownership lease. At most one per repository. ADR-0001 §3.7.
preflight
Backup preflight: user-declared CEL preconditions a Snapshot must satisfy before its mover Job is launched (the “stronger preflight” of docs/repository-health.md).
recorded
Recorded snapshot metadata — the kopiur-meta kopia tag.
repository
The Repository CRD — a namespaced kopia repository. ADR-0003 §3.1.
repository_replication
The RepositoryReplication CRD — mirror a repository’s blobs to a second backend on a schedule (ADR-0005 §13(d)). The one net-new CRD: it is the “2” in 3-2-1 backup, wrapping kopia repository sync-to.
restore
The Restore CRD — a restore from a snapshot/identity to a PVC, or a passive populator source. ADR-0001 §3.6, ADR-0003 §4.6.
retention
Grandfather-father-son (GFS) retention selection (ADR §4.4).
schema
Schema helper for embedding a large Kubernetes core/v1 sub-object.
secctx_compat
Pure, controller-free reasoning about whether a mover’s resolved security context can read a backup source PVC, and the inverse — whether a future workload can read what a restore mover writes to a target PVC.
server
Optional kopia web-UI server surface for Repository / ClusterRepository.
snapshot
The Snapshot CRD — a single kopia snapshot as a Kubernetes object. ADR-0001 §3.4, ADR-0003 §4.5.
snapshot_policy
The SnapshotPolicy CRD — the recipe. Idempotent; runs nothing on its own. ADR-0001 §3.3, ADR-0003 §4.8.
snapshot_schedule
The SnapshotSchedule CRD — when a backup runs. Creates Snapshot CRs on a cron schedule in the SnapshotPolicy’s namespace. ADR-0001 §3.5, ADR-0003 §4.4.
success_expr
successExpr: a sandboxed CEL pass/fail predicate over a verification result (ADR-0005 §4/§15).
validate
Cross-field validation the type system can’t express (ADR §2.2 principle 8).

Constants§

GROUP
The CRD API group for all kopiur resources.
VERSION
The current (and only, per ADR §8) API version.