@@ -28,14 +28,25 @@ pub enum Error {
2828}
2929
3030/// Build RBAC objects for the product workloads.
31- /// The `rbac_prefix` is meant to be the product name, for example: zookeeper, airflow, etc.
32- /// and it is a assumed that a ClusterRole named `{rbac_prefix}-clusterrole` exists.
31+ /// The `product_name` is meant to be the product name, for example: zookeeper, airflow, etc.
32+ /// and it is a assumed that a ClusterRole named `{product_name}-clusterrole` exists.
33+
3334pub fn build_rbac_resources < T : Clone + Resource < DynamicType = ( ) > > (
3435 resource : & T ,
35- rbac_prefix : & str ,
36+ // 'product_name' is not used to build the names of the serviceAccount and roleBinding objects,
37+ // as this caused problems with multiple clusters of the same product within the same namespace
38+ // see <https://stackable.atlassian.net/browse/SUP-148> for more details.
39+ // Instead the names for these objects are created by reading the name from the cluster object
40+ // and appending [-rolebinding|-serviceaccount] to create unique names instead of using the
41+ // same objects for multiple clusters.
42+ product_name : & str ,
3643 labels : Labels ,
3744) -> Result < ( ServiceAccount , RoleBinding ) > {
38- let sa_name = service_account_name ( rbac_prefix) ;
45+ let sa_name = service_account_name ( & resource. name_any ( ) ) ;
46+ // We add the legacy serviceAccount name to the binding here for at least one
47+ // release cycle, so that the switchover during the upgrade can be smoother.
48+ // To be removed in v24.3+1.
49+ let legacy_sa_name = service_account_name ( product_name) ;
3950 let service_account = ServiceAccount {
4051 metadata : ObjectMetaBuilder :: new ( )
4152 . name_and_namespace ( resource)
@@ -52,7 +63,7 @@ pub fn build_rbac_resources<T: Clone + Resource<DynamicType = ()>>(
5263 let role_binding = RoleBinding {
5364 metadata : ObjectMetaBuilder :: new ( )
5465 . name_and_namespace ( resource)
55- . name ( role_binding_name ( rbac_prefix ) )
66+ . name ( role_binding_name ( & resource . name_any ( ) ) )
5667 . ownerreference_from_resource ( resource, None , Some ( true ) )
5768 . context ( RoleBindingOwnerReferenceFromResourceSnafu {
5869 name : resource. name_any ( ) ,
@@ -61,29 +72,45 @@ pub fn build_rbac_resources<T: Clone + Resource<DynamicType = ()>>(
6172 . build ( ) ,
6273 role_ref : RoleRef {
6374 kind : "ClusterRole" . to_string ( ) ,
64- name : format ! ( "{rbac_prefix }-clusterrole" ) ,
75+ name : format ! ( "{product_name }-clusterrole" ) ,
6576 api_group : "rbac.authorization.k8s.io" . to_string ( ) ,
6677 } ,
67- subjects : Some ( vec ! [ Subject {
68- kind: "ServiceAccount" . to_string( ) ,
69- name: sa_name,
70- namespace: resource. namespace( ) ,
71- ..Subject :: default ( )
72- } ] ) ,
78+ subjects : Some ( vec ! [
79+ Subject {
80+ kind: "ServiceAccount" . to_string( ) ,
81+ name: sa_name,
82+ namespace: resource. namespace( ) ,
83+ ..Subject :: default ( )
84+ } ,
85+ // We add the legacy serviceAccount name to the binding here for at least one
86+ // release cycle, so that the switchover during the upgrade can be smoother.
87+ Subject {
88+ kind: "ServiceAccount" . to_string( ) ,
89+ name: legacy_sa_name,
90+ namespace: resource. namespace( ) ,
91+ ..Subject :: default ( )
92+ } ,
93+ ] ) ,
7394 } ;
7495
7596 Ok ( ( service_account, role_binding) )
7697}
7798
7899/// Generate the service account name.
79100/// The `rbac_prefix` is meant to be the product name, for example: zookeeper, airflow, etc.
80- pub fn service_account_name ( rbac_prefix : & str ) -> String {
101+ /// This is private because operators should not use this function to calculate names for
102+ /// serviceAccount objects, but rather read the name from the objects returned by
103+ /// `build_rbac_resources` if they need the name.
104+ fn service_account_name ( rbac_prefix : & str ) -> String {
81105 format ! ( "{rbac_prefix}-serviceaccount" )
82106}
83107
84108/// Generate the role binding name.
85109/// The `rbac_prefix` is meant to be the product name, for example: zookeeper, airflow, etc.
86- pub fn role_binding_name ( rbac_prefix : & str ) -> String {
110+ /// This is private because operators should not use this function to calculate names for
111+ /// roleBinding objects, but rather read the name from the objects returned by
112+ /// `build_rbac_resources` if they need the name.
113+ fn role_binding_name ( rbac_prefix : & str ) -> String {
87114 format ! ( "{rbac_prefix}-rolebinding" )
88115}
89116
@@ -130,7 +157,7 @@ mod tests {
130157 build_rbac_resources ( & cluster, RESOURCE_NAME , Labels :: new ( ) ) . unwrap ( ) ;
131158
132159 assert_eq ! (
133- Some ( service_account_name( RESOURCE_NAME ) ) ,
160+ Some ( service_account_name( CLUSTER_NAME ) ) ,
134161 rbac_sa. metadata. name,
135162 "service account does not match"
136163 ) ;
@@ -141,7 +168,7 @@ mod tests {
141168 ) ;
142169
143170 assert_eq ! (
144- Some ( role_binding_name( RESOURCE_NAME ) ) ,
171+ Some ( role_binding_name( CLUSTER_NAME ) ) ,
145172 rbac_rolebinding. metadata. name,
146173 "rolebinding does not match"
147174 ) ;
0 commit comments