@@ -28,14 +28,25 @@ pub enum Error {
28
28
}
29
29
30
30
/// 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
+
33
34
pub fn build_rbac_resources < T : Clone + Resource < DynamicType = ( ) > > (
34
35
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 ,
36
43
labels : Labels ,
37
44
) -> 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) ;
39
50
let service_account = ServiceAccount {
40
51
metadata : ObjectMetaBuilder :: new ( )
41
52
. name_and_namespace ( resource)
@@ -52,7 +63,7 @@ pub fn build_rbac_resources<T: Clone + Resource<DynamicType = ()>>(
52
63
let role_binding = RoleBinding {
53
64
metadata : ObjectMetaBuilder :: new ( )
54
65
. name_and_namespace ( resource)
55
- . name ( role_binding_name ( rbac_prefix ) )
66
+ . name ( role_binding_name ( & resource . name_any ( ) ) )
56
67
. ownerreference_from_resource ( resource, None , Some ( true ) )
57
68
. context ( RoleBindingOwnerReferenceFromResourceSnafu {
58
69
name : resource. name_any ( ) ,
@@ -61,29 +72,45 @@ pub fn build_rbac_resources<T: Clone + Resource<DynamicType = ()>>(
61
72
. build ( ) ,
62
73
role_ref : RoleRef {
63
74
kind : "ClusterRole" . to_string ( ) ,
64
- name : format ! ( "{rbac_prefix }-clusterrole" ) ,
75
+ name : format ! ( "{product_name }-clusterrole" ) ,
65
76
api_group : "rbac.authorization.k8s.io" . to_string ( ) ,
66
77
} ,
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
+ ] ) ,
73
94
} ;
74
95
75
96
Ok ( ( service_account, role_binding) )
76
97
}
77
98
78
99
/// Generate the service account name.
79
100
/// 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 {
81
105
format ! ( "{rbac_prefix}-serviceaccount" )
82
106
}
83
107
84
108
/// Generate the role binding name.
85
109
/// 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 {
87
114
format ! ( "{rbac_prefix}-rolebinding" )
88
115
}
89
116
@@ -130,7 +157,7 @@ mod tests {
130
157
build_rbac_resources ( & cluster, RESOURCE_NAME , Labels :: new ( ) ) . unwrap ( ) ;
131
158
132
159
assert_eq ! (
133
- Some ( service_account_name( RESOURCE_NAME ) ) ,
160
+ Some ( service_account_name( CLUSTER_NAME ) ) ,
134
161
rbac_sa. metadata. name,
135
162
"service account does not match"
136
163
) ;
@@ -141,7 +168,7 @@ mod tests {
141
168
) ;
142
169
143
170
assert_eq ! (
144
- Some ( role_binding_name( RESOURCE_NAME ) ) ,
171
+ Some ( role_binding_name( CLUSTER_NAME ) ) ,
145
172
rbac_rolebinding. metadata. name,
146
173
"rolebinding does not match"
147
174
) ;
0 commit comments