@@ -3,11 +3,9 @@ package trustmanager
33import (
44 "context"
55 "fmt"
6+ "reflect"
67
7- admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
8- appsv1 "k8s.io/api/apps/v1"
98 corev1 "k8s.io/api/core/v1"
10- rbacv1 "k8s.io/api/rbac/v1"
119 "k8s.io/apimachinery/pkg/api/errors"
1210 "k8s.io/apimachinery/pkg/runtime"
1311 "k8s.io/apimachinery/pkg/types"
@@ -16,15 +14,12 @@ import (
1614 ctrl "sigs.k8s.io/controller-runtime"
1715 "sigs.k8s.io/controller-runtime/pkg/builder"
1816 "sigs.k8s.io/controller-runtime/pkg/client"
19- "sigs.k8s.io/controller-runtime/pkg/event"
2017 "sigs.k8s.io/controller-runtime/pkg/handler"
2118 "sigs.k8s.io/controller-runtime/pkg/predicate"
2219 "sigs.k8s.io/controller-runtime/pkg/reconcile"
2320
2421 "github.com/go-logr/logr"
2522
26- certmanagerv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
27-
2823 v1alpha1 "github.com/openshift/cert-manager-operator/api/operator/v1alpha1"
2924 "github.com/openshift/cert-manager-operator/pkg/controller/common"
3025)
@@ -44,21 +39,12 @@ type Reconciler struct {
4439 scheme * runtime.Scheme
4540}
4641
42+ // TODO: Add more RBAC rules as resources are implemented
4743// +kubebuilder:rbac:groups=operator.openshift.io,resources=trustmanagers,verbs=get;list;watch;update;patch
4844// +kubebuilder:rbac:groups=operator.openshift.io,resources=trustmanagers/status,verbs=get;update;patch
4945// +kubebuilder:rbac:groups=operator.openshift.io,resources=trustmanagers/finalizers,verbs=update
5046// +kubebuilder:rbac:groups="",resources=namespaces,verbs=get;list;watch
51- // +kubebuilder:rbac:groups="",resources=configmaps,verbs=get;list;watch;create;update;patch
5247// +kubebuilder:rbac:groups="",resources=serviceaccounts,verbs=get;list;watch;create;update;patch
53- // +kubebuilder:rbac:groups="",resources=services,verbs=get;list;watch;create;update;patch
54- // +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch
55- // +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=clusterroles;clusterrolebindings,verbs=get;list;watch;create;update;patch
56- // +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=roles;rolebindings,verbs=get;list;watch;create;update;patch
57- // +kubebuilder:rbac:groups=cert-manager.io,resources=certificates;issuers,verbs=get;list;watch;create;update;patch
58- // +kubebuilder:rbac:groups=admissionregistration.k8s.io,resources=validatingwebhookconfigurations,verbs=get;list;watch;create;update;patch
59- // +kubebuilder:rbac:groups=trust.cert-manager.io,resources=bundles,verbs=get;list;watch
60- // +kubebuilder:rbac:groups=trust.cert-manager.io,resources=bundles/finalizers,verbs=update
61- // +kubebuilder:rbac:groups=trust.cert-manager.io,resources=bundles/status,verbs=patch
6248
6349// New returns a new Reconciler instance.
6450func New (mgr ctrl.Manager ) (* Reconciler , error ) {
@@ -77,74 +63,42 @@ func New(mgr ctrl.Manager) (*Reconciler, error) {
7763
7864// SetupWithManager sets up the controller with the Manager.
7965func (r * Reconciler ) SetupWithManager (mgr ctrl.Manager ) error {
80- // mapFunc unconditionally enqueues the singleton TrustManager CR.
81- // Filtering is handled by predicates attached to each Watch.
82- mapFunc := func (ctx context.Context , obj client.Object ) []reconcile.Request {
66+ mapFunc := func (_ context.Context , obj client.Object ) []reconcile.Request {
8367 r .log .V (4 ).Info ("received reconcile event" , "object" , fmt .Sprintf ("%T" , obj ), "name" , obj .GetName (), "namespace" , obj .GetNamespace ())
84- return []reconcile.Request {{NamespacedName : types.NamespacedName {Name : trustManagerObjectName }}}
68+
69+ objLabels := obj .GetLabels ()
70+ if objLabels != nil {
71+ if objLabels [common .ManagedResourceLabelKey ] == RequestEnqueueLabelValue {
72+ return []reconcile.Request {
73+ {
74+ NamespacedName : types.NamespacedName {
75+ Name : trustManagerObjectName ,
76+ },
77+ },
78+ }
79+ }
80+ }
81+
82+ r .log .V (4 ).Info ("object not of interest, ignoring reconcile event" , "object" , fmt .Sprintf ("%T" , obj ), "name" , obj .GetName (), "namespace" , obj .GetNamespace ())
83+ return []reconcile.Request {}
8584 }
8685
87- isManagedResource := func (object client.Object ) bool {
86+ // predicate function to ignore events for objects not managed by controller.
87+ controllerManagedResources := predicate .NewPredicateFuncs (func (object client.Object ) bool {
8888 labels := object .GetLabels ()
8989 matches := labels != nil && labels [common .ManagedResourceLabelKey ] == RequestEnqueueLabelValue
9090 r .log .V (4 ).Info ("predicate evaluation" , "object" , fmt .Sprintf ("%T" , object ), "name" , object .GetName (), "namespace" , object .GetNamespace (), "labels" , labels , "matches" , matches )
9191 return matches
92- }
93-
94- // Predicate to filter events for resources managed by this controller.
95- // On updates, checks both old and new objects so that events where the
96- // managed label is removed still trigger reconciliation.
97- controllerManagedResources := predicate.Funcs {
98- CreateFunc : func (e event.CreateEvent ) bool {
99- return isManagedResource (e .Object )
100- },
101- UpdateFunc : func (e event.UpdateEvent ) bool {
102- return isManagedResource (e .ObjectOld ) || isManagedResource (e .ObjectNew )
103- },
104- DeleteFunc : func (e event.DeleteEvent ) bool {
105- return isManagedResource (e .Object )
106- },
107- GenericFunc : func (e event.GenericEvent ) bool {
108- return isManagedResource (e .Object )
109- },
110- }
92+ })
11193
11294 controllerManagedResourcePredicates := builder .WithPredicates (controllerManagedResources )
11395
114- // withIgnoreStatusUpdatePredicates filters out status-only updates while still
115- // detecting spec changes (generation bump) and metadata drift (label/annotation edits).
116- withIgnoreStatusUpdatePredicates := builder .WithPredicates (
117- predicate .Or (
118- predicate.GenerationChangedPredicate {},
119- predicate.LabelChangedPredicate {},
120- predicate.AnnotationChangedPredicate {},
121- ),
122- controllerManagedResources ,
123- )
124-
125- // Predicate that matches the CNO-injected CA bundle ConfigMap in the operator namespace.
126- // This ConfigMap is NOT managed by trust-manager-controller (no managed label) but we need to detect
127- // when CNO updates the trusted CA bundle so we can reformat and propagate it.
128- injectedCABundleConfigMapPredicate := predicate .NewPredicateFuncs (func (object client.Object ) bool {
129- return object .GetNamespace () == common .OperatorNamespace &&
130- object .GetName () == common .TrustedCABundleConfigMapName
131- })
132-
96+ // TODO: Add more watches as resources are implemented
13397 return ctrl .NewControllerManagedBy (mgr ).
98+ // GenerationChangedPredicate ignores status-only updates
13499 For (& v1alpha1.TrustManager {}, builder .WithPredicates (predicate.GenerationChangedPredicate {})).
135100 Named (ControllerName ).
136101 Watches (& corev1.ServiceAccount {}, handler .EnqueueRequestsFromMapFunc (mapFunc ), controllerManagedResourcePredicates ).
137- Watches (& appsv1.Deployment {}, handler .EnqueueRequestsFromMapFunc (mapFunc ), withIgnoreStatusUpdatePredicates ).
138- Watches (& corev1.Service {}, handler .EnqueueRequestsFromMapFunc (mapFunc ), controllerManagedResourcePredicates ).
139- Watches (& corev1.ConfigMap {}, handler .EnqueueRequestsFromMapFunc (mapFunc ), controllerManagedResourcePredicates ).
140- Watches (& corev1.ConfigMap {}, handler .EnqueueRequestsFromMapFunc (mapFunc ), builder .WithPredicates (injectedCABundleConfigMapPredicate )).
141- Watches (& rbacv1.ClusterRole {}, handler .EnqueueRequestsFromMapFunc (mapFunc ), controllerManagedResourcePredicates ).
142- Watches (& rbacv1.ClusterRoleBinding {}, handler .EnqueueRequestsFromMapFunc (mapFunc ), controllerManagedResourcePredicates ).
143- Watches (& rbacv1.Role {}, handler .EnqueueRequestsFromMapFunc (mapFunc ), controllerManagedResourcePredicates ).
144- Watches (& rbacv1.RoleBinding {}, handler .EnqueueRequestsFromMapFunc (mapFunc ), controllerManagedResourcePredicates ).
145- Watches (& certmanagerv1.Certificate {}, handler .EnqueueRequestsFromMapFunc (mapFunc ), withIgnoreStatusUpdatePredicates ).
146- Watches (& certmanagerv1.Issuer {}, handler .EnqueueRequestsFromMapFunc (mapFunc ), withIgnoreStatusUpdatePredicates ).
147- Watches (& admissionregistrationv1.ValidatingWebhookConfiguration {}, handler .EnqueueRequestsFromMapFunc (mapFunc ), controllerManagedResourcePredicates ).
148102 Complete (r )
149103}
150104
@@ -191,7 +145,13 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
191145}
192146
193147func (r * Reconciler ) processReconcileRequest (trustManager * v1alpha1.TrustManager , req types.NamespacedName ) (ctrl.Result , error ) {
194- reconcileErr := r .reconcileTrustManagerDeployment (trustManager )
148+ trustManagerCreateRecon := false
149+ if ! containsProcessedAnnotation (trustManager ) && reflect .DeepEqual (trustManager .Status , v1alpha1.TrustManagerStatus {}) {
150+ r .log .V (1 ).Info ("starting reconciliation of newly created trustmanager" , "name" , trustManager .GetName ())
151+ trustManagerCreateRecon = true
152+ }
153+
154+ reconcileErr := r .reconcileTrustManagerDeployment (trustManager , trustManagerCreateRecon )
195155 if reconcileErr != nil {
196156 r .log .Error (reconcileErr , "failed to reconcile TrustManager deployment" , "request" , req )
197157 }
0 commit comments