diff --git a/Cargo.lock b/Cargo.lock index 68bf7d3f..93948462 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -929,12 +929,16 @@ version = "1.0.1" dependencies = [ "async-trait", "flv-future-aio", + "flv-util", "futures", "http 0.1.21", "k8-diff", + "k8-obj-app", + "k8-obj-core", "k8-obj-metadata", "log", "pin-utils", + "rand", "serde", "serde_json", "serde_qs 0.5.2", diff --git a/src/k8-metadata-client/Cargo.toml b/src/k8-metadata-client/Cargo.toml index dc45b7aa..835ff3d5 100644 --- a/src/k8-metadata-client/Cargo.toml +++ b/src/k8-metadata-client/Cargo.toml @@ -20,3 +20,10 @@ flv-future-aio = { version = "2.0.0" } k8-diff = { version = "0.1.0", path = "../k8-diff"} k8-obj-metadata = { version = "1.0.0", path = "../k8-obj-metadata" } +[dev-dependencies] +rand = "0.7.2" +async-trait = "0.1.21" +flv-future-aio = { version = "2.0.0", features=["fixture"]} +flv-util = { version = "0.1.0", features=["fixture"]} +k8-obj-app = { version = "1.0.0", path = "../k8-obj-app"} +k8-obj-core = { version = "1.1.0", path = "../k8-obj-core"} \ No newline at end of file diff --git a/src/k8-metadata-client/src/in_memory.rs b/src/k8-metadata-client/src/in_memory.rs new file mode 100644 index 00000000..0c93859a --- /dev/null +++ b/src/k8-metadata-client/src/in_memory.rs @@ -0,0 +1,434 @@ +use k8_obj_metadata::Crd; +use std::collections::HashMap; +use std::fmt; +use std::fmt::Debug; +use std::fmt::Display; +use std::io::Error as IoError; +use std::sync::{Arc, PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard}; +use std::default::Default; + +use async_trait::async_trait; +use futures::stream::BoxStream; +use futures::stream::StreamExt; +use serde::de::DeserializeOwned; +use serde::Serialize; +use serde_json::Value; + +use k8_diff::DiffError; +use k8_obj_metadata::InputK8Obj; +use k8_obj_metadata::K8List; +use k8_obj_metadata::K8Meta; +use k8_obj_metadata::K8Obj; +use k8_obj_metadata::K8Status; +use k8_obj_metadata::K8Watch; +use k8_obj_metadata::ObjectMeta; +use k8_obj_metadata::Spec; +use k8_obj_metadata::UpdateK8ObjStatus; +use k8_obj_metadata::StatusEnum; + +use crate::ListArg; +use crate::MetadataClient; +use crate::MetadataClientError; +use crate::NameSpace; +use crate::TokenStreamResult; + +#[derive(Debug)] +pub enum InMemoryError { + IoError(IoError), + DiffError(DiffError), + JsonError(serde_json::Error), + LockPoisonError, + PatchError, + NotFound, +} + +impl From for InMemoryError { + fn from(error: IoError) -> Self { + Self::IoError(error) + } +} + +impl From for InMemoryError { + fn from(error: serde_json::Error) -> Self { + Self::JsonError(error) + } +} + +impl From for InMemoryError { + fn from(error: DiffError) -> Self { + Self::DiffError(error) + } +} + +type ReadPoisonError<'a> = PoisonError>; + +impl<'a> From> for InMemoryError { + fn from(_error: ReadPoisonError) -> Self { + Self::LockPoisonError + } +} + +type WritePoisonError<'a> = PoisonError>; + +impl<'a> From> for InMemoryError { + fn from(_error: WritePoisonError) -> Self { + Self::LockPoisonError + } +} + +impl fmt::Display for InMemoryError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::IoError(err) => write!(f, "io: {}", err), + Self::JsonError(err) => write!(f, "{}", err), + Self::NotFound => write!(f, "not found"), + Self::DiffError(err) => write!(f, "{:#?}", err), + Self::PatchError => write!(f, "patch error"), + Self::LockPoisonError => write!(f, "lock poison error"), + } + } +} + +impl MetadataClientError for InMemoryError { + fn patch_error() -> Self { + Self::PatchError + } + + fn not_founded(&self) -> bool { + match self { + Self::NotFound => true, + _ => false, + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +struct ItemKey { + crd: &'static Crd, + ns: String, + name: String, +} + +impl ItemKey { + pub fn new(metadata: &dyn K8Meta) -> Self + where + S: Spec + { + + ItemKey { + crd: S::metadata(), + ns: metadata.namespace().to_owned(), + name: metadata.name().to_owned() + } + } +} + +type ItemMap = HashMap; + +#[derive(Debug, Default)] +pub struct InMemoryClient { + store: Arc>, +} + +impl InMemoryClient { + pub fn new() -> Self { + Self::default() + } +} + +#[async_trait] +impl MetadataClient for InMemoryClient { + type MetadataClientError = InMemoryError; + + async fn retrieve_item(&self, metadata: &M) -> Result, Self::MetadataClientError> + where + K8Obj: DeserializeOwned, + S: Spec, + M: K8Meta + Send + Sync, + { + let store = self.store.read()?; + let item_key = ItemKey::new::(metadata); + let item_value = store.get(&item_key).ok_or(InMemoryError::NotFound)?; + let value: K8Obj = serde_json::from_value(item_value.clone())?; + + Ok(K8Obj { + api_version: value.api_version, + kind: value.kind, + metadata: ObjectMeta { + name: value.metadata.name().to_owned(), + namespace: value.metadata.namespace().to_owned(), + ..Default::default() + }, + spec: value.spec, + ..Default::default() + }) + } + + async fn retrieve_items_with_option( + &self, + _namespace: N, + _option: Option, + ) -> Result, Self::MetadataClientError> + where + S: Spec, + N: Into + Send + Sync, + { + unimplemented!(); + } + + fn retrieve_items_in_chunks<'a, S, N>( + self: Arc, + _namespace: N, + _limit: u32, + _option: Option, + ) -> BoxStream<'a, K8List> + where + S: Spec + 'static, + N: Into + Send + Sync + 'static, + { + unimplemented!(); + } + + async fn delete_item(&self, metadata: &M) -> Result + where + S: Spec, + M: K8Meta + Send + Sync, + { + let mut store = self.store.write()?; + let item_key = ItemKey::new::(metadata); + let item_value = store.remove(&item_key).ok_or(InMemoryError::NotFound)?; + let value: K8Obj = serde_json::from_value(item_value.clone())?; + + Ok(K8Status { + api_version: value.api_version, + code: None, + details: None, + kind: value.kind, + message: None, + reason: None, + status: StatusEnum::SUCCESS, + }) + } + + async fn create_item( + &self, + value: InputK8Obj, + ) -> Result, Self::MetadataClientError> + where + InputK8Obj: Serialize + Debug, + K8Obj: DeserializeOwned, + S: Spec + Send, + { + let k8_obj = K8Obj { + api_version: value.api_version, + kind: value.kind, + metadata: ObjectMeta { + name: value.metadata.name().to_owned(), + namespace: value.metadata.namespace().to_owned(), + ..Default::default() + }, + spec: value.spec, + ..Default::default() + }; + + let item_key = ItemKey::new::(&value.metadata); + let item_value = serde_json::to_value(&k8_obj)?; + let mut store = self.store.write()?; + store.insert(item_key, item_value); + + Ok(k8_obj) + } + + async fn update_status( + &self, + update_k8_status: &UpdateK8ObjStatus, + ) -> Result, Self::MetadataClientError> + where + UpdateK8ObjStatus: Serialize + Debug, + K8Obj: DeserializeOwned, + S: Spec + Send + Sync, + S::Status: Send + Sync, + { + let mut store = self.store.write()?; + let item_key = ItemKey::new::(&update_k8_status.metadata); + let item_value = store.get_mut(&item_key).ok_or(InMemoryError::NotFound)?; + + let mut k8_obj: K8Obj = serde_json::from_value(item_value.clone())?; + k8_obj.status = update_k8_status.status.clone(); + + *item_value = serde_json::to_value(&k8_obj)?; + + Ok(k8_obj) + } + + async fn patch_spec( + &self, + _metadata: &M, + _patch: &Value, + ) -> Result, Self::MetadataClientError> + where + K8Obj: DeserializeOwned, + S: Spec + Send, + M: K8Meta + Display + Send + Sync, + { + unimplemented!(); + } + + fn watch_stream_since( + &self, + _namespace: N, + _resource_version: Option, + ) -> BoxStream<'_, TokenStreamResult> + where + K8Watch: DeserializeOwned, + S: Spec + Send + 'static, + S::Header: Send + 'static, + S::Status: Send + 'static, + N: Into, + { + unimplemented!(); + } +} + +#[cfg(test)] +mod tests { + + use crate::client::MetadataClient; + use super::InMemoryClient; + use super::InMemoryError; + + use std::collections::HashMap; + + use flv_future_aio::test_async; + use rand::distributions::Alphanumeric; + use rand::{thread_rng, Rng}; + + use k8_obj_metadata::InputK8Obj; + use k8_obj_metadata::InputObjectMeta; + use k8_obj_core::service::ServicePort; + use k8_obj_core::service::ServiceSpec; + use k8_obj_core::service::ServiceStatus; + use k8_obj_core::service::LoadBalancerStatus; + use k8_obj_core::service::LoadBalancerIngress; + + use k8_obj_metadata::Spec; + use k8_obj_metadata::K8Status; + use k8_obj_metadata::K8Obj; + use k8_obj_metadata::StatusEnum; + use k8_obj_metadata::UpdateK8ObjStatus; + + const SPU_DEFAULT_NAME: &'static str = "spu"; + + fn new_service() -> InputK8Obj { + let rng = thread_rng(); + let rname: String = rng.sample_iter(&Alphanumeric).take(5).collect(); + let name = format!("test{}", rname); + + let mut labels = HashMap::new(); + labels.insert("app".to_owned(), SPU_DEFAULT_NAME.to_owned()); + let mut selector = HashMap::new(); + selector.insert("app".to_owned(), SPU_DEFAULT_NAME.to_owned()); + + let service_spec = ServiceSpec { + cluster_ip: "None".to_owned(), + ports: vec![ServicePort { + port: 9092, + ..Default::default() + }], + selector: Some(selector), + ..Default::default() + }; + + let new_item: InputK8Obj = InputK8Obj { + api_version: ServiceSpec::api_version(), + kind: ServiceSpec::kind(), + metadata: InputObjectMeta { + name: name.to_lowercase(), + labels, + namespace: "default".to_owned(), + ..Default::default() + }, + spec: service_spec, + ..Default::default() + }; + + new_item + } + + #[test_async] + async fn test_create_and_delete_service() -> Result<(), InMemoryError> { + let new_item = new_service(); + + let client = InMemoryClient::new(); + let item = client.create_item::(new_item) + .await + .expect("service should be created"); + + let k8_status = client + .delete_item::(&item.metadata) + .await + .expect("delete should work"); + + assert_k8_status_for_item(k8_status, item); + + Ok(()) + } + + #[test_async] + async fn test_create_and_retrieve_service() -> Result<(), InMemoryError> { + let new_item = new_service(); + + let client = InMemoryClient::new(); + let item = client.create_item::(new_item) + .await + .expect("service should be created"); + + let retreived_item = client + .retrieve_item::(&item.metadata) + .await + .expect("retreive should work"); + + assert_eq!(retreived_item, item); + + Ok(()) + } + + // #[test_async] + // async fn test_create_and_update_service_status() -> Result<(), InMemoryError> { + // let new_item = new_service(); + + // let client = InMemoryClient::new(); + // let item = client.create_item::(new_item) + // .await + // .expect("service should be created"); + + + // let new_service_status = ServiceStatus { + // load_balancer: LoadBalancerStatus { + // ingress: vec![LoadBalancerIngress { hostname: Some("localhost".to_owned()), ip: None } ] + // } + // }; + // let update = UpdateK8ObjStatus::new(new_service_status, item.metadata.clone().into()); + + // let updated_item = client + // .update_status::(&update) + // .await + // .expect("update should work"); + + // let retreived_item = client + // .retrieve_item::(&item.metadata) + // .await + // .expect("retreive should work"); + + // assert_ne!(updated_item, item); + // assert_eq!(retreived_item, updated_item); + + // Ok(()) + // } + + fn assert_k8_status_for_item(k8_status: K8Status, item: K8Obj) where S: Spec { + assert_eq!(k8_status.status, StatusEnum::SUCCESS); + assert_eq!(k8_status.api_version, item.api_version); + assert_eq!(k8_status.kind, item.kind); + } +} diff --git a/src/k8-metadata-client/src/lib.rs b/src/k8-metadata-client/src/lib.rs index 3cfd7f84..01041c9c 100644 --- a/src/k8-metadata-client/src/lib.rs +++ b/src/k8-metadata-client/src/lib.rs @@ -1,6 +1,7 @@ mod client; mod diff; mod nothing; +mod in_memory; pub use diff::*; pub use client::MetadataClient; @@ -11,5 +12,7 @@ pub use client::ListArg; pub use client::as_token_stream_result; pub use nothing::DoNothingClient; pub use nothing::DoNothingError; +pub use in_memory::InMemoryClient; +pub use in_memory::InMemoryError; pub type SharedClient = std::sync::Arc; \ No newline at end of file diff --git a/src/k8-obj-app/src/stateful.rs b/src/k8-obj-app/src/stateful.rs index 5516e1ec..d8cd8955 100644 --- a/src/k8-obj-app/src/stateful.rs +++ b/src/k8-obj-app/src/stateful.rs @@ -20,7 +20,7 @@ const STATEFUL_API: Crd = Crd { }, }; -#[derive(Deserialize, Serialize, Debug, Default, Clone)] +#[derive(Deserialize, Serialize, Debug, Default, Clone, PartialEq)] #[serde(rename_all = "camelCase",default)] pub struct StatefulSetSpec { pub pod_management_policy: Option, @@ -44,7 +44,7 @@ impl Spec for StatefulSetSpec { } -#[derive(Deserialize, Serialize, Debug, Default, Clone)] +#[derive(Deserialize, Serialize, Debug, Default, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct StatefulSetUpdateStrategy { pub _type: String, @@ -52,7 +52,7 @@ pub struct StatefulSetUpdateStrategy { } -#[derive(Deserialize, Serialize, Debug, Default, Clone)] +#[derive(Deserialize, Serialize, Debug, Default, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct RollingUpdateStatefulSetStrategy { partition: u32 @@ -64,7 +64,7 @@ pub enum PodMangementPolicy { Parallel, } -#[derive(Deserialize, Serialize, Debug, Clone)] +#[derive(Deserialize, Serialize, Debug, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct PersistentVolumeClaim { pub access_modes: Vec, @@ -79,17 +79,17 @@ pub enum VolumeAccessMode { ReadOnlyMany, } -#[derive(Deserialize, Serialize, Debug, Clone)] +#[derive(Deserialize, Serialize, Debug, Clone, PartialEq)] pub struct ResourceRequirements { pub requests: VolumeRequest, } -#[derive(Deserialize, Serialize, Debug, Clone)] +#[derive(Deserialize, Serialize, Debug, Clone, PartialEq)] pub struct VolumeRequest { pub storage: String, } -#[derive(Deserialize, Serialize, Default,Debug, Clone)] +#[derive(Deserialize, Serialize, Default,Debug, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct StatefulSetStatus { pub replicas: u16, @@ -113,7 +113,7 @@ pub enum StatusEnum { Unknown, } -#[derive(Deserialize, Serialize, Debug, Clone)] +#[derive(Deserialize, Serialize, Debug, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct StatefulSetCondition { pub message: String, diff --git a/src/k8-obj-core/src/config_map.rs b/src/k8-obj-core/src/config_map.rs index 3794d330..6a84b045 100644 --- a/src/k8-obj-core/src/config_map.rs +++ b/src/k8-obj-core/src/config_map.rs @@ -31,7 +31,7 @@ impl Spec for ConfigMapSpec { } } -#[derive(Deserialize, Serialize, Debug, Default, Clone)] +#[derive(Deserialize, Serialize, Debug, Default, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct ConfigMapSpec {} diff --git a/src/k8-obj-core/src/namespace.rs b/src/k8-obj-core/src/namespace.rs index 353ce685..b3377dc5 100644 --- a/src/k8-obj-core/src/namespace.rs +++ b/src/k8-obj-core/src/namespace.rs @@ -18,7 +18,7 @@ const API: Crd = Crd { }, }; -#[derive(Deserialize, Serialize, Debug, Default, Clone)] +#[derive(Deserialize, Serialize, Debug, Default, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct NamespaceSpec { } @@ -38,7 +38,7 @@ impl Spec for NamespaceSpec { default_store_spec!(NamespaceSpec,NamespaceStatus,"Namespace"); -#[derive(Deserialize, Serialize, PartialEq,Debug, Default, Clone)] +#[derive(Deserialize, Serialize, PartialEq, Debug, Default, Clone)] #[serde(rename_all = "camelCase",default)] pub struct NamespaceStatus { pub phase: String diff --git a/src/k8-obj-core/src/plugin.rs b/src/k8-obj-core/src/plugin.rs index b53b4435..87a15126 100644 --- a/src/k8-obj-core/src/plugin.rs +++ b/src/k8-obj-core/src/plugin.rs @@ -18,7 +18,7 @@ const CREDENTIAL_API: Crd = Crd { }; -#[derive(Deserialize, Serialize, Debug, Default, Clone)] +#[derive(Deserialize, Serialize, Debug, Default, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct ExecCredentialSpec { } diff --git a/src/k8-obj-core/src/pod.rs b/src/k8-obj-core/src/pod.rs index dbb136ea..10eb649b 100644 --- a/src/k8-obj-core/src/pod.rs +++ b/src/k8-obj-core/src/pod.rs @@ -31,7 +31,7 @@ impl Spec for PodSpec { } } -#[derive(Deserialize, Serialize, Debug, Default, Clone)] +#[derive(Deserialize, Serialize, Debug, Default, Clone, PartialEq)] #[serde(rename_all = "camelCase",default)] pub struct PodSpec { pub volumes: Vec, @@ -46,7 +46,7 @@ pub struct PodSpec { pub scheduler_name: Option } -#[derive(Deserialize, Serialize, Debug, Default, Clone)] +#[derive(Deserialize, Serialize, Debug, Default, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct PodSecurityContext { pub fs_group: Option, @@ -55,7 +55,7 @@ pub struct PodSecurityContext { pub run_as_user: Option } -#[derive(Deserialize, Serialize, Default, Debug, Clone)] +#[derive(Deserialize, Serialize, Default, Debug, Clone, PartialEq)] #[serde(rename_all = "camelCase",default)] pub struct ContainerSpec { pub name: String, @@ -72,7 +72,7 @@ pub struct ContainerSpec { pub tty: Option } -#[derive(Deserialize, Serialize, Default, Debug, Clone)] +#[derive(Deserialize, Serialize, Default, Debug, Clone, PartialEq)] #[serde(rename_all = "camelCase",default)] pub struct ResourceRequirements { pub api_groups: Vec, @@ -81,7 +81,7 @@ pub struct ResourceRequirements { pub verbs: Vec } -#[derive(Deserialize, Serialize, Default, Debug, Clone)] +#[derive(Deserialize, Serialize, Default, Debug, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct ContainerPortSpec { pub container_port: u16, @@ -101,14 +101,14 @@ impl ContainerPortSpec { -#[derive(Deserialize, Serialize, Default, Debug, Clone)] +#[derive(Deserialize, Serialize, Default, Debug, Clone, PartialEq)] pub struct VolumeSpec { pub name: String, pub secret: Option, pub persistent_volume_claim: Option, } -#[derive(Deserialize, Serialize, Default, Debug, Clone)] +#[derive(Deserialize, Serialize, Default, Debug, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct VolumeMount { pub mount_path: String, @@ -118,7 +118,7 @@ pub struct VolumeMount { pub sub_path: Option, } -#[derive(Deserialize, Serialize, Default, Debug, Clone)] +#[derive(Deserialize, Serialize, Default, Debug, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct SecretVolumeSpec { pub default_mode: u16, @@ -126,14 +126,14 @@ pub struct SecretVolumeSpec { pub optional: Option, } -#[derive(Deserialize, Serialize, Default, Debug, Clone)] +#[derive(Deserialize, Serialize, Default, Debug, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct PersistentVolumeClaimVolumeSource { claim_name: String, read_only: bool, } -#[derive(Deserialize, Serialize, Default, Debug, Clone)] +#[derive(Deserialize, Serialize, Default, Debug, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct PodStatus { pub phase: String, @@ -147,7 +147,7 @@ pub struct PodStatus { impl Status for PodStatus{} -#[derive(Deserialize, Serialize, Debug, Clone)] +#[derive(Deserialize, Serialize, Debug, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct ContainerStatus { pub name: String, @@ -161,13 +161,13 @@ pub struct ContainerStatus { pub container_id: Option, } -#[derive(Deserialize, Serialize, Debug, Clone)] +#[derive(Deserialize, Serialize, Debug, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct ContainerState { pub running: Option, } -#[derive(Deserialize, Serialize, Debug, Clone)] +#[derive(Deserialize, Serialize, Debug, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct ContainerStateRunning { pub started_at: String, diff --git a/src/k8-obj-metadata/src/crd.rs b/src/k8-obj-metadata/src/crd.rs index 50bb4902..a57b575f 100644 --- a/src/k8-obj-metadata/src/crd.rs +++ b/src/k8-obj-metadata/src/crd.rs @@ -3,14 +3,14 @@ //! //! Interface to the CRD header definition in K8 key value store //! -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq, Hash)] pub struct Crd { pub group: &'static str, pub version: &'static str, pub names: CrdNames, } -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq, Hash)] pub struct CrdNames { pub kind: &'static str, pub plural: &'static str, diff --git a/src/k8-obj-metadata/src/lib.rs b/src/k8-obj-metadata/src/lib.rs index 9abc04df..b7d0a353 100644 --- a/src/k8-obj-metadata/src/lib.rs +++ b/src/k8-obj-metadata/src/lib.rs @@ -24,7 +24,7 @@ pub trait Status: Sized + Debug + Clone + Default + Serialize + DeserializeOwned pub trait Header: Sized + Debug + Clone + Default + Serialize + DeserializeOwned + Send + Sync {} /// Kubernetes Spec -pub trait Spec: Sized + Debug + Clone + Default + Serialize + DeserializeOwned + Send + Sync { +pub trait Spec: Sized + Debug + Clone + Default + Serialize + DeserializeOwned + Send + Sync + PartialEq { type Status: Status; @@ -59,7 +59,7 @@ pub trait Spec: Sized + Debug + Clone + Default + Serialize + DeserializeOwned + } -#[derive(Deserialize, Serialize, Debug, Default, Clone)] +#[derive(Deserialize, Serialize, Debug, Default, Clone, PartialEq)] pub struct DefaultHeader{} impl Header for DefaultHeader{} \ No newline at end of file diff --git a/src/k8-obj-metadata/src/metadata.rs b/src/k8-obj-metadata/src/metadata.rs index 76957396..03cb1192 100644 --- a/src/k8-obj-metadata/src/metadata.rs +++ b/src/k8-obj-metadata/src/metadata.rs @@ -259,6 +259,18 @@ impl From for ItemMeta { } } +impl K8Meta for UpdateItemMeta { + + fn name(&self) -> &str { + &self.name + } + + fn namespace(&self) -> &str { + &self.namespace + } + +} + /// used for updating item #[derive(Deserialize, Serialize, Debug, Default, Clone)] #[serde(rename_all = "camelCase")] @@ -336,7 +348,7 @@ pub struct StatusDetails { pub uid: String, } -#[derive(Deserialize, Serialize, Debug, Default, Clone)] +#[derive(Deserialize, Serialize, Debug, Default, Clone, PartialEq)] #[serde(rename_all = "camelCase")] #[serde(bound(serialize = "S: Serialize"))] #[serde(bound(deserialize = "S: DeserializeOwned"))] @@ -493,7 +505,7 @@ impl From for InputObjectMeta { } /// name is optional for template -#[derive(Deserialize, Serialize, Debug, Default, Clone)] +#[derive(Deserialize, Serialize, Debug, Default, Clone, PartialEq)] #[serde(rename_all = "camelCase",default)] pub struct TemplateMeta { pub name: Option, @@ -523,7 +535,7 @@ impl TemplateMeta { -#[derive(Deserialize, Serialize, Debug, Default, Clone)] +#[derive(Deserialize, Serialize, Debug, Default, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct TemplateSpec { pub metadata: Option, @@ -619,7 +631,7 @@ impl LabelSelector { } } -#[derive(Deserialize, Serialize, Default, Debug, Clone)] +#[derive(Deserialize, Serialize, Default, Debug, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct Env { pub name: String, @@ -647,13 +659,13 @@ impl Env { } } -#[derive(Deserialize, Serialize, Default, Debug, Clone)] +#[derive(Deserialize, Serialize, Default, Debug, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct EnvVarSource { field_ref: Option } -#[derive(Deserialize, Serialize, Default, Debug, Clone)] +#[derive(Deserialize, Serialize, Default, Debug, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct ObjectFieldSelector { pub field_path: String diff --git a/src/k8-obj-storage/src/storage_class.rs b/src/k8-obj-storage/src/storage_class.rs index 0ba5cb41..b9a3098c 100644 --- a/src/k8-obj-storage/src/storage_class.rs +++ b/src/k8-obj-storage/src/storage_class.rs @@ -18,7 +18,7 @@ const STORAGE_API: Crd = Crd { }, }; -#[derive(Deserialize, Serialize, Debug, Default, Clone)] +#[derive(Deserialize, Serialize, Debug, Default, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct StorageClassSpec { } @@ -35,7 +35,7 @@ impl Spec for StorageClassSpec { } -#[derive(Deserialize, Serialize, Debug, Default, Clone)] +#[derive(Deserialize, Serialize, Debug, Default, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct StorageClassHeader { pub allow_volume_expansion: Option, @@ -46,7 +46,7 @@ pub struct StorageClassHeader { impl Header for StorageClassHeader{} -#[derive(Deserialize, Serialize, Default,Debug, Clone)] +#[derive(Deserialize, Serialize, Default,Debug, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct StorageClassStatus { }