@@ -10,8 +10,9 @@ use stackable_operator::{
1010 crd:: listener:: v1alpha1:: Listener ,
1111 k8s_openapi:: api:: {
1212 apps:: v1:: StatefulSet ,
13- core:: v1:: { ConfigMap , Service } ,
13+ core:: v1:: { ConfigMap , Service , ServiceAccount } ,
1414 policy:: v1:: PodDisruptionBudget ,
15+ rbac:: v1:: RoleBinding ,
1516 } ,
1617 kube:: { Resource , api:: ObjectMeta } ,
1718 kvp:: Labels ,
@@ -22,6 +23,7 @@ use stackable_operator::{
2223 builder:: meta:: ownerreference_from_resource,
2324 kvp:: label:: { recommended_labels, role_group_selector} ,
2425 role_group_utils:: ResourceNames ,
26+ role_utils,
2527 types:: {
2628 kubernetes:: { ListenerClassName , NamespaceName , SecretClassName , Uid } ,
2729 operator:: {
@@ -64,13 +66,18 @@ pub(crate) fn shared_spooling_secret_name(cluster_name: &ClusterName) -> String
6466 format ! ( "{cluster_name}-spooling-secret" )
6567}
6668
69+ // Placeholder version label value for resources whose labels must not change after deployment.
70+ stackable_operator:: constant!( UNVERSIONED_PRODUCT_VERSION : ProductVersion = "none" ) ;
71+
6772/// Every Kubernetes resource produced by the client-free [`build()`](build::build) step.
6873pub struct KubernetesResources {
6974 pub stateful_sets : Vec < StatefulSet > ,
7075 pub services : Vec < Service > ,
7176 pub listeners : Vec < Listener > ,
7277 pub config_maps : Vec < ConfigMap > ,
7378 pub pod_disruption_budgets : Vec < PodDisruptionBudget > ,
79+ pub service_accounts : Vec < ServiceAccount > ,
80+ pub role_bindings : Vec < RoleBinding > ,
7481}
7582
7683#[ derive( Clone , Debug ) ]
@@ -153,7 +160,11 @@ pub struct ValidatedCluster {
153160 pub namespace : NamespaceName ,
154161 pub uid : Uid ,
155162 pub image : ResolvedProductImage ,
156- pub product_version : u16 ,
163+ /// The numeric Trino version (e.g. `481`), used for version-dependent configuration.
164+ pub numeric_product_version : u16 ,
165+ /// The version label value (`app.kubernetes.io/version`) as a type-safe [`ProductVersion`],
166+ /// parsed once from the resolved image's app version label value.
167+ pub product_version : ProductVersion ,
157168 pub cluster_config : ValidatedClusterConfig ,
158169 pub role_configs : BTreeMap < TrinoRole , ValidatedRoleConfig > ,
159170 pub role_group_configs : BTreeMap < TrinoRole , BTreeMap < RoleGroupName , TrinoRoleGroupConfig > > ,
@@ -166,7 +177,7 @@ impl ValidatedCluster {
166177 namespace : NamespaceName ,
167178 uid : Uid ,
168179 image : ResolvedProductImage ,
169- product_version : u16 ,
180+ numeric_product_version : u16 ,
170181 cluster_config : ValidatedClusterConfig ,
171182 role_configs : BTreeMap < TrinoRole , ValidatedRoleConfig > ,
172183 role_group_configs : BTreeMap < TrinoRole , BTreeMap < RoleGroupName , TrinoRoleGroupConfig > > ,
@@ -181,8 +192,10 @@ impl ValidatedCluster {
181192 name,
182193 namespace,
183194 uid,
195+ product_version : ProductVersion :: from_str ( & image. app_version_label_value )
196+ . expect ( "the app version label value is a valid product version" ) ,
184197 image,
185- product_version ,
198+ numeric_product_version ,
186199 cluster_config,
187200 role_configs,
188201 role_group_configs,
@@ -219,6 +232,15 @@ impl ValidatedCluster {
219232 self . cluster_config . authentication_enabled ( ) || self . server_tls_enabled ( )
220233 }
221234
235+ /// Type-safe names for the per-cluster RBAC resources: the ServiceAccount shared by all
236+ /// Pods, its (namespaced) RoleBinding, and the operator-deployed ClusterRole it binds.
237+ pub fn rbac_resource_names ( & self ) -> role_utils:: ResourceNames {
238+ role_utils:: ResourceNames {
239+ cluster_name : self . name . clone ( ) ,
240+ product_name : product_name ( ) ,
241+ }
242+ }
243+
222244 /// Type-safe names for the resources of a given role group.
223245 pub ( crate ) fn resource_names (
224246 & self ,
@@ -270,16 +292,10 @@ impl ValidatedCluster {
270292 RoleName :: from_str ( & role. to_string ( ) ) . expect ( "a TrinoRole is a valid RFC 1123 role name" )
271293 }
272294
273- /// The version label value (`app.kubernetes.io/version`) as a type-safe [`ProductVersion`].
274- fn version_label ( & self ) -> ProductVersion {
275- ProductVersion :: from_str ( & self . image . app_version_label_value )
276- . expect ( "the app version label value is a valid product version" )
277- }
278-
279- fn recommended_labels_with_version (
295+ fn recommended_labels_with (
280296 & self ,
281297 version : & ProductVersion ,
282- role : & TrinoRole ,
298+ role_name : & RoleName ,
283299 role_group_name : & RoleGroupName ,
284300 ) -> Labels {
285301 recommended_labels (
@@ -288,38 +304,42 @@ impl ValidatedCluster {
288304 version,
289305 & operator_name ( ) ,
290306 & controller_name ( ) ,
291- & Self :: role_name ( role ) ,
307+ role_name,
292308 role_group_name,
293309 )
294310 }
295311
296312 /// Recommended labels for a role-group resource (using the resolved product version).
297- pub ( crate ) fn recommended_labels (
313+ pub fn recommended_labels ( & self , role : & TrinoRole , role_group_name : & RoleGroupName ) -> Labels {
314+ self . recommended_labels_for ( & Self :: role_name ( role) , role_group_name)
315+ }
316+
317+ /// Recommended labels for a resource that is not tied to a concrete [`TrinoRole`] (e.g. the
318+ /// cluster-shared RBAC resources), using a free-form role/role-group label value.
319+ pub fn recommended_labels_for (
298320 & self ,
299- role : & TrinoRole ,
321+ role_name : & RoleName ,
300322 role_group_name : & RoleGroupName ,
301323 ) -> Labels {
302- self . recommended_labels_with_version ( & self . version_label ( ) , role , role_group_name)
324+ self . recommended_labels_with ( & self . product_version , role_name , role_group_name)
303325 }
304326
305- /// Recommended labels using a fixed `"none"` version , for resources whose labels must not
306- /// change after creation (e.g. listener PVC templates).
307- pub ( crate ) fn unversioned_recommended_labels (
327+ /// Recommended labels with the constant [`UNVERSIONED_PRODUCT_VERSION`] , for resources whose
328+ /// labels must not change after creation (e.g. listener PVC templates).
329+ pub fn unversioned_recommended_labels (
308330 & self ,
309331 role : & TrinoRole ,
310332 role_group_name : & RoleGroupName ,
311333 ) -> Labels {
312- let none = ProductVersion :: from_str ( "none" )
313- . expect ( "\" none\" is a valid product version label value" ) ;
314- self . recommended_labels_with_version ( & none, role, role_group_name)
334+ self . recommended_labels_with (
335+ & UNVERSIONED_PRODUCT_VERSION ,
336+ & Self :: role_name ( role) ,
337+ role_group_name,
338+ )
315339 }
316340
317341 /// Selector labels matching the pods of a role group.
318- pub ( crate ) fn role_group_selector (
319- & self ,
320- role : & TrinoRole ,
321- role_group_name : & RoleGroupName ,
322- ) -> Labels {
342+ pub fn role_group_selector ( & self , role : & TrinoRole , role_group_name : & RoleGroupName ) -> Labels {
323343 role_group_selector (
324344 self ,
325345 & product_name ( ) ,
0 commit comments