Skip to content

Commit 78bd455

Browse files
authored
Merge branch 'main' into fix/clashing-volumes-and-mounts-2
2 parents b7fcdaa + 8fcf506 commit 78bd455

File tree

8 files changed

+170
-35
lines changed

8 files changed

+170
-35
lines changed

crates/stackable-operator/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@ All notable changes to this project will be documented in this file.
66

77
### Fixed
88

9+
- Fix the logback configuration for logback versions from 1.3.6/1.4.6 to 1.3.11/1.4.11 ([#874]).
910
- 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]).
1011

1112
### Changed
1213

1314
- 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]).
1415

1516
[#871]: https://github.com/stackabletech/operator-rs/pull/871
17+
[#874]: https://github.com/stackabletech/operator-rs/pull/874
1618

1719
## [0.76.0] - 2024-09-19
1820

crates/stackable-operator/src/product_logging/framework.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,19 @@ pub fn create_logback_config(
605605
</rollingPolicy>
606606
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
607607
<MaxFileSize>{max_log_file_size_in_mib}MB</MaxFileSize>
608-
<checkIncrement>5 seconds</checkIncrement>
608+
<!--
609+
checkIncrement defines how often file sizes are checked, because
610+
checking them is a relatively costly operation.
611+
checkIncrement was introduced in the SizeBasedTriggeringPolicy in
612+
logback 1.3.6/1.4.6 as an Integer representing milliseconds. In logback
613+
1.3.12/1.4.12, it was changed to a Duration, also accepting a unit.
614+
Without a given unit, milliseconds are assumed. The logback manual is
615+
misleading: In logback 1.5.8, checkIncrement is no longer used for the
616+
SizeAndTimeBasedFileNamingAndTriggeringPolicy, but it is still used for
617+
the SizeBasedTriggeringPolicy!
618+
In prior versions of logback, setting this option has no effect.
619+
-->
620+
<checkIncrement>5000</checkIncrement>
609621
</triggeringPolicy>
610622
</appender>
611623

crates/stackable-versioned-macros/src/attrs/common/container.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,10 @@ pub(crate) struct OptionAttributes {
141141
#[derive(Clone, Debug, FromMeta)]
142142
pub(crate) struct KubernetesAttributes {
143143
pub(crate) skip: Option<KubernetesSkipAttributes>,
144+
pub(crate) singular: Option<String>,
145+
pub(crate) plural: Option<String>,
144146
pub(crate) kind: Option<String>,
147+
pub(crate) namespaced: Flag,
145148
pub(crate) group: String,
146149
}
147150

crates/stackable-versioned-macros/src/codegen/common/container.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use std::ops::Deref;
22

3+
use convert_case::{Case, Casing};
4+
use k8s_version::Version;
35
use proc_macro2::TokenStream;
46
use quote::format_ident;
57
use syn::{Attribute, Ident, Visibility};
@@ -52,6 +54,16 @@ impl IdentExt for Ident {
5254
}
5355
}
5456

57+
pub(crate) trait VersionExt {
58+
fn as_variant_ident(&self) -> Ident;
59+
}
60+
61+
impl VersionExt for Version {
62+
fn as_variant_ident(&self) -> Ident {
63+
format_ident!("{ident}", ident = self.to_string().to_case(Case::Pascal))
64+
}
65+
}
66+
5567
/// This struct bundles values from [`DeriveInput`][1].
5668
///
5769
/// [`DeriveInput`][1] cannot be used directly when constructing a
@@ -118,6 +130,9 @@ impl<I> VersionedContainer<I> {
118130

119131
let kubernetes_options = attributes.kubernetes_attrs.map(|a| KubernetesOptions {
120132
skip_merged_crd: a.skip.map_or(false, |s| s.merged_crd.is_present()),
133+
namespaced: a.namespaced.is_present(),
134+
singular: a.singular,
135+
plural: a.plural,
121136
group: a.group,
122137
kind: a.kind,
123138
});
@@ -166,7 +181,10 @@ pub(crate) struct VersionedContainerOptions {
166181

167182
#[derive(Debug)]
168183
pub(crate) struct KubernetesOptions {
184+
pub(crate) singular: Option<String>,
185+
pub(crate) plural: Option<String>,
169186
pub(crate) skip_merged_crd: bool,
170187
pub(crate) kind: Option<String>,
188+
pub(crate) namespaced: bool,
171189
pub(crate) group: String,
172190
}

crates/stackable-versioned-macros/src/codegen/vstruct/mod.rs

Lines changed: 103 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,17 @@ use syn::{parse_quote, DataStruct, Error, Ident};
88
use crate::{
99
attrs::common::ContainerAttributes,
1010
codegen::{
11-
common::{Container, ContainerInput, ContainerVersion, Item, VersionedContainer},
11+
common::{
12+
Container, ContainerInput, ContainerVersion, Item, VersionExt, VersionedContainer,
13+
},
1214
vstruct::field::VersionedField,
1315
},
1416
};
1517

1618
pub(crate) mod field;
1719

20+
type GenerateVersionReturn = (TokenStream, Option<(TokenStream, (Ident, String))>);
21+
1822
/// Stores individual versions of a single struct. Each version tracks field
1923
/// actions, which describe if the field was added, renamed or deprecated in
2024
/// that version. Fields which are not versioned, are included in every
@@ -85,24 +89,30 @@ impl Container<DataStruct, VersionedField> for VersionedStruct {
8589
}
8690

8791
fn generate_tokens(&self) -> TokenStream {
88-
let mut kubernetes_crd_fn_calls = TokenStream::new();
89-
let mut container_definition = TokenStream::new();
92+
let mut tokens = TokenStream::new();
93+
94+
let mut enum_variants = Vec::new();
95+
let mut crd_fn_calls = Vec::new();
9096

9197
let mut versions = self.versions.iter().peekable();
9298

9399
while let Some(version) = versions.next() {
94-
container_definition.extend(self.generate_version(version, versions.peek().copied()));
95-
kubernetes_crd_fn_calls.extend(self.generate_kubernetes_crd_fn_call(version));
100+
let (container_definition, merged_crd) =
101+
self.generate_version(version, versions.peek().copied());
102+
103+
if let Some((crd_fn_call, enum_variant)) = merged_crd {
104+
enum_variants.push(enum_variant);
105+
crd_fn_calls.push(crd_fn_call);
106+
}
107+
108+
tokens.extend(container_definition);
96109
}
97110

98-
// If tokens for the 'crd()' function calls were generated, also generate
99-
// the 'merge_crds' call.
100-
if !kubernetes_crd_fn_calls.is_empty() {
101-
container_definition
102-
.extend(self.generate_kubernetes_merge_crds(kubernetes_crd_fn_calls));
111+
if !crd_fn_calls.is_empty() {
112+
tokens.extend(self.generate_kubernetes_merge_crds(crd_fn_calls, enum_variants));
103113
}
104114

105-
container_definition
115+
tokens
106116
}
107117
}
108118

@@ -112,7 +122,7 @@ impl VersionedStruct {
112122
&self,
113123
version: &ContainerVersion,
114124
next_version: Option<&ContainerVersion>,
115-
) -> TokenStream {
125+
) -> GenerateVersionReturn {
116126
let mut token_stream = TokenStream::new();
117127

118128
let original_attributes = &self.original_attributes;
@@ -137,7 +147,27 @@ impl VersionedStruct {
137147
let version_specific_docs = self.generate_struct_docs(version);
138148

139149
// Generate K8s specific code
140-
let kubernetes_cr_derive = self.generate_kubernetes_cr_derive(version);
150+
let (kubernetes_cr_derive, merged_crd) = match &self.options.kubernetes_options {
151+
Some(options) => {
152+
// Generate the CustomResource derive macro with the appropriate
153+
// attributes supplied using #[kube()].
154+
let cr_derive = self.generate_kubernetes_cr_derive(version);
155+
156+
// Generate merged_crd specific code when not opted out.
157+
let merged_crd = if !options.skip_merged_crd {
158+
let crd_fn_call = self.generate_kubernetes_crd_fn_call(version);
159+
let enum_variant = version.inner.as_variant_ident();
160+
let enum_display = version.inner.to_string();
161+
162+
Some((crd_fn_call, (enum_variant, enum_display)))
163+
} else {
164+
None
165+
};
166+
167+
(Some(cr_derive), merged_crd)
168+
}
169+
None => (None, None),
170+
};
141171

142172
// Generate tokens for the module and the contained struct
143173
token_stream.extend(quote! {
@@ -160,7 +190,7 @@ impl VersionedStruct {
160190
token_stream.extend(self.generate_from_impl(version, next_version));
161191
}
162192

163-
token_stream
193+
(token_stream, merged_crd)
164194
}
165195

166196
/// Generates version specific doc comments for the struct.
@@ -253,61 +283,102 @@ impl VersionedStruct {
253283
/// attributes.
254284
fn generate_kubernetes_cr_derive(&self, version: &ContainerVersion) -> Option<TokenStream> {
255285
if let Some(kubernetes_options) = &self.options.kubernetes_options {
286+
// Required arguments
256287
let group = &kubernetes_options.group;
257288
let version = version.inner.to_string();
258289
let kind = kubernetes_options
259290
.kind
260291
.as_ref()
261292
.map_or(self.idents.kubernetes.to_string(), |kind| kind.clone());
262293

294+
// Optional arguments
295+
let namespaced = kubernetes_options
296+
.namespaced
297+
.then_some(quote! { , namespaced });
298+
let singular = kubernetes_options
299+
.singular
300+
.as_ref()
301+
.map(|s| quote! { , singular = #s });
302+
let plural = kubernetes_options
303+
.plural
304+
.as_ref()
305+
.map(|p| quote! { , plural = #p });
306+
263307
return Some(quote! {
264308
#[derive(::kube::CustomResource)]
265-
#[kube(group = #group, version = #version, kind = #kind)]
309+
#[kube(group = #group, version = #version, kind = #kind #singular #plural #namespaced)]
266310
});
267311
}
268312

269313
None
270314
}
271315

272316
/// Generates the `merge_crds` function call.
273-
fn generate_kubernetes_merge_crds(&self, fn_calls: TokenStream) -> TokenStream {
317+
fn generate_kubernetes_merge_crds(
318+
&self,
319+
crd_fn_calls: Vec<TokenStream>,
320+
enum_variants: Vec<(Ident, String)>,
321+
) -> TokenStream {
274322
let ident = &self.idents.kubernetes;
275323

324+
let version_enum_definition = self.generate_kubernetes_version_enum(enum_variants);
325+
276326
quote! {
277327
#[automatically_derived]
278328
pub struct #ident;
279329

330+
#version_enum_definition
331+
280332
#[automatically_derived]
281333
impl #ident {
282334
/// Generates a merged CRD which contains all versions defined using the
283335
/// `#[versioned()]` macro.
284336
pub fn merged_crd(
285-
stored_apiversion: &str
337+
stored_apiversion: Version
286338
) -> ::std::result::Result<::k8s_openapi::apiextensions_apiserver::pkg::apis::apiextensions::v1::CustomResourceDefinition, ::kube::core::crd::MergeError> {
287-
::kube::core::crd::merge_crds(vec![#fn_calls], stored_apiversion)
339+
::kube::core::crd::merge_crds(vec![#(#crd_fn_calls),*], &stored_apiversion.to_string())
288340
}
289341
}
290342
}
291343
}
292344

293345
/// Generates the inner `crd()` functions calls which get used in the
294346
/// `merge_crds` function.
295-
fn generate_kubernetes_crd_fn_call(&self, version: &ContainerVersion) -> Option<TokenStream> {
296-
if self
297-
.options
298-
.kubernetes_options
299-
.as_ref()
300-
.is_some_and(|o| !o.skip_merged_crd)
301-
{
302-
let struct_ident = &self.idents.kubernetes;
303-
let version_ident = &version.ident;
304-
305-
let path: syn::Path = parse_quote!(#version_ident::#struct_ident);
306-
return Some(quote! {
307-
<#path as ::kube::CustomResourceExt>::crd(),
347+
fn generate_kubernetes_crd_fn_call(&self, version: &ContainerVersion) -> TokenStream {
348+
let struct_ident = &self.idents.kubernetes;
349+
let version_ident = &version.ident;
350+
let path: syn::Path = parse_quote!(#version_ident::#struct_ident);
351+
352+
quote! {
353+
<#path as ::kube::CustomResourceExt>::crd()
354+
}
355+
}
356+
357+
fn generate_kubernetes_version_enum(&self, enum_variants: Vec<(Ident, String)>) -> TokenStream {
358+
let mut enum_variant_matches = TokenStream::new();
359+
let mut enum_variant_idents = TokenStream::new();
360+
361+
for (enum_variant_ident, enum_variant_display) in enum_variants {
362+
enum_variant_idents.extend(quote! {#enum_variant_ident,});
363+
enum_variant_matches.extend(quote! {
364+
Version::#enum_variant_ident => f.write_str(#enum_variant_display),
308365
});
309366
}
310367

311-
None
368+
quote! {
369+
#[automatically_derived]
370+
pub enum Version {
371+
#enum_variant_idents
372+
}
373+
374+
#[automatically_derived]
375+
impl ::std::fmt::Display for Version {
376+
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::result::Result<(), ::std::fmt::Error> {
377+
match self {
378+
#enum_variant_matches
379+
}
380+
}
381+
}
382+
}
312383
}
313384
}

crates/stackable-versioned-macros/src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,15 @@ println!("{}", serde_yaml::to_string(&merged_crd).unwrap());
462462
```
463463
"#
464464
)]
465+
/// Currently, the following arguments are supported:
466+
///
467+
/// - `group`: Sets the CRD group, usually the domain of the company.
468+
/// - `kind`: Allows overwriting the kind field of the CRD. This defaults
469+
/// to the struct name (without the 'Spec' suffix).
470+
/// - `singular`: Sets the singular name.
471+
/// - `plural`: Sets the plural name.
472+
/// - `namespaced`: Specifies that this is a namespaced resource rather than
473+
/// a cluster scoped.
465474
#[proc_macro_attribute]
466475
pub fn versioned(attrs: TokenStream, input: TokenStream) -> TokenStream {
467476
let attrs = match NestedMeta::parse_meta_list(attrs.into()) {

crates/stackable-versioned-macros/tests/k8s/pass/crd.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,12 @@ fn main() {
99
version(name = "v1alpha1"),
1010
version(name = "v1beta1"),
1111
version(name = "v1"),
12-
k8s(group = "stackable.tech")
12+
k8s(
13+
group = "stackable.tech",
14+
singular = "foo",
15+
plural = "foos",
16+
namespaced,
17+
)
1318
)]
1419
#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)]
1520
pub struct FooSpec {
@@ -21,6 +26,6 @@ fn main() {
2126
baz: bool,
2227
}
2328

24-
let merged_crd = Foo::merged_crd("v1").unwrap();
29+
let merged_crd = Foo::merged_crd(Version::V1).unwrap();
2530
println!("{}", serde_yaml::to_string(&merged_crd).unwrap());
2631
}

crates/stackable-versioned/CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,21 @@ All notable changes to this project will be documented in this file.
44

55
## [Unreleased]
66

7+
### Added
8+
9+
- Add forwarding of `singular`, `plural`, and `namespaced` arguments in `k8s()`
10+
([#873]).
11+
- Generate a `Version` enum containing all declared versions as variants
12+
([#872]).
13+
14+
### Changed
15+
16+
- The `merged_crd` associated function now takes `Version` instead of `&str` as
17+
input ([#872]).
18+
19+
[#872]: https://github.com/stackabletech/operator-rs/pull/872
20+
[#873]: https://github.com/stackabletech/operator-rs/pull/873
21+
722
## [0.2.0] - 2024-09-19
823

924
### Added

0 commit comments

Comments
 (0)