@@ -18,6 +18,7 @@ package controller
1818
1919import (
2020 "context"
21+ "fmt"
2122 "time"
2223
2324 "github.com/PrefectHQ/prefect-operator/internal/prefect"
@@ -28,10 +29,13 @@ import (
2829 "k8s.io/apimachinery/pkg/api/meta"
2930 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3031 "k8s.io/apimachinery/pkg/runtime"
32+ "k8s.io/apimachinery/pkg/types"
3133 ctrl "sigs.k8s.io/controller-runtime"
3234 "sigs.k8s.io/controller-runtime/pkg/client"
3335 "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
36+ "sigs.k8s.io/controller-runtime/pkg/handler"
3437 "sigs.k8s.io/controller-runtime/pkg/log"
38+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
3539
3640 prefectiov1 "github.com/PrefectHQ/prefect-operator/api/v1"
3741 "github.com/PrefectHQ/prefect-operator/internal/conditions"
@@ -108,15 +112,25 @@ func (r *PrefectWorkPoolReconciler) Reconcile(ctx context.Context, req ctrl.Requ
108112 return ctrl.Result {RequeueAfter : time .Second }, nil
109113 }
110114
115+ var baseJobTemplateConfigMap corev1.ConfigMap
116+
117+ if workPool .Spec .BaseJobTemplate != nil && workPool .Spec .BaseJobTemplate .ConfigMap != nil {
118+ configMapRef := workPool .Spec .BaseJobTemplate .ConfigMap
119+ err := r .Get (ctx , types.NamespacedName {Name : configMapRef .Name , Namespace : workPool .Namespace }, & baseJobTemplateConfigMap )
120+ if err != nil {
121+ return ctrl.Result {}, err
122+ }
123+ }
124+
111125 specHash , err := utils .Hash (workPool .Spec , 16 )
112126 if err != nil {
113127 log .Error (err , "Failed to calculate spec hash" , "workPool" , workPool .Name )
114128 return ctrl.Result {}, err
115129 }
116130
117- if r .needsSync (& workPool , specHash ) {
131+ if r .needsSync (& workPool , specHash , & baseJobTemplateConfigMap ) {
118132 log .Info ("Starting sync with Prefect API" , "deployment" , workPool .Name )
119- err := r .syncWithPrefect (ctx , & workPool )
133+ err := r .syncWithPrefect (ctx , & workPool , & baseJobTemplateConfigMap )
120134 if err != nil {
121135 return ctrl.Result {}, err
122136 }
@@ -221,7 +235,7 @@ func (r *PrefectWorkPoolReconciler) Reconcile(ctx context.Context, req ctrl.Requ
221235 return ctrl.Result {}, nil
222236}
223237
224- func (r * PrefectWorkPoolReconciler ) needsSync (workPool * prefectiov1.PrefectWorkPool , currentSpecHash string ) bool {
238+ func (r * PrefectWorkPoolReconciler ) needsSync (workPool * prefectiov1.PrefectWorkPool , currentSpecHash string , baseJobTemplateConfigMap * corev1. ConfigMap ) bool {
225239 if workPool .Status .Id == nil || * workPool .Status .Id == "" {
226240 return true
227241 }
@@ -234,6 +248,10 @@ func (r *PrefectWorkPoolReconciler) needsSync(workPool *prefectiov1.PrefectWorkP
234248 return true
235249 }
236250
251+ if workPool .Status .BaseJobTemplateVersion != baseJobTemplateConfigMap .ResourceVersion {
252+ return true
253+ }
254+
237255 // Drift detection: sync if last sync was too long ago
238256 if workPool .Status .LastSyncTime == nil {
239257 return true
@@ -243,7 +261,7 @@ func (r *PrefectWorkPoolReconciler) needsSync(workPool *prefectiov1.PrefectWorkP
243261 return timeSinceLastSync > 10 * time .Minute
244262}
245263
246- func (r * PrefectWorkPoolReconciler ) syncWithPrefect (ctx context.Context , workPool * prefectiov1.PrefectWorkPool ) error {
264+ func (r * PrefectWorkPoolReconciler ) syncWithPrefect (ctx context.Context , workPool * prefectiov1.PrefectWorkPool , baseJobTemplateConfigMap * corev1. ConfigMap ) error {
247265 name := workPool .Name
248266 log := log .FromContext (ctx )
249267
@@ -259,8 +277,21 @@ func (r *PrefectWorkPoolReconciler) syncWithPrefect(ctx context.Context, workPoo
259277 return err
260278 }
261279
280+ var baseJobTemplate []byte
281+
282+ if baseJobTemplateConfigMap .Name != "" {
283+ key := workPool .Spec .BaseJobTemplate .ConfigMap .Key
284+
285+ baseJobTemplateJson , exists := baseJobTemplateConfigMap .Data [key ]
286+ if ! exists {
287+ return fmt .Errorf ("can't find key %s in ConfigMap %s" , key , baseJobTemplateConfigMap .Name )
288+ }
289+
290+ baseJobTemplate = []byte (baseJobTemplateJson )
291+ }
292+
262293 if prefectWorkPool == nil {
263- workPoolSpec , err := prefect .ConvertToWorkPoolSpec (workPool )
294+ workPoolSpec , err := prefect .ConvertToWorkPoolSpec (ctx , workPool , baseJobTemplate , prefectClient )
264295 if err != nil {
265296 log .Error (err , "Failed to convert work pool spec" , "workPool" , name )
266297 r .setCondition (workPool , PrefectWorkPoolConditionSynced , metav1 .ConditionFalse , "ConversionError" , err .Error ())
@@ -274,7 +305,7 @@ func (r *PrefectWorkPoolReconciler) syncWithPrefect(ctx context.Context, workPoo
274305 return err
275306 }
276307 } else {
277- workPoolSpec , err := prefect .ConvertToWorkPoolUpdateSpec (workPool )
308+ workPoolSpec , err := prefect .ConvertToWorkPoolUpdateSpec (ctx , workPool , baseJobTemplate , prefectClient )
278309 if err != nil {
279310 log .Error (err , "Failed to convert work pool spec" , "workPool" , name )
280311 r .setCondition (workPool , PrefectWorkPoolConditionSynced , metav1 .ConditionFalse , "ConversionError" , err .Error ())
@@ -302,6 +333,7 @@ func (r *PrefectWorkPoolReconciler) syncWithPrefect(ctx context.Context, workPoo
302333 workPool .Status .SpecHash = specHash
303334 workPool .Status .ObservedGeneration = workPool .Generation
304335 workPool .Status .LastSyncTime = & now
336+ workPool .Status .BaseJobTemplateVersion = baseJobTemplateConfigMap .ResourceVersion
305337
306338 r .setCondition (workPool , PrefectWorkPoolConditionSynced , metav1 .ConditionTrue , "SyncSuccessful" , "Work pool successfully synced with Prefect API" )
307339
@@ -384,10 +416,49 @@ func (r *PrefectWorkPoolReconciler) getPrefectClient(ctx context.Context, workPo
384416 return prefectClient , nil
385417}
386418
419+ // func (r *PrefectWorkPoolReconciler) mapConfigMapToWorkPools() handler.MapFunc {
420+ // return func(ctx context.Context, obj handler.MapObject) []reconcile.Request {
421+
422+ // func (r *PrefectWorkPoolReconciler) mapConfigMapToWorkPools(obj client.Object) []reconcile.Request {
423+ func (r * PrefectWorkPoolReconciler ) mapConfigMapToWorkPools (ctx context.Context , obj client.Object ) []reconcile.Request {
424+ configMap , ok := obj .(* corev1.ConfigMap )
425+ if ! ok {
426+ return nil
427+ }
428+
429+ // List all CRs in the ConfigMap's namespace
430+ workPools := & prefectiov1.PrefectWorkPoolList {}
431+ if err := r .List (ctx , workPools , client .InNamespace (configMap .Namespace )); err != nil {
432+ // Log error if needed
433+ return nil
434+ }
435+
436+ if len (workPools .Items ) == 0 {
437+ return nil
438+ }
439+
440+ var requests []reconcile.Request
441+ for _ , workPool := range workPools .Items {
442+ if workPool .Spec .BaseJobTemplate != nil &&
443+ workPool .Spec .BaseJobTemplate .ConfigMap != nil &&
444+ workPool .Spec .BaseJobTemplate .ConfigMap .Name == configMap .Name {
445+ requests = append (requests , reconcile.Request {
446+ NamespacedName : types.NamespacedName {
447+ Name : workPool .Name ,
448+ Namespace : workPool .Namespace ,
449+ },
450+ })
451+ }
452+ }
453+
454+ return requests
455+ }
456+
387457// SetupWithManager sets up the controller with the Manager.
388458func (r * PrefectWorkPoolReconciler ) SetupWithManager (mgr ctrl.Manager ) error {
389459 return ctrl .NewControllerManagedBy (mgr ).
390460 For (& prefectiov1.PrefectWorkPool {}).
391461 Owns (& appsv1.Deployment {}).
462+ Watches (& corev1.ConfigMap {ObjectMeta : metav1.ObjectMeta {Namespace : "prefect" }}, handler .EnqueueRequestsFromMapFunc (r .mapConfigMapToWorkPools )).
392463 Complete (r )
393464}
0 commit comments