Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Command Pattern #1231

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
268 changes: 268 additions & 0 deletions kube-client/src/command/command.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
use k8s_openapi::serde_value::Value;
use kube_core::params::{DeleteParams, Patch, PatchParams, PostParams};
use kube_core::{ApiResource, DynamicObject, Resource};
use serde::Serialize;
use std::fmt::{Display, Formatter};
use std::option::Option::None;

/// TODO
#[derive(Clone, Debug, PartialEq)]
pub struct KubeCommand {
/// TODO
pub namespace: Option<String>,
/// TODO
pub verb: KubeCommandVerb,
}

impl KubeCommand {
/// TODO
pub fn cluster(command: KubeCommandVerb) -> KubeCommand {
Self {
namespace: None,
verb: command,
}
}

/// TODO
pub fn namespaced(namespace: &str, command: KubeCommandVerb) -> KubeCommand {
Self {
namespace: Some(namespace.to_string()),
verb: command,
}
}

/// TODO
pub fn api_resource(&self) -> ApiResource {
self.verb.api_resource()
}

/// TODO
pub fn kind(&self) -> String {
self.verb.kind()
}

/// TODO
pub fn name(&self) -> String {
self.verb.name()
}

/// TODO
pub fn namespace(&self) -> Option<String> {
self.namespace.clone()
}

/// TODO
pub fn verb_name(&self) -> String {
self.verb.verb_name()
}
}

/// TODO
#[derive(Clone, Debug, PartialEq)]
pub enum KubeCommandVerb {
Create {
name: String,
object: Box<DynamicObject>,
resource: ApiResource,
params: PostParams,
},
Replace {
name: String,
object: Box<DynamicObject>,
resource: ApiResource,
params: PostParams,
},
ReplaceStatus {
name: String,
data: Vec<u8>,
resource: ApiResource,
params: PostParams,
},
Patch {
name: String,
patch: Patch<Value>,
resource: ApiResource,
params: PatchParams,
},
PatchStatus {
name: String,
patch: Patch<Value>,
resource: ApiResource,
params: PatchParams,
},
Delete {
name: String,
resource: ApiResource,
params: DeleteParams,
},
}

impl Display for KubeCommandVerb {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(&format!("{}: {}/{}", self.verb_name(), self.kind(), self.name()))
}
}

impl KubeCommandVerb {
pub fn create<K: Resource + Serialize>(
name: String,
resource: K,
params: PostParams,
) -> Result<KubeCommandVerb, serde_json::Error>
where
K::DynamicType: Default,
{
let mut dynamic_object = DynamicObject::new(&name, &ApiResource::erase::<K>(&Default::default()));

dynamic_object.metadata = resource.meta().clone();
dynamic_object.data = serde_json::to_value(resource)?;

Ok(KubeCommandVerb::Create {
name,
object: Box::new(dynamic_object),
resource: ApiResource::erase::<K>(&Default::default()),
params,
})
}

pub fn replace<K: Resource + Serialize>(
name: String,
resource: K,
params: PostParams,
) -> Result<KubeCommandVerb, serde_json::Error>
where
K::DynamicType: Default,
{
let mut dynamic_object = DynamicObject::new(&name, &ApiResource::erase::<K>(&Default::default()));

dynamic_object.metadata = resource.meta().clone();
dynamic_object.data = serde_json::to_value(resource)?;

Ok(KubeCommandVerb::Replace {
name,
object: Box::new(dynamic_object),
resource: ApiResource::erase::<K>(&Default::default()),
params,
})
}

pub fn replace_status<K: Resource + Serialize>(
name: String,
resource: K,
params: PostParams,
) -> Result<KubeCommandVerb, serde_json::Error>
where
K::DynamicType: Default,
{
Ok(KubeCommandVerb::ReplaceStatus {
name,
data: serde_json::to_vec(&resource)?,
resource: ApiResource::erase::<K>(&Default::default()),
params,
})
}

pub fn patch<K: Resource>(name: String, patch: Patch<Value>, params: PatchParams) -> KubeCommandVerb
where
K::DynamicType: Default,
{
KubeCommandVerb::Patch {
name,
patch: patch,
resource: ApiResource::erase::<K>(&Default::default()),
params,
}
}

pub fn patch_status<K: Resource>(
name: String,
patch: Patch<Value>,
params: PatchParams,
) -> KubeCommandVerb
where
K::DynamicType: Default,
{
KubeCommandVerb::PatchStatus {
name,
patch,
resource: ApiResource::erase::<K>(&Default::default()),
params,
}
}

pub fn delete<K: Resource>(name: String, params: DeleteParams) -> KubeCommandVerb
where
K::DynamicType: Default,
{
KubeCommandVerb::Delete {
name,
resource: ApiResource::erase::<K>(&Default::default()),
params,
}
}

pub fn in_scope(self, namespace: Option<String>) -> KubeCommand {
KubeCommand {
namespace,
verb: self,
}
}

pub fn in_cluster(self) -> KubeCommand {
KubeCommand {
namespace: None,
verb: self,
}
}

pub fn in_namespace(self, namespace: String) -> KubeCommand {
KubeCommand {
namespace: Some(namespace),
verb: self,
}
}

pub fn name(&self) -> String {
match self {
KubeCommandVerb::Create { name, .. }
| KubeCommandVerb::Replace { name, .. }
| KubeCommandVerb::ReplaceStatus { name, .. }
| KubeCommandVerb::Patch { name, .. }
| KubeCommandVerb::PatchStatus { name, .. }
| KubeCommandVerb::Delete { name, .. } => name.to_string(),
}
}

pub fn kind(&self) -> String {
match self {
KubeCommandVerb::Create { resource, .. }
| KubeCommandVerb::Replace { resource, .. }
| KubeCommandVerb::ReplaceStatus { resource, .. }
| KubeCommandVerb::Patch { resource, .. }
| KubeCommandVerb::PatchStatus { resource, .. }
| KubeCommandVerb::Delete { resource, .. } => resource.kind.to_string(),
}
}

pub fn verb_name(&self) -> String {
match self {
KubeCommandVerb::Create { .. } => "Create".to_string(),
KubeCommandVerb::Replace { .. } => "Replace".to_string(),
KubeCommandVerb::ReplaceStatus { .. } => "ReplaceStatus".to_string(),
KubeCommandVerb::Patch { .. } => "Patch".to_string(),
KubeCommandVerb::PatchStatus { .. } => "PatchStatus".to_string(),
KubeCommandVerb::Delete { .. } => "Delete".to_string(),
}
}

pub fn api_resource(&self) -> ApiResource {
match self {
KubeCommandVerb::Create { resource, .. }
| KubeCommandVerb::Replace { resource, .. }
| KubeCommandVerb::ReplaceStatus { resource, .. }
| KubeCommandVerb::Patch { resource, .. }
| KubeCommandVerb::PatchStatus { resource, .. }
| KubeCommandVerb::Delete { resource, .. } => resource.clone(),
}
}
}
67 changes: 67 additions & 0 deletions kube-client/src/command/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//! TODO

