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

add a versioned CustomResourceExt trait - fixes #497 #545

Merged
merged 4 commits into from
Jun 8, 2021
Merged
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
3 changes: 3 additions & 0 deletions examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ authors = [
publish = false
edition = "2018"

[package.metadata.release]
disable-release = true

[features]
default = ["native-tls", "schema", "kubederive", "ws"]
kubederive = ["kube/derive"] # by default import kube-derive with its default features
Expand Down
1 change: 1 addition & 0 deletions examples/crd_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use k8s_openapi::apiextensions_apiserver::pkg::apis::apiextensions::v1beta1 as a
use kube::{
api::{Api, DeleteParams, ListParams, Patch, PatchParams, PostParams, ResourceExt},
Client, CustomResource,
core::crd::v1beta1::CustomResourceExt
};

// Own custom resource
Expand Down
2 changes: 1 addition & 1 deletion examples/crd_apply.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use k8s_openapi::apiextensions_apiserver::pkg::apis::apiextensions::v1 as apiext

use kube::{
api::{Api, ListParams, Patch, PatchParams, ResourceExt, WatchEvent},
Client, CustomResource,
Client, CustomResource, CustomResourceExt
};

// NB: This example uses server side apply and beta1 customresources
Expand Down
2 changes: 1 addition & 1 deletion examples/crd_derive.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use k8s_openapi::apimachinery::pkg::apis::meta::v1::Condition;
use kube::{CustomResource, Resource};
use kube::{CustomResource, CustomResourceExt, Resource};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

Expand Down
3 changes: 2 additions & 1 deletion examples/crd_derive_no_schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@ properties:
#[cfg(not(feature = "schema"))]
impl Bar {
fn crd_with_manual_schema() -> CustomResourceDefinition {
use kube::CustomResourceExt;
let schema: JSONSchemaProps = serde_yaml::from_str(MANUAL_SCHEMA).expect("invalid schema");

let mut crd = Self::crd();
let mut crd = <Self as CustomResourceExt>::crd();
crd.spec.versions.iter_mut().for_each(|v| {
v.schema = Some(CustomResourceValidation {
open_api_v3_schema: Some(schema.clone()),
Expand Down
2 changes: 1 addition & 1 deletion examples/crd_derive_schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use kube::{
Api, ApiResource, DeleteParams, DynamicObject, GroupVersionKind, ListParams, Patch, PatchParams,
PostParams, WatchEvent,
},
Client, CustomResource,
Client, CustomResource, CustomResourceExt
};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
Expand Down
36 changes: 36 additions & 0 deletions kube-core/src/crd.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//! Traits and tyes for CustomResources

use k8s_openapi::apiextensions_apiserver::pkg::apis::apiextensions as apiexts;

/// Types for v1 CustomResourceDefinitions
pub mod v1 {
/// Extension trait that will be implemented by kube-derive
///
/// This trait variant is implemented by default (or when `#[kube(apiextensions = "v1")]`)
pub trait CustomResourceExt {
/// Helper to generate the CRD including the JsonSchema
///
/// This is using the stable v1::CustomResourceDefinitions (present in kubernetes >= 1.16)
fn crd() -> super::apiexts::v1::CustomResourceDefinition;
/// Helper to generate the api information type for use with the dynamic `Api`
fn api_resource() -> crate::discovery::ApiResource;
}
}

/// Types for legacy v1beta1 CustomResourceDefinitions
pub mod v1beta1 {
/// Extension trait that will be implemented by kube-derive for legacy v1beta1::CustomResourceDefinitions
///
/// This trait variant is only implemented with `#[kube(apiextensions = "v1beta1")]`
pub trait CustomResourceExt {
/// Helper to generate the legacy CRD without a JsonSchema
///
/// This is using v1beta1::CustomResourceDefinitions (which will be removed in kubernetes 1.22)
fn crd() -> super::apiexts::v1beta1::CustomResourceDefinition;
/// Helper to generate the api information type for use with the dynamic `Api`
fn api_resource() -> crate::discovery::ApiResource;
}
}

/// re-export the current latest version until a newer one is available in cloud providers
pub use v1::CustomResourceExt;
3 changes: 3 additions & 0 deletions kube-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ pub mod discovery;
pub mod dynamic;
pub use dynamic::DynamicObject;

pub mod crd;
pub use crd::CustomResourceExt;

pub mod gvk;
pub use gvk::{GroupVersion, GroupVersionKind, GroupVersionResource};

Expand Down
4 changes: 2 additions & 2 deletions kube-core/src/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,8 +294,8 @@ impl PatchParams {
if self.force {
qp.append_pair("force", "true");
}
if let Some(ref field_manager) = self.field_manager {
qp.append_pair("fieldManager", &field_manager);
if let Some(ref fm) = self.field_manager {
qp.append_pair("fieldManager", fm);
}
}

Expand Down
12 changes: 6 additions & 6 deletions kube-core/src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ impl Request {
let mut qp = form_urlencoded::Serializer::new(target);

if let Some(fields) = &lp.field_selector {
qp.append_pair("fieldSelector", &fields);
qp.append_pair("fieldSelector", fields);
}
if let Some(labels) = &lp.label_selector {
qp.append_pair("labelSelector", &labels);
qp.append_pair("labelSelector", labels);
}
if let Some(limit) = &lp.limit {
qp.append_pair("limit", &limit.to_string());
Expand Down Expand Up @@ -69,10 +69,10 @@ impl Request {
// https://github.com/kubernetes/kubernetes/issues/6513
qp.append_pair("timeoutSeconds", &lp.timeout.unwrap_or(290).to_string());
if let Some(fields) = &lp.field_selector {
qp.append_pair("fieldSelector", &fields);
qp.append_pair("fieldSelector", fields);
}
if let Some(labels) = &lp.label_selector {
qp.append_pair("labelSelector", &labels);
qp.append_pair("labelSelector", labels);
}
if lp.bookmarks {
qp.append_pair("allowWatchBookmarks", "true");
Expand Down Expand Up @@ -120,10 +120,10 @@ impl Request {
let target = format!("{}?", self.url_path);
let mut qp = form_urlencoded::Serializer::new(target);
if let Some(fields) = &lp.field_selector {
qp.append_pair("fieldSelector", &fields);
qp.append_pair("fieldSelector", fields);
}
if let Some(labels) = &lp.label_selector {
qp.append_pair("labelSelector", &labels);
qp.append_pair("labelSelector", labels);
}
let urlstr = qp.finish();
let body = serde_json::to_vec(&dp)?;
Expand Down
2 changes: 1 addition & 1 deletion kube-core/src/subresource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ impl Request {
let mut qp = form_urlencoded::Serializer::new(target);

if let Some(container) = &lp.container {
qp.append_pair("container", &container);
qp.append_pair("container", container);
}

if lp.follow {
Expand Down
11 changes: 7 additions & 4 deletions kube-derive/src/custom_resource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,9 @@ pub(crate) fn derive(input: proc_macro2::TokenStream) -> proc_macro2::TokenStrea
let apiext = quote! {
k8s_openapi::apiextensions_apiserver::pkg::apis::apiextensions::#v1ident
};
let extver = quote! {
kube::core::crd::#v1ident
};

let short_json = serde_json::to_string(&shortnames).unwrap();
let crd_meta_name = format!("{}.{}", plural, group);
Expand Down Expand Up @@ -329,10 +332,10 @@ pub(crate) fn derive(input: proc_macro2::TokenStream) -> proc_macro2::TokenStrea
}
};

// Implement the ::crd and ::api_resource methods (fine to not have in a trait as its a generated type)
// Implement the CustomResourcExt trait to allow users writing generic logic on top of them
let impl_crd = quote! {
impl #rootident {
pub fn crd() -> #apiext::CustomResourceDefinition {
impl #extver::CustomResourceExt for #rootident {
fn crd() -> #apiext::CustomResourceDefinition {
let columns : Vec<#apiext::CustomResourceColumnDefinition> = serde_json::from_str(#printers).expect("valid printer column json");
let scale: Option<#apiext::CustomResourceSubresourceScale> = if #scale_code.is_empty() {
None
Expand All @@ -358,7 +361,7 @@ pub(crate) fn derive(input: proc_macro2::TokenStream) -> proc_macro2::TokenStrea
.expect("valid custom resource from #[kube(attrs..)]")
}

pub fn api_resource() -> kube::core::ApiResource {
fn api_resource() -> kube::core::ApiResource {
kube::core::ApiResource::erase::<Self>(&())
}
}
Expand Down
11 changes: 7 additions & 4 deletions kube-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ mod custom_resource;
/// This root object will implement the [`kube::Resource`] trait
/// so it can be used with [`kube::Api`].
///
/// The generated type will also implement a `::crd` method to generate the crd
/// at the specified api version (or `v1` if unspecified).
/// The generated type will also implement kube's [`kube::CustomResourceExt`] trait to generate the crd
/// and generate [`kube::core::ApiResource`] information for use with the dynamic api.
///
/// # Example
///
/// ```rust
/// use serde::{Serialize, Deserialize};
/// use kube::Resource;
/// use kube::{Resource, CustomResourceExt};
/// use kube_derive::CustomResource;
/// use schemars::JsonSchema;
///
Expand Down Expand Up @@ -72,7 +72,8 @@ mod custom_resource;
/// The version for `CustomResourceDefinition` desired in the `apiextensions.k8s.io` group.
/// Default is `v1` (for clusters >= 1.17). If using kubernetes <= 1.16 please use `v1beta1`.
///
/// **NOTE**: Support for `v1` requires deriving the openapi v3 `JsonSchema` via the `schemars` dependency.
/// - **NOTE**: Support for `v1` requires deriving the openapi v3 `JsonSchema` via the `schemars` dependency.
/// - **NOTE**: When using `v1beta` the associated `CustomResourceExt` trait lives in `kube::core::crd::v1beta`
///
/// ### `#[kube(singular = "nonstandard-singular")]`
/// To specify the singular name. Defaults to lowercased `kind`.
Expand Down Expand Up @@ -196,6 +197,8 @@ mod custom_resource;
/// [`kube`]: https://docs.rs/kube
/// [`kube::Api`]: https://docs.rs/kube/*/kube/struct.Api.html
/// [`kube::Resource`]: https://docs.rs/kube/*/kube/trait.Resource.html
/// [`kube::core::ApiResource`]: https://docs.rs/kube/*/kube/core/struct.ApiResource.html
/// [`kube::CustomResourceExt`]: https://docs.rs/kube/*/kube/trait.CustomResourceExt.html
#[proc_macro_derive(CustomResource, attributes(kube))]
pub fn derive_custom_resource(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
custom_resource::derive(proc_macro2::TokenStream::from(input)).into()
Expand Down
1 change: 1 addition & 0 deletions kube-derive/tests/crd_schema_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ fn default_nullable() -> Option<String> {

#[test]
fn test_crd_schema_matches_expected() {
use kube::core::CustomResourceExt;
assert_eq!(
Foo::crd(),
serde_json::from_value(serde_json::json!({
Expand Down
14 changes: 7 additions & 7 deletions kube/src/api/core_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ where
/// }
/// ```
pub async fn list(&self, lp: &ListParams) -> Result<ObjectList<K>> {
let mut req = self.request.list(&lp)?;
let mut req = self.request.list(lp)?;
req.extensions_mut().insert("list");
self.client.request::<ObjectList<K>>(req).await
}
Expand All @@ -75,7 +75,7 @@ where
K: Serialize,
{
let bytes = serde_json::to_vec(&data)?;
let mut req = self.request.create(&pp, bytes)?;
let mut req = self.request.create(pp, bytes)?;
req.extensions_mut().insert("create");
self.client.request::<K>(req).await
}
Expand Down Expand Up @@ -103,7 +103,7 @@ where
/// }
/// ```
pub async fn delete(&self, name: &str, dp: &DeleteParams) -> Result<Either<K, Status>> {
let mut req = self.request.delete(name, &dp)?;
let mut req = self.request.delete(name, dp)?;
req.extensions_mut().insert("delete");
self.client.request_status::<K>(req).await
}
Expand Down Expand Up @@ -140,7 +140,7 @@ where
dp: &DeleteParams,
lp: &ListParams,
) -> Result<Either<ObjectList<K>, Status>> {
let mut req = self.request.delete_collection(&dp, &lp)?;
let mut req = self.request.delete_collection(dp, lp)?;
req.extensions_mut().insert("delete_collection");
self.client.request_status::<ObjectList<K>>(req).await
}
Expand Down Expand Up @@ -180,7 +180,7 @@ where
pp: &PatchParams,
patch: &Patch<P>,
) -> Result<K> {
let mut req = self.request.patch(name, &pp, patch)?;
let mut req = self.request.patch(name, pp, patch)?;
req.extensions_mut().insert("patch");
self.client.request::<K>(req).await
}
Expand Down Expand Up @@ -234,7 +234,7 @@ where
K: Serialize,
{
let bytes = serde_json::to_vec(&data)?;
let mut req = self.request.replace(name, &pp, bytes)?;
let mut req = self.request.replace(name, pp, bytes)?;
req.extensions_mut().insert("replace");
self.client.request::<K>(req).await
}
Expand Down Expand Up @@ -281,7 +281,7 @@ where
lp: &ListParams,
version: &str,
) -> Result<impl Stream<Item = Result<WatchEvent<K>>>> {
let mut req = self.request.watch(&lp, &version)?;
let mut req = self.request.watch(lp, version)?;
req.extensions_mut().insert("watch");
self.client.request_events::<K>(req).await
}
Expand Down
8 changes: 4 additions & 4 deletions kube/src/api/subresource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@ where
pp: &PatchParams,
patch: &Patch<P>,
) -> Result<Scale> {
let mut req = self.request.patch_subresource("scale", name, &pp, patch)?;
let mut req = self.request.patch_subresource("scale", name, pp, patch)?;
req.extensions_mut().insert("patch_scale");
self.client.request::<Scale>(req).await
}

/// Replace the scale subresource
pub async fn replace_scale(&self, name: &str, pp: &PostParams, data: Vec<u8>) -> Result<Scale> {
let mut req = self.request.replace_subresource("scale", name, &pp, data)?;
let mut req = self.request.replace_subresource("scale", name, pp, data)?;
req.extensions_mut().insert("replace_scale");
self.client.request::<Scale>(req).await
}
Expand Down Expand Up @@ -98,7 +98,7 @@ where
pp: &PatchParams,
patch: &Patch<P>,
) -> Result<K> {
let mut req = self.request.patch_subresource("status", name, &pp, patch)?;
let mut req = self.request.patch_subresource("status", name, pp, patch)?;
req.extensions_mut().insert("patch_status");
self.client.request::<K>(req).await
}
Expand All @@ -123,7 +123,7 @@ where
/// }
/// ```
pub async fn replace_status(&self, name: &str, pp: &PostParams, data: Vec<u8>) -> Result<K> {
let mut req = self.request.replace_subresource("status", name, &pp, data)?;
let mut req = self.request.replace_subresource("status", name, pp, data)?;
req.extensions_mut().insert("replace_status");
self.client.request::<K>(req).await
}
Expand Down
4 changes: 2 additions & 2 deletions kube/src/client/auth/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,9 +222,9 @@ fn token_from_gcp_provider(provider: &AuthProviderConfig) -> Result<ProviderToke

if let Some(field) = provider.config.get("token-key") {
let json_output: serde_json::Value = serde_json::from_slice(&output.stdout)?;
let token = extract_value(&json_output, &field)?;
let token = extract_value(&json_output, field)?;
if let Some(field) = provider.config.get("expiry-key") {
let expiry = extract_value(&json_output, &field)?;
let expiry = extract_value(&json_output, field)?;
let expiry = expiry
.parse::<DateTime<Utc>>()
.map_err(ConfigError::MalformedTokenExpirationDate)?;
Expand Down
6 changes: 3 additions & 3 deletions kube/src/client/tls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pub mod native_tls {
if let Some(ders) = root_cert {
for der in ders {
builder.add_root_certificate(
Certificate::from_der(&der).map_err(|e| Error::SslError(format!("{}", e)))?,
Certificate::from_der(der).map_err(|e| Error::SslError(format!("{}", e)))?,
);
}
}
Expand All @@ -40,8 +40,8 @@ pub mod native_tls {
// TODO Replace this with pure Rust implementation to avoid depending on openssl on macOS and Win
fn pkcs12_from_pem(pem: &[u8], password: &str) -> Result<Vec<u8>> {
use openssl::{pkcs12::Pkcs12, pkey::PKey, x509::X509};
let x509 = X509::from_pem(&pem)?;
let pkey = PKey::private_key_from_pem(&pem)?;
let x509 = X509::from_pem(pem)?;
let pkey = PKey::private_key_from_pem(pem)?;
let p12 = Pkcs12::builder().build(password, "kubeconfig", &pkey, &x509)?;
let der = p12.to_der()?;
Ok(der)
Expand Down
2 changes: 1 addition & 1 deletion kube/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ impl Config {

if let Some(ca_bundle) = loader.ca_bundle()? {
for ca in &ca_bundle {
accept_invalid_certs = hacky_cert_lifetime_for_macos(&ca);
accept_invalid_certs = hacky_cert_lifetime_for_macos(ca);
}
root_cert = Some(ca_bundle);
}
Expand Down
Loading