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_storage::ModelStorageKind;
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 = "ModelClaim",
17 root = "ModelClaimCrd",
18 status = "ModelClaimStatus",
19 shortname = "mc",
20 namespaced,
21 printcolumn = r#"{
22 "name": "sto`rage",
23 "type": "string",
24 "description": "attached storage name",
25 "jsonPath": ".spec.storageName"
26 }"#,
27 printcolumn = r#"{
28 "name": "state",
29 "type": "string",
30 "description": "state of the model claim",
31 "jsonPath": ".status.state"
32 }"#,
33 printcolumn = r#"{
34 "name": "created-at",
35 "type": "date",
36 "description": "created time",
37 "jsonPath": ".metadata.creationTimestamp"
38 }"#,
39 printcolumn = r#"{
40 "name": "updated-at",
41 "type": "date",
42 "description": "updated time",
43 "jsonPath": ".status.lastUpdated"
44 }"#,
45 printcolumn = r#"{
46 "name": "version",
47 "type": "integer",
48 "description": "model claim version",
49 "jsonPath": ".metadata.generation"
50 }"#,
51 )
52)]
53#[serde(rename_all = "camelCase")]
54pub struct ModelClaimSpec {
55 #[serde(default)]
56 pub affinity: ModelClaimAffinity,
57 #[serde(default = "ModelClaimSpec::default_allow_replacement")]
58 pub allow_replacement: bool,
59 #[serde(default)]
60 pub binding_policy: ModelClaimBindingPolicy,
61 #[serde(default)]
62 pub deletion_policy: ModelClaimDeletionPolicy,
63 #[serde(default)]
64 pub resources: Option<ResourceRequirements>,
65 #[serde(default)]
66 pub storage: Option<ModelStorageKind>,
67 #[serde(default)]
68 pub storage_name: Option<String>,
69}
70
71#[cfg(feature = "k8s")]
72impl ModelClaimCrd {
73 pub const FINALIZER_NAME: &'static str = "cdl.ulagbulag.io/finalizer-model-claims";
74}
75
76impl Default for ModelClaimSpec {
77 fn default() -> Self {
78 Self {
79 affinity: ModelClaimAffinity::default(),
80 allow_replacement: Self::default_allow_replacement(),
81 binding_policy: ModelClaimBindingPolicy::default(),
82 deletion_policy: ModelClaimDeletionPolicy::default(),
83 resources: None,
84 storage: None,
85 storage_name: None,
86 }
87 }
88}
89
90impl ModelClaimSpec {
91 const fn default_allow_replacement() -> bool {
92 true
93 }
94}
95
96#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
97#[serde(rename_all = "camelCase")]
98pub struct ModelClaimAffinity {
99 #[serde(default)]
100 pub placement_affinity: ModelClaimAffinityRequirements,
101 #[serde(default)]
102 pub replacement_affinity: ModelClaimAffinityRequirements,
103}
104
105#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
106#[serde(rename_all = "camelCase")]
107pub struct ModelClaimAffinityRequirements {
108 #[serde(default)]
109 pub preferred: Vec<ModelClaimPreferredAffinity>,
110 #[serde(default)]
111 pub required: Vec<ModelClaimAffinityPreference>,
112}
113
114#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
115#[serde(rename_all = "camelCase")]
116pub struct ModelClaimPreferredAffinity {
117 #[serde(default, flatten)]
118 pub base: ModelClaimAffinityPreference,
119 pub weight: u8,
120}
121
122#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
123#[serde(rename_all = "camelCase")]
124pub struct ModelClaimAffinityPreference {
125 #[serde(default)]
126 pub match_expressions: Vec<ModelClaimAffinityExpression>,
127}
128
129#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
130#[serde(rename_all = "camelCase")]
131pub struct ModelClaimAffinityExpression {
132 pub query: String,
133 #[serde(default)]
134 pub source: ModelClaimAffinityExpressionSource,
135}
136
137#[derive(
138 Copy,
139 Clone,
140 Debug,
141 Display,
142 Default,
143 EnumString,
144 PartialEq,
145 Eq,
146 PartialOrd,
147 Ord,
148 Hash,
149 Serialize,
150 Deserialize,
151 JsonSchema,
152)]
153pub enum ModelClaimAffinityExpressionSource {
154 #[default]
155 Prometheus,
156}
157
158#[derive(
159 Copy,
160 Clone,
161 Debug,
162 Display,
163 Default,
164 EnumString,
165 PartialEq,
166 Eq,
167 PartialOrd,
168 Ord,
169 Hash,
170 Serialize,
171 Deserialize,
172 JsonSchema,
173)]
174pub enum ModelClaimBindingPolicy {
175 Balanced,
176 #[default]
177 LowestCopy,
178 LowestLatency,
179}
180
181#[derive(
182 Copy,
183 Clone,
184 Debug,
185 Display,
186 Default,
187 EnumString,
188 PartialEq,
189 Eq,
190 PartialOrd,
191 Ord,
192 Hash,
193 Serialize,
194 Deserialize,
195 JsonSchema,
196)]
197pub enum ModelClaimDeletionPolicy {
198 Delete,
199 #[default]
200 Retain,
201}
202
203#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
204#[serde(rename_all = "camelCase")]
205pub struct ModelClaimStatus {
206 #[serde(default)]
207 pub state: ModelClaimState,
208 #[serde(default)]
209 pub resources: Option<ResourceRequirements>,
210 #[serde(default)]
211 pub storage: Option<ModelStorageKind>,
212 #[serde(default)]
213 pub storage_name: Option<String>,
214 pub last_updated: DateTime<Utc>,
215}
216
217#[derive(
218 Copy,
219 Clone,
220 Debug,
221 Display,
222 Default,
223 EnumString,
224 PartialEq,
225 Eq,
226 PartialOrd,
227 Ord,
228 Hash,
229 Serialize,
230 Deserialize,
231 JsonSchema,
232)]
233pub enum ModelClaimState {
234 #[default]
235 Pending,
236 Ready,
237 Replacing,
238 Deleting,
239}