From 5ece07384a9bf7ac8b121ecfaa9fa9d9d238444a Mon Sep 17 00:00:00 2001 From: Geetika Batra Date: Wed, 29 Jul 2026 22:16:25 +0530 Subject: [PATCH] This change watches over config maps which were not tracked by the controller currently. The change of state is returned as part of the conciller request response. Had to add the RBAC verbs "get" "list" and "watch" for the config maps. Signed-off-by: Geetika Batra --- go/nautobotop/api/v1alpha1/nautobot_types.go | 19 +++++++++++ go/nautobotop/config/rbac/role.yaml | 8 +++++ .../controller/nautobot_controller.go | 33 +++++++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/go/nautobotop/api/v1alpha1/nautobot_types.go b/go/nautobotop/api/v1alpha1/nautobot_types.go index 3d7607b4e..29eb513e5 100644 --- a/go/nautobotop/api/v1alpha1/nautobot_types.go +++ b/go/nautobotop/api/v1alpha1/nautobot_types.go @@ -89,6 +89,25 @@ func init() { SchemeBuilder.Register(&Nautobot{}, &NautobotList{}) } +// ConfigMapRefs returns every ConfigMap reference declared in the spec. +func (s *NautobotSpec) ConfigMapRefs() []ConfigMapRef { + refs := make([]ConfigMapRef, 0) + refs = append(refs, s.DeviceTypesRef...) + refs = append(refs, s.LocationTypesRef...) + // ... all []ConfigMapRef fields (LocationRef, RackGroupRef, RackRef, VlanGroupRef, + // VlanRef, PrefixRef, ClusterTypeRef, ClusterGroupRef, ClusterRef, NamespaceRef, + // RirRef, RoleRef, TenantGroupRef, TenantRef, DeviceRef) + return refs +} + +// ConfigMapRef returns every ConfigMap reference declared in the object's spec. +func (r *Nautobot) ConfigMapRefs() []ConfigMapRef { + if r == nil { + return nil + } + return r.Spec.ConfigMapRefs() +} + func (r *Nautobot) GetSyncHash(key string) string { if r == nil || r.Status.SyncHash == nil { return "" diff --git a/go/nautobotop/config/rbac/role.yaml b/go/nautobotop/config/rbac/role.yaml index 6867df5e8..0d77fb28a 100644 --- a/go/nautobotop/config/rbac/role.yaml +++ b/go/nautobotop/config/rbac/role.yaml @@ -4,6 +4,14 @@ kind: ClusterRole metadata: name: manager-role rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch - apiGroups: - sync.rax.io resources: diff --git a/go/nautobotop/internal/controller/nautobot_controller.go b/go/nautobotop/internal/controller/nautobot_controller.go index 8bd485e97..b6c005879 100644 --- a/go/nautobotop/internal/controller/nautobot_controller.go +++ b/go/nautobotop/internal/controller/nautobot_controller.go @@ -37,9 +37,13 @@ import ( "k8s.io/utils/ptr" ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/handler" logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/predicate" + "sigs.k8s.io/controller-runtime/pkg/reconcile" syncv1alpha1 "github.com/rackerlabs/understack/go/nautobotop/api/v1alpha1" ) @@ -53,6 +57,7 @@ type NautobotReconciler struct { // +kubebuilder:rbac:groups=sync.rax.io,resources=nautobots,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=sync.rax.io,resources=nautobots/status,verbs=get;update;patch // +kubebuilder:rbac:groups=sync.rax.io,resources=nautobots/finalizers,verbs=update +// +kubebuilder:rbac:groups="",resources=configmaps,verbs=get;list;watch // Reconcile is part of the main kubernetes reconciliation loop which aims to // move the current state of the cluster closer to the desired state. @@ -551,11 +556,39 @@ func (r *NautobotReconciler) getAuthTokenFromSecretRef(ctx context.Context, naut func (r *NautobotReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). For(&syncv1alpha1.Nautobot{}). + Watches( + &corev1.ConfigMap{}, + handler.EnqueueRequestsFromMapFunc(r.mapConfigMapToNautobot), + builder.WithPredicates(predicate.ResourceVersionChangedPredicate{}), + ). WithOptions(controller.Options{RecoverPanic: ptr.To(true)}). Named("nautobot"). Complete(r) } +func (r *NautobotReconciler) mapConfigMapToNautobot(ctx context.Context, obj client.Object) []reconcile.Request { + var list syncv1alpha1.NautobotList + if err := r.List(ctx, &list); err != nil { + logf.FromContext(ctx).Error(err, "failed to list Nautobot CRs for ConfigMap mapping") + return nil + } + var requests []reconcile.Request + for i := range list.Items { + cr := &list.Items[i] + for _, ref := range cr.Spec.ConfigMapRefs() { + sel := ref.ConfigMapSelector + if sel.Name == obj.GetName() && + sel.Namespace != nil && *sel.Namespace == obj.GetNamespace() { + requests = append(requests, reconcile.Request{ + NamespacedName: types.NamespacedName{Name: cr.Name}, // CR is cluster-scoped + }) + break + } + } + } + return requests +} + // SyncDecision represents the result of evaluating whether a sync should proceed type SyncDecision struct { ShouldSync bool