@@ -61,70 +61,86 @@ type NautobotReconciler struct {
6161//
6262// For more details, check Reconcile and its Result here:
6363// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.20.4/pkg/reconcile
64+ // resourceConfig defines configuration for a single resource type
65+ type resourceConfig struct {
66+ name string
67+ configRefs []syncv1alpha1.ConfigMapRef
68+ syncFunc func (context.Context , * nbClient.NautobotClient , map [string ]string ) error
69+ }
70+
6471func (r * NautobotReconciler ) Reconcile (ctx context.Context , req ctrl.Request ) (ctrl.Result , error ) {
6572 log := logf .FromContext (ctx )
6673 var nautobotCR syncv1alpha1.Nautobot
6774 if err := r .Get (ctx , req .NamespacedName , & nautobotCR ); err != nil {
6875 return ctrl.Result {}, client .IgnoreNotFound (err )
6976 }
7077
71- // Aggregate device type data from all referenced ConfigMaps
72- locationTypeMap , err := r .aggregateDeviceTypeDataFromConfigMap (ctx , nautobotCR .Spec .LocationTypesRef )
73- if err != nil {
74- log .Error (err , "failed to aggregate device type data from ConfigMaps" )
75- return ctrl.Result {}, err
78+ syncInterval := time .Duration (nautobotCR .Spec .SyncIntervalSeconds ) * time .Second
79+ requeueAfter := time .Duration (nautobotCR .Spec .RequeueAfter ) * time .Second
80+
81+ // Define all resources to sync
82+ // Add more resources here: {name: "location", configRefs: nautobotCR.Spec.LocationsRef, syncFunc: r.syncLocations}
83+ resources := []resourceConfig {
84+ {name : "locationType" , configRefs : nautobotCR .Spec .LocationTypesRef , syncFunc : r .syncLocationTypes },
85+ {name : "location" , configRefs : nautobotCR .Spec .LocationRef , syncFunc : r .syncLocation },
86+ {name : "deviceType" , configRefs : nautobotCR .Spec .DeviceTypesRef , syncFunc : r .syncDeviceTypes },
7687 }
7788
78- // Aggregate device type data from all referenced ConfigMaps
79- deviceTypeMap , err := r .aggregateDeviceTypeDataFromConfigMap (ctx , nautobotCR .Spec .DeviceTypesRef )
80- if err != nil {
81- log .Error (err , "failed to aggregate device type data from ConfigMaps" )
82- return ctrl.Result {}, err
89+ // Aggregate data and check sync decisions for all resources
90+ resourcesToSync := make (map [string ]map [string ]string )
91+ for _ , res := range resources {
92+ dataMap , err := r .aggregateDataFromConfigMap (ctx , res .configRefs )
93+ if err != nil {
94+ log .Error (err , "failed to aggregate data" , "resource" , res .name )
95+ return ctrl.Result {}, err
96+ }
97+
98+ currentHash := computeHash (dataMap )
99+ previousHash := nautobotCR .GetSyncHash (res .name )
100+ decision := r .shouldSync (nautobotCR .Status .LastSyncedAt , syncInterval , currentHash , previousHash )
101+
102+ if decision .ShouldSync {
103+ log .Info ("resource needs sync" , "resource" , res .name , "reason" , decision .Reason )
104+ resourcesToSync [res .name ] = dataMap
105+ } else {
106+ log .Info ("skipping resource sync" , "resource" , res .name , "reason" , decision .Reason )
107+ }
83108 }
84109
85- // Check if sync should proceed based on time interval and data changes
86- syncInterval := time .Duration (nautobotCR .Spec .SyncIntervalSeconds ) * time .Second
87- requestTimeAfter := time .Duration (nautobotCR .Spec .RequeueAfter ) * time .Second
88- currentHash := computeHash (deviceTypeMap )
89- previousHash := nautobotCR .GetSyncHash ("deviceType" )
90-
91- syncDecision := r .shouldSync (nautobotCR .Status .LastSyncedAt , syncInterval , currentHash , previousHash )
92- if ! syncDecision .ShouldSync {
93- log .Info ("skipping sync" , "reason" , syncDecision .Reason , "hash" , currentHash )
94- nautobotCR .Status .Message = syncDecision .StatusMessage
110+ // If nothing to sync, update status and requeue
111+ if len (resourcesToSync ) == 0 {
112+ nautobotCR .Status .Message = "No changes detected"
95113 if err := r .Status ().Update (ctx , & nautobotCR ); err != nil {
96114 log .Error (err , "failed to update status" )
97115 return ctrl.Result {}, err
98116 }
99- return ctrl.Result {RequeueAfter : requestTimeAfter }, nil
117+ return ctrl.Result {RequeueAfter : requeueAfter }, nil
100118 }
101119
102- log .Info ("proceeding with sync" , "reason" , syncDecision .Reason , "hash" , currentHash )
103-
104- // Retrieve the Nautobot authentication token from a secret or external source
120+ // Create Nautobot client
105121 username , token , err := r .getAuthTokenFromSecretRef (ctx , nautobotCR )
106122 if err != nil {
107- log .Error (err , "failed parse find nautobot auth token" )
123+ log .Error (err , "failed to get nautobot auth token" )
108124 return ctrl.Result {}, err
109125 }
110-
111- // Create Nautobot client
112126 nautobotURL := fmt .Sprintf ("http://%s.%s.svc.cluster.local/api" , nautobotCR .Spec .NautobotServiceRef .Name , nautobotCR .Spec .NautobotServiceRef .Namespace )
113127 nautobotClient := nbClient .NewNautobotClient (nautobotURL , username , token )
114128
115- if err := r .syncLocationTypes (ctx , nautobotClient , locationTypeMap ); err != nil {
116- log .Error (err , "failed to sync device types" )
117- return ctrl.Result {}, err
118- }
119- if err := r .syncDeviceTypes (ctx , nautobotClient , deviceTypeMap ); err != nil {
120- log .Error (err , "failed to sync device types" )
121- return ctrl.Result {}, err
129+ // Sync resources that need updating
130+ for _ , res := range resources {
131+ if dataMap , ok := resourcesToSync [res .name ]; ok {
132+ if err := res .syncFunc (ctx , nautobotClient , dataMap ); err != nil {
133+ log .Error (err , "failed to sync resource" , "resource" , res .name )
134+ return ctrl.Result {}, err
135+ }
136+ nautobotCR .SetSyncHash (res .name , computeHash (dataMap ))
137+ }
122138 }
123139
140+ // Update status
124141 nautobotCR .Status .LastSyncedAt = metav1 .Now ()
125142 nautobotCR .Status .Ready = true
126143 nautobotCR .Status .NautobotStatusReport = nautobotClient .Report
127- nautobotCR .SetSyncHash ("deviceType" , currentHash )
128144 if len (nautobotClient .Report ) > 0 {
129145 nautobotCR .Status .Message = "sync completed with some errors"
130146 } else {
@@ -134,15 +150,14 @@ func (r *NautobotReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
134150 log .Error (err , "failed to update status" )
135151 return ctrl.Result {}, err
136152 }
137- // Successfully completed reconciliation; requeue after configured sync interval
153+
138154 log .Info ("sync completed successfully" )
139- return ctrl.Result {RequeueAfter : requestTimeAfter }, nil
155+ return ctrl.Result {RequeueAfter : requeueAfter }, nil
140156}
141157
142- // aggregateDeviceTypeDataFromConfigMap fetches and merges data from all referenced ConfigMaps.
143- // It returns a map containing all device type configurations.
144- func (r * NautobotReconciler ) aggregateDeviceTypeDataFromConfigMap (ctx context.Context , refs []syncv1alpha1.ConfigMapRef ) (map [string ]string , error ) {
145- deviceTypeMap := make (map [string ]string )
158+ // aggregateDataFromConfigMap fetches and merges data from all referenced ConfigMaps.
159+ func (r * NautobotReconciler ) aggregateDataFromConfigMap (ctx context.Context , refs []syncv1alpha1.ConfigMapRef ) (map [string ]string , error ) {
160+ dataMap := make (map [string ]string )
146161
147162 for _ , ref := range refs {
148163 var configMap corev1.ConfigMap
@@ -156,27 +171,36 @@ func (r *NautobotReconciler) aggregateDeviceTypeDataFromConfigMap(ctx context.Co
156171 namespacedName .Namespace , namespacedName .Name , err )
157172 }
158173
159- // Merge ConfigMap data into the aggregate map
160- maps .Copy (deviceTypeMap , configMap .Data )
174+ maps .Copy (dataMap , configMap .Data )
161175 }
162176
163- return deviceTypeMap , nil
177+ return dataMap , nil
164178}
165179
166180// syncDeviceTypes syncs device types to Nautobot.
167- // The hash comparison is now handled in the Reconcile function.
168181func (r * NautobotReconciler ) syncDeviceTypes (ctx context.Context ,
169182 nautobotClient * nbClient.NautobotClient ,
170183 deviceTypeMap map [string ]string ,
171184) error {
172185 log := logf .FromContext (ctx )
173-
174- log .Info ("syncing device types" , "deviceTypeCount" , len (deviceTypeMap ))
186+ log .Info ("syncing device types" , "count" , len (deviceTypeMap ))
175187 syncSvc := sync .NewDeviceTypeSync (nautobotClient )
176188 if err := syncSvc .SyncAll (ctx , deviceTypeMap ); err != nil {
177189 return fmt .Errorf ("failed to sync device types: %w" , err )
178190 }
191+ return nil
192+ }
179193
194+ func (r * NautobotReconciler ) syncLocation (ctx context.Context ,
195+ nautobotClient * nbClient.NautobotClient ,
196+ locationType map [string ]string ,
197+ ) error {
198+ log := logf .FromContext (ctx )
199+ log .Info ("syncing location types" , "count" , len (locationType ))
200+ syncSvc := sync .NewLocationSync (nautobotClient )
201+ if err := syncSvc .SyncAll (ctx , locationType ); err != nil {
202+ return fmt .Errorf ("failed to sync location types: %w" , err )
203+ }
180204 return nil
181205}
182206
@@ -185,13 +209,11 @@ func (r *NautobotReconciler) syncLocationTypes(ctx context.Context,
185209 locationType map [string ]string ,
186210) error {
187211 log := logf .FromContext (ctx )
188-
189- log .Info ("syncing location types" , "locationTypeCount" , len (locationType ))
212+ log .Info ("syncing location types" , "count" , len (locationType ))
190213 syncSvc := sync .NewLocationTypeSync (nautobotClient )
191214 if err := syncSvc .SyncAll (ctx , locationType ); err != nil {
192215 return fmt .Errorf ("failed to sync location types: %w" , err )
193216 }
194-
195217 return nil
196218}
197219
0 commit comments