1use crate::backend::Backend;
4use crate::common::{CacheDefaults, CatalogBounds, CreateBehavior, Encryption};
5use crate::maintenance::RepositoryMaintenanceSpec;
6use k8s_openapi::apimachinery::pkg::apis::meta::v1::Condition;
7use kube::CustomResource;
8use schemars::JsonSchema;
9use serde::{Deserialize, Serialize};
10
11#[derive(CustomResource, Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
15#[kube(
16 group = "kopiur.home-operations.com",
17 version = "v1alpha1",
18 kind = "Repository",
19 namespaced,
20 status = "RepositoryStatus",
21 shortname = "kopiarepo",
22 category = "kopiur",
23 printcolumn = r#"{"name":"Phase","type":"string","jsonPath":".status.phase"}"#,
24 printcolumn = r#"{"name":"Backend","type":"string","jsonPath":".status.backend"}"#,
25 printcolumn = r#"{"name":"Age","type":"date","jsonPath":".metadata.creationTimestamp"}"#
26)]
27#[serde(rename_all = "camelCase")]
28pub struct RepositorySpec {
29 pub backend: Backend,
31 pub encryption: Encryption,
34 #[serde(default, skip_serializing_if = "Option::is_none")]
38 pub create: Option<CreateBehavior>,
39 #[serde(default, skip_serializing_if = "Option::is_none")]
41 pub cache_defaults: Option<CacheDefaults>,
42 #[serde(default, skip_serializing_if = "Option::is_none")]
45 pub catalog: Option<CatalogBounds>,
46 #[serde(default, skip_serializing_if = "Option::is_none")]
50 pub maintenance: Option<RepositoryMaintenanceSpec>,
51}
52
53#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq, Default, JsonSchema)]
68pub enum RepositoryPhase {
69 #[default]
71 Pending,
72 Initializing,
74 Ready,
76 Degraded,
78 Failed,
80}
81
82impl crate::common::PhaseLabel for RepositoryPhase {
83 const ALL: &'static [Self] = &[
84 Self::Pending,
85 Self::Initializing,
86 Self::Ready,
87 Self::Degraded,
88 Self::Failed,
89 ];
90 fn label(&self) -> &'static str {
91 match self {
92 Self::Pending => "Pending",
93 Self::Initializing => "Initializing",
94 Self::Ready => "Ready",
95 Self::Degraded => "Degraded",
96 Self::Failed => "Failed",
97 }
98 }
99}
100
101#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default, JsonSchema)]
104#[serde(rename_all = "camelCase")]
105pub struct RepositoryStatus {
106 #[serde(default, skip_serializing_if = "Option::is_none")]
108 pub phase: Option<RepositoryPhase>,
109 #[serde(default, skip_serializing_if = "Option::is_none")]
111 pub observed_generation: Option<i64>,
112 #[serde(default, skip_serializing_if = "Option::is_none")]
114 pub unique_id: Option<String>,
115 #[serde(default, skip_serializing_if = "Option::is_none")]
117 pub backend: Option<String>,
118 #[serde(default, skip_serializing_if = "Option::is_none")]
120 pub storage_stats: Option<StorageStats>,
121 #[serde(default, skip_serializing_if = "Option::is_none")]
123 pub catalog: Option<CatalogStatus>,
124 #[serde(default, skip_serializing_if = "Vec::is_empty")]
126 pub conditions: Vec<Condition>,
127}
128
129#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Default, JsonSchema)]
131#[serde(rename_all = "camelCase")]
132pub struct StorageStats {
133 #[serde(default, skip_serializing_if = "Option::is_none")]
135 pub snapshot_count: Option<i64>,
136 #[serde(default, skip_serializing_if = "Option::is_none")]
138 pub total_size: Option<String>,
139 #[serde(default, skip_serializing_if = "Option::is_none")]
141 pub last_observed_at: Option<String>,
142}
143
144#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Default, JsonSchema)]
146#[serde(rename_all = "camelCase")]
147pub struct CatalogStatus {
148 #[serde(default, skip_serializing_if = "Option::is_none")]
150 pub discovered_backup_count: Option<i64>,
151 #[serde(default, skip_serializing_if = "Option::is_none")]
153 pub last_refresh_at: Option<String>,
154}