1use std::collections::BTreeMap;
2use std::collections::HashMap;
3use std::fmt;
4use std::fmt::Debug;
5use std::marker::PhantomData;
6
7use serde::de::{DeserializeOwned, Deserializer};
8use serde::Deserialize;
9use serde::Serialize;
10
11use crate::Spec;
12
13pub const DEFAULT_NS: &str = "default";
14pub const TYPE_OPAQUE: &str = "Opaque";
15
16pub trait K8Meta {
17 fn name(&self) -> &str;
19
20 fn namespace(&self) -> &str;
22}
23
24pub trait LabelProvider: Sized {
25 fn set_label_map(self, labels: HashMap<String, String>) -> Self;
26
27 fn set_labels<T: ToString>(self, labels: Vec<(T, T)>) -> Self {
29 let mut label_map = HashMap::new();
30 for (key, value) in labels {
31 label_map.insert(key.to_string(), value.to_string());
32 }
33 self.set_label_map(label_map)
34 }
35}
36
37#[derive(Deserialize, Serialize, PartialEq, Debug, Default, Clone)]
40#[serde(rename_all = "camelCase", default)]
41pub struct ObjectMeta {
42 pub name: String,
44 pub namespace: String,
45 pub uid: String,
46 pub creation_timestamp: String,
47 pub generation: Option<i32>,
48 pub resource_version: String,
49 pub cluster_name: Option<String>,
51 pub deletion_timestamp: Option<String>,
52 pub deletion_grace_period_seconds: Option<u32>,
53 pub labels: HashMap<String, String>,
54 pub owner_references: Vec<OwnerReferences>,
55 pub annotations: HashMap<String, String>,
56 pub finalizers: Vec<String>,
57}
58
59impl LabelProvider for ObjectMeta {
60 fn set_label_map(mut self, labels: HashMap<String, String>) -> Self {
61 self.labels = labels;
62 self
63 }
64}
65
66impl K8Meta for ObjectMeta {
67 fn name(&self) -> &str {
68 &self.name
69 }
70
71 fn namespace(&self) -> &str {
72 &self.namespace
73 }
74}
75
76impl ObjectMeta {
77 pub fn new<S>(name: S, name_space: S) -> Self
78 where
79 S: Into<String>,
80 {
81 Self {
82 name: name.into(),
83 namespace: name_space.into(),
84 ..Default::default()
85 }
86 }
87
88 pub fn set_labels<T: Into<String>>(mut self, labels: Vec<(T, T)>) -> Self {
90 let mut label_map = HashMap::new();
91 for (key, value) in labels {
92 label_map.insert(key.into(), value.into());
93 }
94 self.labels = label_map;
95 self
96 }
97
98 pub fn named<S>(name: S) -> Self
100 where
101 S: Into<String>,
102 {
103 Self {
104 name: name.into(),
105 ..Default::default()
106 }
107 }
108
109 pub fn make_owner_reference<S: Spec>(&self) -> OwnerReferences {
112 OwnerReferences {
113 kind: S::kind(),
114 name: self.name.clone(),
115 uid: self.uid.clone(),
116 ..Default::default()
118 }
119 }
120
121 pub fn namespace(&self) -> &str {
122 &self.namespace
123 }
124
125 pub fn make_child_input_metadata<S: Spec>(&self, childname: String) -> InputObjectMeta {
127 let mut owner_refs: Vec<OwnerReferences> = vec![];
128 owner_refs.push(self.make_owner_reference::<S>());
129
130 InputObjectMeta {
131 name: childname,
132 namespace: self.namespace().to_owned(),
133 owner_references: owner_refs,
134 ..Default::default()
135 }
136 }
137
138 pub fn as_input(&self) -> InputObjectMeta {
139 InputObjectMeta {
140 name: self.name.clone(),
141 namespace: self.namespace.clone(),
142 ..Default::default()
143 }
144 }
145
146 pub fn as_item(&self) -> ItemMeta {
147 ItemMeta {
148 name: self.name.clone(),
149 namespace: self.namespace.clone(),
150 }
151 }
152
153 pub fn as_update(&self) -> UpdateItemMeta {
154 UpdateItemMeta {
155 name: self.name.clone(),
156 namespace: self.namespace.clone(),
157 resource_version: self.resource_version.clone(),
158 }
159 }
160}
161
162#[derive(Deserialize, Serialize, Debug, Default, Clone)]
163#[serde(rename_all = "camelCase")]
164pub struct InputObjectMeta {
165 pub name: String,
166 pub labels: HashMap<String, String>,
167 pub namespace: String,
168 pub owner_references: Vec<OwnerReferences>,
169 pub finalizers: Vec<String>,
170 pub annotations: HashMap<String, String>,
171}
172
173impl LabelProvider for InputObjectMeta {
174 fn set_label_map(mut self, labels: HashMap<String, String>) -> Self {
175 self.labels = labels;
176 self
177 }
178}
179
180impl fmt::Display for InputObjectMeta {
181 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
182 write!(f, "{}:{}", self.name, self.namespace)
183 }
184}
185
186impl K8Meta for InputObjectMeta {
187 fn name(&self) -> &str {
188 &self.name
189 }
190
191 fn namespace(&self) -> &str {
192 &self.namespace
193 }
194}
195
196impl InputObjectMeta {
197 pub fn named<S: Into<String>>(name: S, namespace: S) -> Self {
199 InputObjectMeta {
200 name: name.into(),
201 namespace: namespace.into(),
202 ..Default::default()
203 }
204 }
205}
206
207impl From<ObjectMeta> for InputObjectMeta {
208 fn from(meta: ObjectMeta) -> Self {
209 Self {
210 name: meta.name,
211 namespace: meta.namespace,
212 ..Default::default()
213 }
214 }
215}
216
217#[derive(Deserialize, Serialize, Debug, Default, Clone)]
219#[serde(rename_all = "camelCase")]
220pub struct ItemMeta {
221 pub name: String,
222 pub namespace: String,
223}
224
225impl From<ObjectMeta> for ItemMeta {
226 fn from(meta: ObjectMeta) -> Self {
227 Self {
228 name: meta.name,
229 namespace: meta.namespace,
230 }
231 }
232}
233
234#[derive(Deserialize, Serialize, Debug, Default, Clone)]
236#[serde(rename_all = "camelCase")]
237pub struct UpdateItemMeta {
238 pub name: String,
239 pub namespace: String,
240 pub resource_version: String,
241}
242
243impl From<ObjectMeta> for UpdateItemMeta {
244 fn from(meta: ObjectMeta) -> Self {
245 Self {
246 name: meta.name,
247 namespace: meta.namespace,
248 resource_version: meta.resource_version,
249 }
250 }
251}
252
253#[derive(Deserialize, Serialize, Debug, Clone, PartialEq)]
254#[serde(rename_all = "camelCase")]
255pub struct OwnerReferences {
256 pub api_version: String,
257 #[serde(default)]
258 pub block_owner_deletion: bool,
259 pub controller: Option<bool>,
260 pub kind: String,
261 pub name: String,
262 pub uid: String,
263}
264
265impl Default for OwnerReferences {
266 fn default() -> Self {
267 Self {
268 api_version: "v1".to_owned(),
269 block_owner_deletion: false,
270 controller: None,
271 kind: "".to_owned(),
272 uid: "".to_owned(),
273 name: "".to_owned(),
274 }
275 }
276}
277
278#[derive(Debug, Clone)]
279pub enum DeleteStatus<S>
280where
281 S: Spec,
282{
283 Deleted(DeletedStatus),
284 ForegroundDelete(K8Obj<S>),
285}
286
287#[derive(Deserialize, Debug, Clone)]
289#[serde(rename_all = "camelCase")]
290pub struct DeletedStatus {
291 pub api_version: String,
292 pub code: Option<u16>,
293 pub details: Option<StatusDetails>,
294 pub kind: String,
295 pub message: Option<String>,
296 pub reason: Option<String>,
297 pub status: StatusEnum,
298}
299
300#[derive(Deserialize, Debug, Eq, PartialEq, Clone)]
302pub enum StatusEnum {
303 #[serde(rename = "Success")]
304 SUCCESS,
305 #[serde(rename = "Failure")]
306 FAILURE,
307}
308
309#[derive(Deserialize, Serialize, Debug, Clone)]
315pub struct StatusDetails {
316 pub name: String,
317 pub group: Option<String>,
318 pub kind: String,
319 pub uid: String,
320}
321
322#[derive(Deserialize, Serialize, Debug, Default, Clone)]
323#[serde(rename_all = "camelCase")]
324#[serde(bound(serialize = "S: Serialize"))]
325#[serde(bound(deserialize = "S: DeserializeOwned"))]
326pub struct K8Obj<S>
327where
328 S: Spec,
329{
330 #[serde(default = "S::api_version")]
331 pub api_version: String,
332 #[serde(default = "S::kind")]
333 pub kind: String,
334 #[serde(default)]
335 pub metadata: ObjectMeta,
336 #[serde(default)]
337 pub spec: S,
338 #[serde(flatten)]
339 pub header: S::Header,
340 #[serde(default)]
341 pub status: S::Status,
342}
343
344impl<S> K8Obj<S>
345where
346 S: Spec,
347{
348 #[allow(dead_code)]
349 pub fn new<N>(name: N, spec: S) -> Self
350 where
351 N: Into<String>,
352 {
353 Self {
354 api_version: S::api_version(),
355 kind: S::kind(),
356 metadata: ObjectMeta::named(name),
357 spec,
358 ..Default::default()
359 }
360 }
361
362 #[allow(dead_code)]
363 pub fn set_status(mut self, status: S::Status) -> Self {
364 self.status = status;
365 self
366 }
367
368 pub fn as_status_update(&self, status: S::Status) -> UpdateK8ObjStatus<S> {
369 UpdateK8ObjStatus {
370 api_version: S::api_version(),
371 kind: S::kind(),
372 metadata: self.metadata.as_update(),
373 status,
374 ..Default::default()
375 }
376 }
377}
378
379impl<S> K8Obj<S>
380where
381 S: Spec,
382{
383 pub fn as_input(&self) -> InputK8Obj<S> {
384 K8SpecObj {
385 api_version: self.api_version.clone(),
386 kind: self.kind.clone(),
387 metadata: self.metadata.as_input(),
388 spec: self.spec.clone(),
389 ..Default::default()
390 }
391 }
392}
393
394#[derive(Deserialize, Serialize, Debug, Default, Clone)]
396#[serde(rename_all = "camelCase")]
397pub struct K8SpecObj<S, M> {
398 pub api_version: String,
399 pub kind: String,
400 pub metadata: M,
401 pub spec: S,
402 #[serde(default)]
403 pub data: BTreeMap<String, String>,
404}
405
406impl<S, M> K8SpecObj<S, M>
407where
408 S: Spec,
409{
410 pub fn new(spec: S, metadata: M) -> Self
411 where
412 M: Default,
413 {
414 Self {
415 api_version: S::api_version(),
416 kind: S::kind(),
417 metadata,
418 spec,
419 ..Default::default()
420 }
421 }
422}
423
424pub type InputK8Obj<S> = K8SpecObj<S, InputObjectMeta>;
425pub type UpdateK8Obj<S> = K8SpecObj<S, ItemMeta>;
426
427#[derive(Deserialize, Serialize, Debug, Default, Clone)]
429#[serde(rename_all = "camelCase")]
430pub struct UpdateK8ObjStatus<S>
431where
432 S: Spec,
433{
434 pub api_version: String,
435 pub kind: String,
436 pub metadata: UpdateItemMeta,
437 pub status: S::Status,
438 pub data: PhantomData<S>,
439}
440
441impl<S> UpdateK8ObjStatus<S>
442where
443 S: Spec,
444{
445 pub fn new(status: S::Status, metadata: UpdateItemMeta) -> Self {
446 Self {
447 api_version: S::api_version(),
448 kind: S::kind(),
449 metadata,
450 status,
451 ..Default::default()
452 }
453 }
454}
455
456impl<S> From<UpdateK8Obj<S>> for InputK8Obj<S>
457where
458 S: Default,
459{
460 fn from(update: UpdateK8Obj<S>) -> Self {
461 Self {
462 api_version: update.api_version,
463 kind: update.kind,
464 metadata: update.metadata.into(),
465 spec: update.spec,
466 ..Default::default()
467 }
468 }
469}
470
471impl From<ItemMeta> for InputObjectMeta {
472 fn from(update: ItemMeta) -> Self {
473 Self {
474 name: update.name,
475 namespace: update.namespace,
476 ..Default::default()
477 }
478 }
479}
480
481#[derive(Deserialize, Serialize, Debug, Default, Clone)]
483#[serde(rename_all = "camelCase", default)]
484pub struct TemplateMeta {
485 pub name: Option<String>,
486 pub creation_timestamp: Option<String>,
487 pub labels: HashMap<String, String>,
488}
489
490impl LabelProvider for TemplateMeta {
491 fn set_label_map(mut self, labels: HashMap<String, String>) -> Self {
492 self.labels = labels;
493 self
494 }
495}
496
497impl TemplateMeta {
498 pub fn named<S>(name: S) -> Self
500 where
501 S: Into<String>,
502 {
503 Self {
504 name: Some(name.into()),
505 ..Default::default()
506 }
507 }
508}
509
510#[derive(Deserialize, Serialize, Debug, Default, Clone)]
511#[serde(rename_all = "camelCase")]
512pub struct TemplateSpec<S> {
513 pub metadata: Option<TemplateMeta>,
514 pub spec: S,
515}
516
517impl<S> TemplateSpec<S> {
518 pub fn new(spec: S) -> Self {
519 TemplateSpec {
520 metadata: None,
521 spec,
522 }
523 }
524}
525
526#[derive(Deserialize, Serialize, Debug, Clone)]
527#[serde(rename_all = "camelCase")]
528#[serde(bound(serialize = "K8Obj<S>: Serialize"))]
529#[serde(bound(deserialize = "K8Obj<S>: DeserializeOwned"))]
530pub struct K8List<S>
531where
532 S: Spec,
533{
534 pub api_version: String,
535 pub kind: String,
536 pub metadata: ListMetadata,
537 pub items: Vec<K8Obj<S>>,
538}
539
540impl<S> K8List<S>
541where
542 S: Spec,
543{
544 #[allow(dead_code)]
545 pub fn new() -> Self {
546 K8List {
547 api_version: S::api_version(),
548 items: vec![],
549 kind: S::kind(),
550 metadata: ListMetadata {
551 _continue: None,
552 resource_version: S::api_version(),
553 },
554 }
555 }
556}
557
558impl<S> Default for K8List<S>
559where
560 S: Spec,
561{
562 fn default() -> Self {
563 Self::new()
564 }
565}
566
567pub trait DeserializeWith: Sized {
568 fn deserialize_with<'de, D>(de: D) -> Result<Self, D::Error>
569 where
570 D: Deserializer<'de>;
571}
572
573#[derive(Deserialize, Debug, Clone)]
574#[serde(tag = "type", content = "object")]
575#[serde(bound(serialize = "K8Obj<S>: Serialize"))]
576#[serde(bound(deserialize = "K8Obj<S>: DeserializeOwned"))]
577pub enum K8Watch<S>
578where
579 S: Spec,
580{
581 ADDED(K8Obj<S>),
582 MODIFIED(K8Obj<S>),
583 DELETED(K8Obj<S>),
584}
585
586#[derive(Deserialize, Serialize, Debug, Clone)]
587#[serde(rename_all = "camelCase")]
588pub struct ListMetadata {
589 pub _continue: Option<String>,
590 pub resource_version: String,
591}
592
593#[derive(Deserialize, Serialize, Default, Debug, PartialEq, Clone)]
594#[serde(rename_all = "camelCase")]
595pub struct LabelSelector {
596 pub match_labels: HashMap<String, String>,
597}
598
599impl LabelSelector {
600 pub fn new_labels<T: Into<String>>(labels: Vec<(T, T)>) -> Self {
601 let mut match_labels = HashMap::new();
602 for (key, value) in labels {
603 match_labels.insert(key.into(), value.into());
604 }
605 LabelSelector { match_labels }
606 }
607}
608
609#[derive(Deserialize, Serialize, Default, Debug, Clone)]
610#[serde(rename_all = "camelCase")]
611pub struct Env {
612 pub name: String,
613 pub value: Option<String>,
614 pub value_from: Option<EnvVarSource>,
615}
616
617impl Env {
618 pub fn key_value<T: Into<String>>(name: T, value: T) -> Self {
619 Env {
620 name: name.into(),
621 value: Some(value.into()),
622 value_from: None,
623 }
624 }
625
626 pub fn key_field_ref<T: Into<String>>(name: T, field_path: T) -> Self {
627 Env {
628 name: name.into(),
629 value: None,
630 value_from: Some(EnvVarSource {
631 field_ref: Some(ObjectFieldSelector {
632 field_path: field_path.into(),
633 }),
634 }),
635 }
636 }
637}
638
639#[derive(Deserialize, Serialize, Default, Debug, Clone)]
640#[serde(rename_all = "camelCase")]
641pub struct EnvVarSource {
642 field_ref: Option<ObjectFieldSelector>,
643}
644
645#[derive(Deserialize, Serialize, Default, Debug, Clone)]
646#[serde(rename_all = "camelCase")]
647pub struct ObjectFieldSelector {
648 pub field_path: String,
649}
650
651#[cfg(test)]
652mod test {
653
654 use super::Env;
655 use super::ObjectMeta;
656
657 #[test]
658 fn test_metadata_label() {
659 let metadata =
660 ObjectMeta::default().set_labels(vec![("app".to_owned(), "test".to_owned())]);
661
662 let maps = metadata.labels;
663 assert_eq!(maps.len(), 1);
664 assert_eq!(maps.get("app").unwrap(), "test");
665 }
666
667 #[test]
668 fn test_env() {
669 let env = Env::key_value("lang", "english");
670 assert_eq!(env.name, "lang");
671 assert_eq!(env.value, Some("english".to_owned()));
672 }
673}
674
675