@@ -55,6 +55,7 @@ const (
55
55
// managed by this controller
56
56
AccessRequestFinalizerName = "accessrequest.ephemeral-access.argoproj-labs.io/finalizer"
57
57
roleTemplateField = ".spec.roleTemplateName"
58
+ projectField = ".status.targetProject"
58
59
)
59
60
60
61
// +kubebuilder:rbac:groups=ephemeral-access.argoproj-labs.io,resources=accessrequests,verbs=get;list;watch;create;update;patch;delete
@@ -281,13 +282,18 @@ func (r *AccessRequestReconciler) handleFinalizer(ctx context.Context, ar *api.A
281
282
// controller. Only non-concluded AccessRequests will be added to the reconciliation
282
283
// list. An AccessRequest is defined as concluded if their status is Expired or Denied.
283
284
func (r * AccessRequestReconciler ) findObjectsForRoleTemplate (ctx context.Context , roleTemplate client.Object ) []reconcile.Request {
285
+ logger := log .FromContext (ctx )
286
+ logger .Debug (fmt .Sprintf ("RoleTemplate %s updated: searching for associated AccessRequests..." , roleTemplate .GetName ()))
284
287
attachedAccessRequests := & api.AccessRequestList {}
285
288
listOps := & client.ListOptions {
286
289
FieldSelector : fields .OneTermEqualSelector (roleTemplateField , roleTemplate .GetName ()),
287
- Namespace : roleTemplate .GetNamespace (),
290
+ // This makes a requirement that the AccessRequest has to live in the
291
+ // same namespace as the AppProject.
292
+ Namespace : roleTemplate .GetNamespace (),
288
293
}
289
294
err := r .List (ctx , attachedAccessRequests , listOps )
290
295
if err != nil {
296
+ logger .Error (err , "findObjectsForRoleTemplate error: list k8s resources error" )
291
297
return []reconcile.Request {}
292
298
}
293
299
@@ -302,16 +308,74 @@ func (r *AccessRequestReconciler) findObjectsForRoleTemplate(ctx context.Context
302
308
}
303
309
}
304
310
}
305
- if len (requests ) == 0 {
311
+ totalRequests := len (requests )
312
+ if totalRequests == 0 {
306
313
return nil
307
314
}
315
+ logger .Debug (fmt .Sprintf ("Found %d associated AccessRequests with RoleTemplate %s. Reconciling..." , totalRequests , roleTemplate .GetName ()))
308
316
return requests
309
317
}
310
318
311
- // SetupWithManager sets up the controller with the Manager.
312
- func (r * AccessRequestReconciler ) SetupWithManager (mgr ctrl.Manager ) error {
313
- // create an AccessRequest index by role template name to allow
314
- // fetching all objects referencing a given RoleTemplate
319
+ // findObjectsForProject will retrieve all AccessRequest resources referencing
320
+ // the given project and build a list of reconcile requests to be sent to the
321
+ // controller. Only non-concluded AccessRequests will be added to the reconciliation
322
+ // list. An AccessRequest is defined as concluded if their status is Expired or Denied.
323
+ func (r * AccessRequestReconciler ) findObjectsForProject (ctx context.Context , project client.Object ) []reconcile.Request {
324
+ logger := log .FromContext (ctx )
325
+ logger .Debug (fmt .Sprintf ("Project %s updated: searching for associated AccessRequests..." , project .GetName ()))
326
+ associatedAccessRequests := & api.AccessRequestList {}
327
+ listOps := & client.ListOptions {
328
+ FieldSelector : fields .OneTermEqualSelector (projectField , project .GetName ()),
329
+ // This makes a requirement that the AccessRequest has to live in the
330
+ // same namespace as the AppProject.
331
+ Namespace : project .GetNamespace (),
332
+ }
333
+ err := r .List (ctx , associatedAccessRequests , listOps )
334
+ if err != nil {
335
+ logger .Error (err , "findObjectsForProject error: list k8s resources error" )
336
+ return []reconcile.Request {}
337
+ }
338
+
339
+ requests := make ([]reconcile.Request , len (associatedAccessRequests .Items ))
340
+ for i , item := range associatedAccessRequests .Items {
341
+ if ! isConcluded (& item ) {
342
+ requests [i ] = reconcile.Request {
343
+ NamespacedName : types.NamespacedName {
344
+ Name : item .GetName (),
345
+ Namespace : item .GetNamespace (),
346
+ },
347
+ }
348
+ }
349
+ }
350
+ totalRequests := len (requests )
351
+ if totalRequests == 0 {
352
+ return nil
353
+ }
354
+ logger .Debug (fmt .Sprintf ("Found %d associated AccessRequests with project %s. Reconciling..." , totalRequests , project .GetName ()))
355
+ return requests
356
+ }
357
+
358
+ // createProjectIndex will create an AccessRequest index by project to allow
359
+ // fetching all objects referencing a given AppProject.
360
+ func createProjectIndex (mgr ctrl.Manager ) error {
361
+ err := mgr .GetFieldIndexer ().
362
+ IndexField (context .Background (), & api.AccessRequest {}, projectField ,
363
+ func (rawObj client.Object ) []string {
364
+ ar := rawObj .(* api.AccessRequest )
365
+ if ar .Status .TargetProject == "" {
366
+ return nil
367
+ }
368
+ return []string {ar .Status .TargetProject }
369
+ })
370
+ if err != nil {
371
+ return fmt .Errorf ("error creating project field index: %w" , err )
372
+ }
373
+ return nil
374
+ }
375
+
376
+ // createRoleTemplateIndex create an AccessRequest index by role template name
377
+ // to allow fetching all objects referencing a given RoleTemplate.
378
+ func createRoleTemplateIndex (mgr ctrl.Manager ) error {
315
379
err := mgr .GetFieldIndexer ().
316
380
IndexField (context .Background (), & api.AccessRequest {}, roleTemplateField , func (rawObj client.Object ) []string {
317
381
ar := rawObj .(* api.AccessRequest )
@@ -321,12 +385,28 @@ func (r *AccessRequestReconciler) SetupWithManager(mgr ctrl.Manager) error {
321
385
return []string {ar .Spec .RoleTemplateName }
322
386
})
323
387
if err != nil {
324
- return fmt .Errorf ("error creating index field for roleTemplateName: %w" , err )
388
+ return fmt .Errorf ("error creating roleTemplateName field index: %w" , err )
389
+ }
390
+ return nil
391
+ }
392
+
393
+ // SetupWithManager sets up the controller with the Manager.
394
+ func (r * AccessRequestReconciler ) SetupWithManager (mgr ctrl.Manager ) error {
395
+ err := createProjectIndex (mgr )
396
+ if err != nil {
397
+ return fmt .Errorf ("create index error: %w" , err )
398
+ }
399
+ err = createRoleTemplateIndex (mgr )
400
+ if err != nil {
401
+ return fmt .Errorf ("create index error: %w" , err )
325
402
}
326
403
return ctrl .NewControllerManagedBy (mgr ).
327
404
For (& api.AccessRequest {}).
328
405
Watches (& api.RoleTemplate {},
329
406
handler .EnqueueRequestsFromMapFunc (r .findObjectsForRoleTemplate ),
330
407
builder .WithPredicates (predicate.ResourceVersionChangedPredicate {})).
408
+ Watches (& argocd.AppProject {},
409
+ handler .EnqueueRequestsFromMapFunc (r .findObjectsForProject ),
410
+ builder .WithPredicates (predicate.ResourceVersionChangedPredicate {})).
331
411
Complete (r )
332
412
}
0 commit comments