@@ -44,6 +44,10 @@ import (
4444 apierrors "k8s.io/apimachinery/pkg/api/errors"
4545)
4646
47+ const (
48+ deployFunctionRoleName = "func-operator-deploy-function"
49+ )
50+
4751// FunctionReconciler reconciles a Function object
4852type FunctionReconciler struct {
4953 client.Client
@@ -58,11 +62,11 @@ type FunctionReconciler struct {
5862// +kubebuilder:rbac:groups=functions.dev,resources=functions/finalizers,verbs=update
5963// +kubebuilder:rbac:groups="",resources=secrets;services;persistentvolumeclaims,verbs=get;list;watch;create;update;patch;delete
6064// +kubebuilder:rbac:groups="apps",resources=deployments,verbs=get;list;watch;create;update;patch;delete
61- // +kubebuilder:rbac:groups="serving.knative.dev",resources=services,verbs=get;list;watch;create;update;patch;delete
65+ // +kubebuilder:rbac:groups="serving.knative.dev",resources=services;routes ,verbs=get;list;watch;create;update;patch;delete
6266// +kubebuilder:rbac:groups="eventing.knative.dev",resources=triggers,verbs=get;list;watch;create;update;patch;delete
6367// +kubebuilder:rbac:groups=tekton.dev,resources=pipelines;pipelineruns,verbs=get;list;watch;create;update;patch;delete
6468// +kubebuilder:rbac:groups=tekton.dev,resources=taskruns,verbs=get;list;watch
65- // +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=rolebindings,verbs=get;list;watch;create;update;patch;delete
69+ // +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=rolebindings;roles ,verbs=get;list;watch;create;update;patch;delete
6670// +kubebuilder:rbac:groups=http.keda.sh,resources=httpscaledobjects,verbs=get;list;watch;create;update;patch;delete
6771
6872// Reconcile a Function with status update
@@ -213,9 +217,67 @@ func (r *FunctionReconciler) updateFunctionStatus(function *v1alpha1.Function, m
213217}
214218
215219func (r * FunctionReconciler ) setupPipelineRBAC (ctx context.Context , function * v1alpha1.Function ) error {
220+ if err := r .ensureDeployFunctionRole (ctx , function .Namespace ); err != nil {
221+ return fmt .Errorf ("failed to ensure deploy-function role: %w" , err )
222+ }
223+
224+ if err := r .ensureDeployFunctionRoleBinding (ctx , function ); err != nil {
225+ return fmt .Errorf ("failed to ensure deploy-function role binding: %w" , err )
226+ }
227+
228+ return nil
229+ }
230+
231+ // ensureDeployFunctionRole ensures the deploy-function Role exists in the namespace and is up-to-date.
232+ // This is a namespace-scoped Role so multiple operator instances won't conflict.
233+ func (r * FunctionReconciler ) ensureDeployFunctionRole (ctx context.Context , namespace string ) error {
234+ logger := log .FromContext (ctx )
235+
236+ expectedRole := & rbacv1.Role {
237+ ObjectMeta : metav1.ObjectMeta {
238+ Name : deployFunctionRoleName ,
239+ Namespace : namespace ,
240+ },
241+ Rules : []rbacv1.PolicyRule {
242+ {
243+ APIGroups : []string {"serving.knative.dev" },
244+ Resources : []string {"services" , "routes" },
245+ Verbs : []string {"create" , "delete" , "get" , "list" , "patch" , "update" , "watch" },
246+ },
247+ },
248+ }
249+
250+ foundRole := & rbacv1.Role {}
251+ err := r .Get (ctx , types.NamespacedName {Name : expectedRole .Name , Namespace : expectedRole .Namespace }, foundRole )
252+ if err != nil {
253+ if apierrors .IsNotFound (err ) {
254+ if err := r .Create (ctx , expectedRole ); err != nil {
255+ return fmt .Errorf ("failed to create role: %w" , err )
256+ }
257+ logger .Info ("Created deploy-function role" )
258+ return nil
259+ }
260+ return fmt .Errorf ("failed to get role: %w" , err )
261+ }
262+
263+ // Role exists - update if needed
264+ if ! equality .Semantic .DeepEqual (expectedRole .Rules , foundRole .Rules ) {
265+ foundRole .Rules = expectedRole .Rules
266+ if err := r .Update (ctx , foundRole ); err != nil {
267+ return fmt .Errorf ("failed to update role: %w" , err )
268+ }
269+ logger .Info ("Updated deploy-function role" )
270+ } else {
271+ logger .Info ("Deploy-function role already up to date" )
272+ }
273+
274+ return nil
275+ }
276+
277+ // ensureDeployFunctionRoleBinding ensures the RoleBinding for the deploy-function role exists and is up-to-date.
278+ func (r * FunctionReconciler ) ensureDeployFunctionRoleBinding (ctx context.Context , function * v1alpha1.Function ) error {
216279 logger := log .FromContext (ctx )
217280
218- logger .Info ("Create rolebinding for deploy-function role" )
219281 expectedRoleBinding := & rbacv1.RoleBinding {
220282 ObjectMeta : metav1.ObjectMeta {
221283 Name : "deploy-function-default" ,
@@ -236,40 +298,39 @@ func (r *FunctionReconciler) setupPipelineRBAC(ctx context.Context, function *v1
236298 Namespace : function .Namespace ,
237299 }},
238300 RoleRef : rbacv1.RoleRef {
239- Kind : "ClusterRole" ,
240- Name : "func-operator-deploy-function" ,
241301 APIGroup : "rbac.authorization.k8s.io" ,
302+ Kind : "Role" ,
303+ Name : deployFunctionRoleName ,
242304 },
243305 }
306+
244307 foundRoleBinding := & rbacv1.RoleBinding {}
245308 err := r .Get (ctx , types.NamespacedName {Name : expectedRoleBinding .Name , Namespace : expectedRoleBinding .Namespace }, foundRoleBinding )
246309 if err != nil {
247310 if apierrors .IsNotFound (err ) {
248311 if err := r .Create (ctx , expectedRoleBinding ); err != nil {
249- return fmt .Errorf ("failed to create role binding for deploy-function role : %w" , err )
312+ return fmt .Errorf ("failed to create role binding: %w" , err )
250313 }
251- logger .Info ("Created role binding for deploy-function role" )
314+ logger .Info ("Created deploy-function role binding " )
252315 return nil
253316 }
254- return fmt .Errorf ("failed to check if deploy-function role binding already exists : %w" , err )
317+ return fmt .Errorf ("failed to get role binding: %w" , err )
255318 }
256319
257320 // Update if needed
258321 if ! equality .Semantic .DeepDerivative (expectedRoleBinding , foundRoleBinding ) {
259- // Copy expected values into found object
260322 foundRoleBinding .Subjects = expectedRoleBinding .Subjects
261323 foundRoleBinding .RoleRef = expectedRoleBinding .RoleRef
262324 foundRoleBinding .OwnerReferences = expectedRoleBinding .OwnerReferences
263325
264326 if err := r .Update (ctx , foundRoleBinding ); err != nil {
265- return fmt .Errorf ("failed to update deploy-function role binding: %w" , err )
327+ return fmt .Errorf ("failed to update role binding: %w" , err )
266328 }
267-
268329 logger .Info ("Updated deploy-function role binding" )
269- return nil
330+ } else {
331+ logger .Info ("Deploy-function role binding already up to date" )
270332 }
271333
272- logger .Info ("Role binding already exists and is up to date. No need to update" )
273334 return nil
274335}
275336
0 commit comments