1use chrono::{DateTime, Utc};
2use k8s_openapi::api::core::v1::ResourceRequirements;
3use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5use strum::{Display, EnumString};
6
7use crate::{model::ModelSpec, model_storage::ModelStorageSpec};
8
9#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
10#[cfg_attr(feature = "k8s", derive(::kube::CustomResource))]
11#[cfg_attr(
12 feature = "k8s",
13 kube(
14 group = "cdl.ulagbulag.io",
15 version = "v1alpha1",
16 kind = "ModelStorageBinding",
17 root = "ModelStorageBindingCrd",
18 status = "ModelStorageBindingStatus",
19 shortname = "msb",
20 namespaced,
21 printcolumn = r#"{
22 "name": "state",
23 "type": "string",
24 "description": "state of the binding",
25 "jsonPath": ".status.state"
26 }"#,
27 printcolumn = r#"{
28 "name": "created-at",
29 "type": "date",
30 "description": "created time",
31 "jsonPath": ".metadata.creationTimestamp"
32 }"#,
33 printcolumn = r#"{
34 "name": "updated-at",
35 "type": "date",
36 "description": "updated time",
37 "jsonPath": ".status.lastUpdated"
38 }"#,
39 printcolumn = r#"{
40 "name": "version",
41 "type": "integer",
42 "description": "binding version",
43 "jsonPath": ".metadata.generation"
44 }"#,
45 )
46)]
47#[serde(rename_all = "camelCase")]
48pub struct ModelStorageBindingSpec {
49 #[serde(default)]
50 pub deletion_policy: ModelStorageBindingDeletionPolicy,
51 pub model: String,
52 #[serde(default)]
53 pub resources: Option<ResourceRequirements>,
54 pub storage: ModelStorageBindingStorageKind<String>,
55}
56
57#[cfg(feature = "k8s")]
58impl ModelStorageBindingCrd {
59 pub const FINALIZER_NAME: &'static str = "cdl.ulagbulag.io/finalizer-model-storage-bindings";
60}
61
62#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
63#[serde(rename_all = "camelCase")]
64pub enum ModelStorageBindingStorageKind<Storage> {
65 Cloned(ModelStorageBindingStorageKindClonedSpec<Storage>),
66 Owned(ModelStorageBindingStorageKindOwnedSpec<Storage>),
67}
68
69impl<Storage> ModelStorageBindingStorageKind<Storage> {
70 pub fn source(&self) -> Option<(&Storage, ModelStorageBindingSyncPolicy)> {
71 match self {
72 Self::Cloned(spec) => Some((&spec.source, spec.sync_policy)),
73 Self::Owned(_) => None,
74 }
75 }
76
77 pub fn source_binding_name(&self) -> Option<&str> {
78 match self {
79 Self::Cloned(spec) => spec.source_binding_name.as_deref(),
80 Self::Owned(_) => None,
81 }
82 }
83
84 pub fn sync_policy(&self) -> Option<ModelStorageBindingSyncPolicy> {
85 match self {
86 Self::Cloned(spec) => Some(spec.sync_policy),
87 Self::Owned(_) => None,
88 }
89 }
90
91 pub fn target(&self) -> &Storage {
92 match self {
93 Self::Cloned(spec) => &spec.target,
94 Self::Owned(spec) => &spec.target,
95 }
96 }
97
98 pub fn into_target(self) -> Storage {
99 match self {
100 Self::Cloned(spec) => spec.target,
101 Self::Owned(spec) => spec.target,
102 }
103 }
104}
105
106#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
107#[serde(rename_all = "camelCase")]
108pub struct ModelStorageBindingStorageKindClonedSpec<Storage> {
109 pub source: Storage,
110 #[serde(default)]
111 pub source_binding_name: Option<String>,
112 pub target: Storage,
113 #[serde(default)]
114 pub sync_policy: ModelStorageBindingSyncPolicy,
115}
116
117#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
118#[serde(rename_all = "camelCase")]
119pub struct ModelStorageBindingStorageSpec<'name, Storage> {
120 pub source: Option<ModelStorageBindingStorageSourceSpec<'name, Storage>>,
121 pub source_binding_name: Option<&'name str>,
122 pub target: Storage,
123 pub target_name: &'name str,
124}
125
126#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
127#[serde(rename_all = "camelCase")]
128pub struct ModelStorageBindingStorageSourceSpec<'name, Storage> {
129 pub name: &'name str,
130 pub storage: Storage,
131 pub sync_policy: ModelStorageBindingSyncPolicy,
132}
133
134impl<'name, Storage> ModelStorageBindingStorageSourceSpec<'name, Storage> {
135 pub fn as_deref(&self) -> ModelStorageBindingStorageSourceSpec<'name, &'_ Storage> {
136 ModelStorageBindingStorageSourceSpec {
137 name: self.name,
138 storage: &self.storage,
139 sync_policy: self.sync_policy,
140 }
141 }
142}
143
144#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
145#[serde(rename_all = "camelCase")]
146pub struct ModelStorageBindingStorageKindOwnedSpec<Storage> {
147 pub target: Storage,
148}
149
150#[derive(
151 Copy,
152 Clone,
153 Debug,
154 Default,
155 PartialEq,
156 Eq,
157 PartialOrd,
158 Ord,
159 Hash,
160 Serialize,
161 Deserialize,
162 JsonSchema,
163)]
164#[serde(rename_all = "camelCase")]
165pub struct ModelStorageBindingSyncPolicy {
166 #[serde(default)]
167 pub pull: ModelStorageBindingSyncPolicyPull,
168 #[serde(default)]
169 pub push: ModelStorageBindingSyncPolicyPush,
170}
171
172impl ModelStorageBindingSyncPolicy {
173 pub fn is_none(&self) -> bool {
174 self.pull == ModelStorageBindingSyncPolicyPull::Never
175 && self.push == ModelStorageBindingSyncPolicyPush::Never
176 }
177}
178
179#[derive(
180 Copy,
181 Clone,
182 Debug,
183 Display,
184 Default,
185 EnumString,
186 PartialEq,
187 Eq,
188 PartialOrd,
189 Ord,
190 Hash,
191 Serialize,
192 Deserialize,
193 JsonSchema,
194)]
195pub enum ModelStorageBindingSyncPolicyPull {
196 #[default]
197 Always,
198 OnCreate,
199 Never,
200}
201
202#[derive(
203 Copy,
204 Clone,
205 Debug,
206 Display,
207 Default,
208 EnumString,
209 PartialEq,
210 Eq,
211 PartialOrd,
212 Ord,
213 Hash,
214 Serialize,
215 Deserialize,
216 JsonSchema,
217)]
218pub enum ModelStorageBindingSyncPolicyPush {
219 #[default]
220 Always,
221 OnDelete,
222 Never,
223}
224
225#[derive(
226 Copy,
227 Clone,
228 Debug,
229 Display,
230 Default,
231 EnumString,
232 PartialEq,
233 Eq,
234 PartialOrd,
235 Ord,
236 Hash,
237 Serialize,
238 Deserialize,
239 JsonSchema,
240)]
241pub enum ModelStorageBindingDeletionPolicy {
242 Delete,
243 #[default]
244 Retain,
245}
246
247#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
248#[serde(rename_all = "camelCase")]
249pub struct ModelStorageBindingStatus {
250 #[serde(default)]
251 pub state: ModelStorageBindingState,
252 #[serde(default)]
253 pub deletion_policy: ModelStorageBindingDeletionPolicy,
254 #[serde(default)]
255 pub model: Option<ModelSpec>,
256 #[serde(default)]
257 pub model_name: Option<String>,
258 #[serde(default)]
259 pub resources: Option<ResourceRequirements>,
260 #[serde(default)]
261 pub storage_source: Option<ModelStorageSpec>,
262 #[serde(default)]
263 pub storage_source_binding_name: Option<String>,
264 #[serde(default)]
265 pub storage_source_name: Option<String>,
266 #[serde(default)]
267 pub storage_source_uid: Option<String>,
268 #[serde(default)]
269 pub storage_sync_policy: Option<ModelStorageBindingSyncPolicy>,
270 #[serde(default)]
271 pub storage_target: Option<ModelStorageSpec>,
272 #[serde(default)]
273 pub storage_target_name: Option<String>,
274 #[serde(default)]
275 pub storage_target_uid: Option<String>,
276 pub last_updated: DateTime<Utc>,
277}
278
279#[derive(
280 Copy,
281 Clone,
282 Debug,
283 Display,
284 Default,
285 EnumString,
286 PartialEq,
287 Eq,
288 PartialOrd,
289 Ord,
290 Hash,
291 Serialize,
292 Deserialize,
293 JsonSchema,
294)]
295pub enum ModelStorageBindingState {
296 #[default]
297 Pending,
298 Ready,
299 Deleting,
300}