diff --git a/crates/stackable-operator/CHANGELOG.md b/crates/stackable-operator/CHANGELOG.md
index c90f09dd..a7364352 100644
--- a/crates/stackable-operator/CHANGELOG.md
+++ b/crates/stackable-operator/CHANGELOG.md
@@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file.
### Fixed
+- Fix the logback configuration for logback versions from 1.3.6/1.4.6 to 1.3.11/1.4.11 ([#874]).
- BREAKING: Avoid clashing volumes and mounts by only adding volumes or mounts if they do not already exist. This makes functions such as `PodBuilder::add_volume` or `ContainerBuilder::add_volume_mount` as well as related ones fallible ([#871]).
### Changed
@@ -13,6 +14,7 @@ All notable changes to this project will be documented in this file.
- BREAKING: Remove the `unique_identifier` argument from `ResolvedS3Connection::add_volumes_and_mounts`, `ResolvedS3Connection::volumes_and_mounts` and `ResolvedS3Connection::credentials_mount_paths` as it is not needed anymore ([#871]).
[#871]: https://github.com/stackabletech/operator-rs/pull/871
+[#874]: https://github.com/stackabletech/operator-rs/pull/874
## [0.76.0] - 2024-09-19
diff --git a/crates/stackable-operator/src/product_logging/framework.rs b/crates/stackable-operator/src/product_logging/framework.rs
index ad0d16c3..5acfa2de 100644
--- a/crates/stackable-operator/src/product_logging/framework.rs
+++ b/crates/stackable-operator/src/product_logging/framework.rs
@@ -605,7 +605,19 @@ pub fn create_logback_config(
{max_log_file_size_in_mib}MB
- 5 seconds
+
+ 5000
diff --git a/crates/stackable-versioned-macros/src/attrs/common/container.rs b/crates/stackable-versioned-macros/src/attrs/common/container.rs
index d5a3ccb0..434c9e1a 100644
--- a/crates/stackable-versioned-macros/src/attrs/common/container.rs
+++ b/crates/stackable-versioned-macros/src/attrs/common/container.rs
@@ -141,7 +141,10 @@ pub(crate) struct OptionAttributes {
#[derive(Clone, Debug, FromMeta)]
pub(crate) struct KubernetesAttributes {
pub(crate) skip: Option,
+ pub(crate) singular: Option,
+ pub(crate) plural: Option,
pub(crate) kind: Option,
+ pub(crate) namespaced: Flag,
pub(crate) group: String,
}
diff --git a/crates/stackable-versioned-macros/src/codegen/common/container.rs b/crates/stackable-versioned-macros/src/codegen/common/container.rs
index 26011259..4472552d 100644
--- a/crates/stackable-versioned-macros/src/codegen/common/container.rs
+++ b/crates/stackable-versioned-macros/src/codegen/common/container.rs
@@ -1,5 +1,7 @@
use std::ops::Deref;
+use convert_case::{Case, Casing};
+use k8s_version::Version;
use proc_macro2::TokenStream;
use quote::format_ident;
use syn::{Attribute, Ident, Visibility};
@@ -52,6 +54,16 @@ impl IdentExt for Ident {
}
}
+pub(crate) trait VersionExt {
+ fn as_variant_ident(&self) -> Ident;
+}
+
+impl VersionExt for Version {
+ fn as_variant_ident(&self) -> Ident {
+ format_ident!("{ident}", ident = self.to_string().to_case(Case::Pascal))
+ }
+}
+
/// This struct bundles values from [`DeriveInput`][1].
///
/// [`DeriveInput`][1] cannot be used directly when constructing a
@@ -118,6 +130,9 @@ impl VersionedContainer {
let kubernetes_options = attributes.kubernetes_attrs.map(|a| KubernetesOptions {
skip_merged_crd: a.skip.map_or(false, |s| s.merged_crd.is_present()),
+ namespaced: a.namespaced.is_present(),
+ singular: a.singular,
+ plural: a.plural,
group: a.group,
kind: a.kind,
});
@@ -166,7 +181,10 @@ pub(crate) struct VersionedContainerOptions {
#[derive(Debug)]
pub(crate) struct KubernetesOptions {
+ pub(crate) singular: Option,
+ pub(crate) plural: Option,
pub(crate) skip_merged_crd: bool,
pub(crate) kind: Option,
+ pub(crate) namespaced: bool,
pub(crate) group: String,
}
diff --git a/crates/stackable-versioned-macros/src/codegen/vstruct/mod.rs b/crates/stackable-versioned-macros/src/codegen/vstruct/mod.rs
index 6dd49390..0c6b42c5 100644
--- a/crates/stackable-versioned-macros/src/codegen/vstruct/mod.rs
+++ b/crates/stackable-versioned-macros/src/codegen/vstruct/mod.rs
@@ -8,13 +8,17 @@ use syn::{parse_quote, DataStruct, Error, Ident};
use crate::{
attrs::common::ContainerAttributes,
codegen::{
- common::{Container, ContainerInput, ContainerVersion, Item, VersionedContainer},
+ common::{
+ Container, ContainerInput, ContainerVersion, Item, VersionExt, VersionedContainer,
+ },
vstruct::field::VersionedField,
},
};
pub(crate) mod field;
+type GenerateVersionReturn = (TokenStream, Option<(TokenStream, (Ident, String))>);
+
/// Stores individual versions of a single struct. Each version tracks field
/// actions, which describe if the field was added, renamed or deprecated in
/// that version. Fields which are not versioned, are included in every
@@ -85,24 +89,30 @@ impl Container for VersionedStruct {
}
fn generate_tokens(&self) -> TokenStream {
- let mut kubernetes_crd_fn_calls = TokenStream::new();
- let mut container_definition = TokenStream::new();
+ let mut tokens = TokenStream::new();
+
+ let mut enum_variants = Vec::new();
+ let mut crd_fn_calls = Vec::new();
let mut versions = self.versions.iter().peekable();
while let Some(version) = versions.next() {
- container_definition.extend(self.generate_version(version, versions.peek().copied()));
- kubernetes_crd_fn_calls.extend(self.generate_kubernetes_crd_fn_call(version));
+ let (container_definition, merged_crd) =
+ self.generate_version(version, versions.peek().copied());
+
+ if let Some((crd_fn_call, enum_variant)) = merged_crd {
+ enum_variants.push(enum_variant);
+ crd_fn_calls.push(crd_fn_call);
+ }
+
+ tokens.extend(container_definition);
}
- // If tokens for the 'crd()' function calls were generated, also generate
- // the 'merge_crds' call.
- if !kubernetes_crd_fn_calls.is_empty() {
- container_definition
- .extend(self.generate_kubernetes_merge_crds(kubernetes_crd_fn_calls));
+ if !crd_fn_calls.is_empty() {
+ tokens.extend(self.generate_kubernetes_merge_crds(crd_fn_calls, enum_variants));
}
- container_definition
+ tokens
}
}
@@ -112,7 +122,7 @@ impl VersionedStruct {
&self,
version: &ContainerVersion,
next_version: Option<&ContainerVersion>,
- ) -> TokenStream {
+ ) -> GenerateVersionReturn {
let mut token_stream = TokenStream::new();
let original_attributes = &self.original_attributes;
@@ -137,7 +147,27 @@ impl VersionedStruct {
let version_specific_docs = self.generate_struct_docs(version);
// Generate K8s specific code
- let kubernetes_cr_derive = self.generate_kubernetes_cr_derive(version);
+ let (kubernetes_cr_derive, merged_crd) = match &self.options.kubernetes_options {
+ Some(options) => {
+ // Generate the CustomResource derive macro with the appropriate
+ // attributes supplied using #[kube()].
+ let cr_derive = self.generate_kubernetes_cr_derive(version);
+
+ // Generate merged_crd specific code when not opted out.
+ let merged_crd = if !options.skip_merged_crd {
+ let crd_fn_call = self.generate_kubernetes_crd_fn_call(version);
+ let enum_variant = version.inner.as_variant_ident();
+ let enum_display = version.inner.to_string();
+
+ Some((crd_fn_call, (enum_variant, enum_display)))
+ } else {
+ None
+ };
+
+ (Some(cr_derive), merged_crd)
+ }
+ None => (None, None),
+ };
// Generate tokens for the module and the contained struct
token_stream.extend(quote! {
@@ -160,7 +190,7 @@ impl VersionedStruct {
token_stream.extend(self.generate_from_impl(version, next_version));
}
- token_stream
+ (token_stream, merged_crd)
}
/// Generates version specific doc comments for the struct.
@@ -253,6 +283,7 @@ impl VersionedStruct {
/// attributes.
fn generate_kubernetes_cr_derive(&self, version: &ContainerVersion) -> Option {
if let Some(kubernetes_options) = &self.options.kubernetes_options {
+ // Required arguments
let group = &kubernetes_options.group;
let version = version.inner.to_string();
let kind = kubernetes_options
@@ -260,9 +291,22 @@ impl VersionedStruct {
.as_ref()
.map_or(self.idents.kubernetes.to_string(), |kind| kind.clone());
+ // Optional arguments
+ let namespaced = kubernetes_options
+ .namespaced
+ .then_some(quote! { , namespaced });
+ let singular = kubernetes_options
+ .singular
+ .as_ref()
+ .map(|s| quote! { , singular = #s });
+ let plural = kubernetes_options
+ .plural
+ .as_ref()
+ .map(|p| quote! { , plural = #p });
+
return Some(quote! {
#[derive(::kube::CustomResource)]
- #[kube(group = #group, version = #version, kind = #kind)]
+ #[kube(group = #group, version = #version, kind = #kind #singular #plural #namespaced)]
});
}
@@ -270,21 +314,29 @@ impl VersionedStruct {
}
/// Generates the `merge_crds` function call.
- fn generate_kubernetes_merge_crds(&self, fn_calls: TokenStream) -> TokenStream {
+ fn generate_kubernetes_merge_crds(
+ &self,
+ crd_fn_calls: Vec,
+ enum_variants: Vec<(Ident, String)>,
+ ) -> TokenStream {
let ident = &self.idents.kubernetes;
+ let version_enum_definition = self.generate_kubernetes_version_enum(enum_variants);
+
quote! {
#[automatically_derived]
pub struct #ident;
+ #version_enum_definition
+
#[automatically_derived]
impl #ident {
/// Generates a merged CRD which contains all versions defined using the
/// `#[versioned()]` macro.
pub fn merged_crd(
- stored_apiversion: &str
+ stored_apiversion: Version
) -> ::std::result::Result<::k8s_openapi::apiextensions_apiserver::pkg::apis::apiextensions::v1::CustomResourceDefinition, ::kube::core::crd::MergeError> {
- ::kube::core::crd::merge_crds(vec![#fn_calls], stored_apiversion)
+ ::kube::core::crd::merge_crds(vec![#(#crd_fn_calls),*], &stored_apiversion.to_string())
}
}
}
@@ -292,22 +344,41 @@ impl VersionedStruct {
/// Generates the inner `crd()` functions calls which get used in the
/// `merge_crds` function.
- fn generate_kubernetes_crd_fn_call(&self, version: &ContainerVersion) -> Option {
- if self
- .options
- .kubernetes_options
- .as_ref()
- .is_some_and(|o| !o.skip_merged_crd)
- {
- let struct_ident = &self.idents.kubernetes;
- let version_ident = &version.ident;
-
- let path: syn::Path = parse_quote!(#version_ident::#struct_ident);
- return Some(quote! {
- <#path as ::kube::CustomResourceExt>::crd(),
+ fn generate_kubernetes_crd_fn_call(&self, version: &ContainerVersion) -> TokenStream {
+ let struct_ident = &self.idents.kubernetes;
+ let version_ident = &version.ident;
+ let path: syn::Path = parse_quote!(#version_ident::#struct_ident);
+
+ quote! {
+ <#path as ::kube::CustomResourceExt>::crd()
+ }
+ }
+
+ fn generate_kubernetes_version_enum(&self, enum_variants: Vec<(Ident, String)>) -> TokenStream {
+ let mut enum_variant_matches = TokenStream::new();
+ let mut enum_variant_idents = TokenStream::new();
+
+ for (enum_variant_ident, enum_variant_display) in enum_variants {
+ enum_variant_idents.extend(quote! {#enum_variant_ident,});
+ enum_variant_matches.extend(quote! {
+ Version::#enum_variant_ident => f.write_str(#enum_variant_display),
});
}
- None
+ quote! {
+ #[automatically_derived]
+ pub enum Version {
+ #enum_variant_idents
+ }
+
+ #[automatically_derived]
+ impl ::std::fmt::Display for Version {
+ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::result::Result<(), ::std::fmt::Error> {
+ match self {
+ #enum_variant_matches
+ }
+ }
+ }
+ }
}
}
diff --git a/crates/stackable-versioned-macros/src/lib.rs b/crates/stackable-versioned-macros/src/lib.rs
index 9aa688f3..814b1c62 100644
--- a/crates/stackable-versioned-macros/src/lib.rs
+++ b/crates/stackable-versioned-macros/src/lib.rs
@@ -462,6 +462,15 @@ println!("{}", serde_yaml::to_string(&merged_crd).unwrap());
```
"#
)]
+/// Currently, the following arguments are supported:
+///
+/// - `group`: Sets the CRD group, usually the domain of the company.
+/// - `kind`: Allows overwriting the kind field of the CRD. This defaults
+/// to the struct name (without the 'Spec' suffix).
+/// - `singular`: Sets the singular name.
+/// - `plural`: Sets the plural name.
+/// - `namespaced`: Specifies that this is a namespaced resource rather than
+/// a cluster scoped.
#[proc_macro_attribute]
pub fn versioned(attrs: TokenStream, input: TokenStream) -> TokenStream {
let attrs = match NestedMeta::parse_meta_list(attrs.into()) {
diff --git a/crates/stackable-versioned-macros/tests/k8s/pass/crd.rs b/crates/stackable-versioned-macros/tests/k8s/pass/crd.rs
index 0defd825..73f690dc 100644
--- a/crates/stackable-versioned-macros/tests/k8s/pass/crd.rs
+++ b/crates/stackable-versioned-macros/tests/k8s/pass/crd.rs
@@ -9,7 +9,12 @@ fn main() {
version(name = "v1alpha1"),
version(name = "v1beta1"),
version(name = "v1"),
- k8s(group = "stackable.tech")
+ k8s(
+ group = "stackable.tech",
+ singular = "foo",
+ plural = "foos",
+ namespaced,
+ )
)]
#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)]
pub struct FooSpec {
@@ -21,6 +26,6 @@ fn main() {
baz: bool,
}
- let merged_crd = Foo::merged_crd("v1").unwrap();
+ let merged_crd = Foo::merged_crd(Version::V1).unwrap();
println!("{}", serde_yaml::to_string(&merged_crd).unwrap());
}
diff --git a/crates/stackable-versioned/CHANGELOG.md b/crates/stackable-versioned/CHANGELOG.md
index 053abf13..6b6f561e 100644
--- a/crates/stackable-versioned/CHANGELOG.md
+++ b/crates/stackable-versioned/CHANGELOG.md
@@ -4,6 +4,21 @@ All notable changes to this project will be documented in this file.
## [Unreleased]
+### Added
+
+- Add forwarding of `singular`, `plural`, and `namespaced` arguments in `k8s()`
+ ([#873]).
+- Generate a `Version` enum containing all declared versions as variants
+ ([#872]).
+
+### Changed
+
+- The `merged_crd` associated function now takes `Version` instead of `&str` as
+ input ([#872]).
+
+[#872]: https://github.com/stackabletech/operator-rs/pull/872
+[#873]: https://github.com/stackabletech/operator-rs/pull/873
+
## [0.2.0] - 2024-09-19
### Added