Skip to content

Commit bfe7d14

Browse files
committed
pick old pr
1 parent d95e896 commit bfe7d14

File tree

5 files changed

+211
-5
lines changed

5 files changed

+211
-5
lines changed

controllers/apps/component/transformer_component_deletion.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,14 @@ func (t *componentDeletionTransformer) deleteCompResources(transCtx *componentTr
158158

159159
func handleRBACResourceDeletion(obj client.Object, transCtx *componentTransformContext, comp *appsv1.Component,
160160
graphCli model.GraphClient, dag *graph.DAG, matchLabels map[string]string) (err error) {
161+
// for new rule
162+
// rolebinding and serviceaccount have the same name
163+
newName := constant.GenerateDefaultServiceAccountNameNew(comp.Name)
164+
if obj.GetName() == newName {
165+
graphCli.Delete(dag, obj)
166+
return
167+
}
168+
161169
// orphan a rbac resource so that it can be adopted by another component
162170
// this means these resources won't get automatically deleted
163171
if err := controllerutil.RemoveControllerReference(comp, obj, model.GetScheme()); err != nil {

controllers/apps/component/transformer_component_rbac.go

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,26 @@ func (t *componentRBACTransformer) Transform(ctx graph.TransformContext, dag *gr
8888
return nil
8989
}
9090

91+
// user managed sa
92+
if serviceAccountName != "" {
93+
return t.handleRBACNewRule(transCtx, dag, serviceAccountName)
94+
}
95+
96+
// check if sa with old naming rule exists
97+
newName := constant.GenerateDefaultServiceAccountNameNew(synthesizedComp.FullCompName)
98+
newNameExists := true
99+
if err := transCtx.Client.Get(transCtx.Context, types.NamespacedName{Namespace: synthesizedComp.Namespace, Name: newName}, sa); err != nil {
100+
if !errors.IsNotFound(err) {
101+
return err
102+
}
103+
newNameExists = false
104+
}
105+
106+
if newNameExists || transCtx.RunningWorkload == nil {
107+
return t.handleRBACNewRule(transCtx, dag, "")
108+
}
109+
110+
// old code path
91111
var err error
92112
comp := transCtx.Component
93113
lastServiceAccountName := comp.Annotations[constant.ComponentLastServiceAccountNameAnnotationKey]
@@ -153,6 +173,93 @@ func (t *componentRBACTransformer) Transform(ctx graph.TransformContext, dag *gr
153173
return nil
154174
}
155175

176+
func (t *componentRBACTransformer) handleRBACNewRule(transCtx *componentTransformContext, dag *graph.DAG, userDefinedSAName string) error {
177+
synthesizedComp := transCtx.SynthesizeComponent
178+
graphCli, _ := transCtx.Client.(model.GraphClient)
179+
saName := userDefinedSAName
180+
var sa *corev1.ServiceAccount
181+
var err error
182+
if userDefinedSAName == "" {
183+
saName = constant.GenerateDefaultServiceAccountNameNew(synthesizedComp.FullCompName)
184+
// if no rolebinding is needed, sa will be created anyway, because other modules may reference it.
185+
sa, err = createOrUpdateServiceAccount(transCtx, saName, graphCli, dag)
186+
if err != nil {
187+
return err
188+
}
189+
}
190+
synthesizedComp.PodSpec.ServiceAccountName = saName
191+
rbs, err := createOrUpdateRoleBindingNew(transCtx, transCtx.CompDef, saName, graphCli, dag)
192+
if err != nil {
193+
return err
194+
}
195+
objs := []client.Object{sa}
196+
if sa != nil {
197+
// serviceAccount should be created before roleBinding and role
198+
for _, rb := range rbs {
199+
objs = append(objs, rb)
200+
graphCli.DependOn(dag, rb, sa)
201+
}
202+
// serviceAccount should be created before workload
203+
itsList := graphCli.FindAll(dag, &workloads.InstanceSet{})
204+
for _, its := range itsList {
205+
graphCli.DependOn(dag, its, sa)
206+
}
207+
}
208+
209+
t.rbacInstanceAssistantObjects(graphCli, dag, objs)
210+
return nil
211+
}
212+
213+
func createOrUpdateRoleBindingNew(transCtx *componentTransformContext,
214+
cmpd *appsv1.ComponentDefinition, serviceAccountName string, graphCli model.GraphClient, dag *graph.DAG) ([]*rbacv1.RoleBinding, error) {
215+
cmpRoleBinding := func(old, new *rbacv1.RoleBinding) bool {
216+
return labelAndAnnotationEqual(old, new) &&
217+
equality.Semantic.DeepEqual(old.Subjects, new.Subjects) &&
218+
equality.Semantic.DeepEqual(old.RoleRef, new.RoleRef)
219+
}
220+
res := make([]*rbacv1.RoleBinding, 0)
221+
222+
if len(cmpd.Spec.PolicyRules) != 0 {
223+
// cluster role is handled by cmpd controller
224+
cmpdRoleBinding := factory.BuildRoleBinding(transCtx.SynthesizeComponent, serviceAccountName, &rbacv1.RoleRef{
225+
APIGroup: rbacv1.GroupName,
226+
Kind: "ClusterRole",
227+
Name: constant.GenerateDefaultRoleName(cmpd.Name),
228+
}, serviceAccountName)
229+
if err := intctrlutil.SetOwnership(transCtx.Component, cmpdRoleBinding, model.GetScheme(), ""); err != nil {
230+
return nil, err
231+
}
232+
rb, err := createOrUpdate(transCtx, cmpdRoleBinding, graphCli, dag, cmpRoleBinding)
233+
if err != nil {
234+
return nil, err
235+
}
236+
res = append(res, rb)
237+
}
238+
239+
if isLifecycleActionsEnabled(transCtx.CompDef) {
240+
clusterPodRoleBinding := factory.BuildRoleBinding(
241+
transCtx.SynthesizeComponent,
242+
fmt.Sprintf("%v-pod", serviceAccountName),
243+
&rbacv1.RoleRef{
244+
APIGroup: rbacv1.GroupName,
245+
Kind: "ClusterRole",
246+
Name: constant.RBACRoleName,
247+
},
248+
serviceAccountName,
249+
)
250+
if err := intctrlutil.SetOwnership(transCtx.Component, clusterPodRoleBinding, model.GetScheme(), ""); err != nil {
251+
return nil, err
252+
}
253+
rb, err := createOrUpdate(transCtx, clusterPodRoleBinding, graphCli, dag, cmpRoleBinding)
254+
if err != nil {
255+
return nil, err
256+
}
257+
res = append(res, rb)
258+
}
259+
260+
return res, nil
261+
}
262+
156263
func (t *componentRBACTransformer) rbacInstanceAssistantObjects(graphCli model.GraphClient, dag *graph.DAG, objs []client.Object) {
157264
itsList := graphCli.FindAll(dag, &workloads.InstanceSet{})
158265
for _, itsObj := range itsList {

controllers/apps/componentdefinition_controller.go

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ import (
3030

3131
k8sappsv1 "k8s.io/api/apps/v1"
3232
corev1 "k8s.io/api/core/v1"
33+
rbacv1 "k8s.io/api/rbac/v1"
34+
"k8s.io/apimachinery/pkg/api/equality"
35+
"k8s.io/apimachinery/pkg/api/errors"
3336
"k8s.io/apimachinery/pkg/runtime"
3437
"k8s.io/apimachinery/pkg/util/rand"
3538
"k8s.io/apimachinery/pkg/util/sets"
@@ -40,8 +43,11 @@ import (
4043

4144
appsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
4245
"github.com/apecloud/kubeblocks/pkg/constant"
46+
"github.com/apecloud/kubeblocks/pkg/controller/builder"
4347
"github.com/apecloud/kubeblocks/pkg/controller/component"
48+
"github.com/apecloud/kubeblocks/pkg/controller/model"
4449
intctrlutil "github.com/apecloud/kubeblocks/pkg/controllerutil"
50+
viper "github.com/apecloud/kubeblocks/pkg/viperx"
4551
)
4652

4753
const (
@@ -89,9 +95,14 @@ func (r *ComponentDefinitionReconciler) Reconcile(ctx context.Context, req ctrl.
8995

9096
// SetupWithManager sets up the controller with the Manager.
9197
func (r *ComponentDefinitionReconciler) SetupWithManager(mgr ctrl.Manager) error {
92-
return intctrlutil.NewControllerManagedBy(mgr).
93-
For(&appsv1.ComponentDefinition{}).
94-
Complete(r)
98+
b := intctrlutil.NewControllerManagedBy(mgr).
99+
For(&appsv1.ComponentDefinition{})
100+
101+
if viper.GetBool(constant.EnableRBACManager) {
102+
b.Owns(&rbacv1.ClusterRole{})
103+
}
104+
105+
return b.Complete(r)
95106
}
96107

97108
func (r *ComponentDefinitionReconciler) reconcile(rctx intctrlutil.RequestCtx,
@@ -117,6 +128,10 @@ func (r *ComponentDefinitionReconciler) reconcile(rctx intctrlutil.RequestCtx,
117128
return intctrlutil.CheckedRequeueWithError(err, rctx.Log, "")
118129
}
119130

131+
if err = r.clusterRole(r.Client, rctx, cmpd); err != nil {
132+
return intctrlutil.RequeueWithError(err, rctx.Log, "")
133+
}
134+
120135
if err = r.available(r.Client, rctx, cmpd); err != nil {
121136
return intctrlutil.CheckedRequeueWithError(err, rctx.Log, "")
122137
}
@@ -181,6 +196,39 @@ func (r *ComponentDefinitionReconciler) immutableHash(cli client.Client, rctx in
181196
return cli.Patch(rctx.Ctx, cmpd, patch)
182197
}
183198

199+
func (r *ComponentDefinitionReconciler) clusterRole(cli client.Client, rctx intctrlutil.RequestCtx,
200+
cmpd *appsv1.ComponentDefinition) error {
201+
if !viper.GetBool(constant.EnableRBACManager) {
202+
return nil
203+
}
204+
205+
if len(cmpd.Spec.PolicyRules) == 0 {
206+
return nil
207+
}
208+
209+
clusterRole := builder.NewClusterRoleBuilder(constant.GenerateDefaultRoleName(cmpd.Name)).
210+
AddLabelsInMap(cmpd.Labels).
211+
AddAnnotationsInMap(cmpd.Annotations).
212+
AddPolicyRules(cmpd.Spec.PolicyRules).
213+
GetObject()
214+
if err := intctrlutil.SetOwnership(cmpd, clusterRole, model.GetScheme(), ""); err != nil {
215+
return err
216+
}
217+
oldClusterRole := &rbacv1.ClusterRole{}
218+
if err := cli.Get(rctx.Ctx, client.ObjectKeyFromObject(clusterRole), oldClusterRole); err != nil {
219+
if errors.IsNotFound(err) {
220+
return cli.Create(rctx.Ctx, clusterRole)
221+
}
222+
return err
223+
}
224+
if equality.Semantic.DeepEqual(oldClusterRole.Labels, clusterRole.Labels) &&
225+
equality.Semantic.DeepEqual(oldClusterRole.Annotations, clusterRole.Annotations) &&
226+
equality.Semantic.DeepEqual(oldClusterRole.Rules, clusterRole.Rules) {
227+
return nil
228+
}
229+
return cli.Update(rctx.Ctx, clusterRole)
230+
}
231+
184232
func (r *ComponentDefinitionReconciler) validate(cli client.Client, rctx intctrlutil.RequestCtx,
185233
cmpd *appsv1.ComponentDefinition) error {
186234
for _, validator := range []func(client.Client, intctrlutil.RequestCtx, *appsv1.ComponentDefinition) error{
@@ -409,8 +457,8 @@ func (r *ComponentDefinitionReconciler) validateAvailable(cli client.Client, rct
409457
}
410458

411459
func (r *ComponentDefinitionReconciler) validateAvailableWithPhases(cmpd *appsv1.ComponentDefinition) error {
412-
phases := sets.New[string](strings.Split(strings.ToLower(*cmpd.Spec.Available.WithPhases), ",")...)
413-
supported := sets.New[string](
460+
phases := sets.New(strings.Split(strings.ToLower(*cmpd.Spec.Available.WithPhases), ",")...)
461+
supported := sets.New(
414462
strings.ToLower(string(appsv1.CreatingComponentPhase)),
415463
strings.ToLower(string(appsv1.RunningComponentPhase)),
416464
strings.ToLower(string(appsv1.UpdatingComponentPhase)),

pkg/constant/pattern.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ func GenerateDefaultServiceAccountName(cmpdName string) string {
8383
return fmt.Sprintf("%s-%s", KBLowerPrefix, cmpdName)
8484
}
8585

86+
func GenerateDefaultServiceAccountNameNew(fullCompName string) string {
87+
return fmt.Sprintf("%s-%s", KBLowerPrefix, fullCompName)
88+
}
89+
8690
// GenerateDefaultRoleName generates default role name for a component.
8791
func GenerateDefaultRoleName(cmpdName string) string {
8892
return fmt.Sprintf("%s-%s", KBLowerPrefix, cmpdName)
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
Copyright (C) 2022-2025 ApeCloud Co., Ltd
3+
4+
This file is part of KubeBlocks project
5+
6+
This program is free software: you can redistribute it and/or modify
7+
it under the terms of the GNU Affero General Public License as published by
8+
the Free Software Foundation, either version 3 of the License, or
9+
(at your option) any later version.
10+
11+
This program is distributed in the hope that it will be useful
12+
but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
GNU Affero General Public License for more details.
15+
16+
You should have received a copy of the GNU Affero General Public License
17+
along with this program. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
20+
package builder
21+
22+
import (
23+
rbacv1 "k8s.io/api/rbac/v1"
24+
)
25+
26+
type ClusterRoleBuilder struct {
27+
BaseBuilder[rbacv1.ClusterRole, *rbacv1.ClusterRole, ClusterRoleBuilder]
28+
}
29+
30+
func NewClusterRoleBuilder(name string) *ClusterRoleBuilder {
31+
builder := &ClusterRoleBuilder{}
32+
builder.init("", name, &rbacv1.ClusterRole{}, builder)
33+
return builder
34+
}
35+
36+
func (builder *ClusterRoleBuilder) AddPolicyRules(rules []rbacv1.PolicyRule) *ClusterRoleBuilder {
37+
builder.get().Rules = append(builder.get().Rules, rules...)
38+
return builder
39+
}

0 commit comments

Comments
 (0)