mod command;

pub use command::*;

use crate::api::DynamicObject;
use crate::client::Status;
use crate::command::command::KubeCommandVerb;
use crate::Api;
use crate::Client;
use crate::Error;
use either::Either;

/// TODO
pub struct Dispatcher {
client: Client,
}

impl Dispatcher {
/// TODO
pub fn new(client: Client) -> Dispatcher {
Dispatcher { client }
}

/// TODO
pub async fn dispatch_command(
&self,
command: KubeCommand,
) -> Result<Either<DynamicObject, Status>, Error> {
let api = match &command.namespace {
None => Api::<DynamicObject>::all_with(self.client.clone(), &command.api_resource()),
Some(namespace) => {
Api::<DynamicObject>::namespaced_with(self.client.clone(), namespace, &command.api_resource())
}
};

api.dispatch_command(command.verb).await
}
}

impl Api<DynamicObject> {
/// TODO
pub async fn dispatch_command(
&self,
command: KubeCommandVerb,
) -> Result<Either<DynamicObject, Status>, Error> {
match command {
KubeCommandVerb::Create { object, params, .. } => {
self.create(&params, &object).await.map(Either::Left)
}
KubeCommandVerb::Replace {
name, object, params, ..
} => self.replace(&name, &params, &object).await.map(Either::Left),
KubeCommandVerb::ReplaceStatus {
name, data, params, ..
} => self.replace_status(&name, &params, data).await.map(Either::Left),
KubeCommandVerb::Patch {
name, patch, params, ..
} => self.patch(&name, &params, &patch).await.map(Either::Left),
KubeCommandVerb::PatchStatus {
name, patch, params, ..
} => self.patch_status(&name, &params, &patch).await.map(Either::Left),
KubeCommandVerb::Delete { name, params, .. } => self.delete(&name, &params).await,
}
}
}
1 change: 1 addition & 0 deletions kube-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ cfg_client! {
pub mod api;
pub mod discovery;
pub mod client;
pub mod command;

#[doc(inline)]
pub use api::Api;
Expand Down
12 changes: 6 additions & 6 deletions kube-core/src/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ impl ListParams {
}

/// The validation directive to use for `fieldValidation` when using server-side apply.
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub enum ValidationDirective {
/// Strict mode will fail any invalid manifests.
///
Expand Down Expand Up @@ -174,7 +174,7 @@ impl ValidationDirective {
}

/// Common query parameters for put/post calls
#[derive(Default, Clone, Debug)]
#[derive(Default, Clone, Debug, PartialEq)]
pub struct PostParams {
/// Whether to run this as a dry run
pub dry_run: bool,
Expand Down Expand Up @@ -303,7 +303,7 @@ impl<T: Serialize> Patch<T> {
}

/// Common query parameters for patch calls
#[derive(Default, Clone, Debug)]
#[derive(Default, Clone, Debug, PartialEq)]
pub struct PatchParams {
/// Whether to run this as a dry run
pub dry_run: bool,
Expand Down Expand Up @@ -401,7 +401,7 @@ impl PatchParams {
}

/// Common query parameters for delete calls
#[derive(Default, Clone, Serialize, Debug)]
#[derive(Default, Clone, Serialize, Debug, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct DeleteParams {
/// When present, indicates that modifications should not be persisted.
Expand Down Expand Up @@ -569,7 +569,7 @@ mod test {
}

/// Preconditions must be fulfilled before an operation (update, delete, etc.) is carried out.
#[derive(Default, Clone, Serialize, Debug)]
#[derive(Default, Clone, Serialize, Debug, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct Preconditions {
/// Specifies the target ResourceVersion
Expand All @@ -581,7 +581,7 @@ pub struct Preconditions {
}

/// Propagation policy when deleting single objects
#[derive(Clone, Debug, Serialize)]
#[derive(Clone, Debug, Serialize, PartialEq)]
pub enum PropagationPolicy {
/// Orphan dependents
Orphan,
Expand Down
Loading