@@ -2515,3 +2515,175 @@ func (b *Bootstrap) fetchSubscription(subName, packageManifest, operatorNs strin
2515
2515
}
2516
2516
return sub , nil
2517
2517
}
2518
+
2519
+ // Wait for Postgres Cluster CR image to be updated with the image from the configmap
2520
+ func (b * Bootstrap ) WaitForPostgresClusterImageUpdate (ctx context.Context , instance * apiv3.CommonService ) error {
2521
+ // Check if Postgres Cluster CR "common-service-db" is created in service namespace
2522
+ pgCluster := & unstructured.Unstructured {}
2523
+ pgCluster .SetGroupVersionKind (schema.GroupVersionKind {
2524
+ Group : constant .PGClusterGroup ,
2525
+ Version : "v1" ,
2526
+ Kind : constant .PGClusterKind ,
2527
+ })
2528
+
2529
+ if clusterCRDExists , err := b .CheckCRD (constant .PGClusterGroup + "/v1" , constant .PGClusterKind ); err != nil {
2530
+ klog .Errorf ("Failed to check if Postgres Cluster CRD exists: %v" , err )
2531
+ return err
2532
+ } else if ! clusterCRDExists {
2533
+ klog .Infof ("Postgres %s Cluster CRD not found, skipping Postgres Cluster image update check" , constant .PGClusterGroup + "/v1" )
2534
+ return nil
2535
+ }
2536
+
2537
+ if err := b .Client .Get (ctx , types.NamespacedName {
2538
+ Name : constant .CSPGCluster ,
2539
+ Namespace : b .CSData .ServicesNs ,
2540
+ }, pgCluster ); err != nil {
2541
+ if errors .IsNotFound (err ) {
2542
+ klog .Infof ("Postgres Cluster CR %s not found in namespace %s, skipping Cluster CR image update check" , constant .CSPGCluster , b .CSData .ServicesNs )
2543
+ return nil
2544
+ }
2545
+ return err
2546
+ }
2547
+
2548
+ configMap , err := b .getPostgresImageConfigMap (ctx )
2549
+ if err != nil {
2550
+ return err
2551
+ } else if configMap == nil {
2552
+ klog .Infof ("Neither %s nor %s configmap found in namespace %s, skipping Postgres Cluster image update check" ,
2553
+ constant .PostgreSQLImageConfigMap , constant .CSPostgreSQLImageConfigMap , b .CSData .OperatorNs )
2554
+ return nil
2555
+ }
2556
+ configMapName := configMap .GetName ()
2557
+ imageKeyName := constant .PostgreSQL16ImageKey
2558
+
2559
+ // Get the image from the configmap
2560
+ desiredImage , exists := configMap .Data [imageKeyName ]
2561
+ if ! exists {
2562
+ klog .Infof ("Image key %s not found in configmap %s/%s, skipping image update check" ,
2563
+ imageKeyName , b .CSData .OperatorNs , configMapName )
2564
+ return nil
2565
+ }
2566
+
2567
+ // Get current image from the Postgres Cluster CR
2568
+ currentImage , found , err := unstructured .NestedString (pgCluster .Object , "spec" , "imageName" )
2569
+ if err != nil {
2570
+ return err
2571
+ }
2572
+
2573
+ // If image is already updated, return nil
2574
+ if found && currentImage == desiredImage {
2575
+ klog .Infof ("Postgres Cluster CR %s image already updated to the desired image in configmap %s/%s" ,
2576
+ constant .CSPGCluster , b .CSData .OperatorNs , configMapName )
2577
+ return nil
2578
+ }
2579
+
2580
+ // Update the configmap with ODLM metadata to trigger ODLM reconciliation
2581
+ if err := b .updateConfigMapWithODLMMetadata (ctx , configMap ); err != nil {
2582
+ return err
2583
+ }
2584
+
2585
+ // Wait for the image to be updated
2586
+ return utilwait .PollImmediate (time .Second * 10 , time .Minute * 2 , func () (done bool , err error ) {
2587
+ // Fetch the latest Postgres Cluster CR
2588
+ err = b .Client .Get (ctx , types.NamespacedName {
2589
+ Name : constant .CSPGCluster ,
2590
+ Namespace : b .CSData .ServicesNs ,
2591
+ }, pgCluster )
2592
+
2593
+ if err != nil {
2594
+ if errors .IsNotFound (err ) {
2595
+ return true , nil
2596
+ }
2597
+ return false , err
2598
+ }
2599
+
2600
+ // Check if image is updated
2601
+ currentImage , found , err := unstructured .NestedString (pgCluster .Object , "spec" , "imageName" )
2602
+ if err != nil {
2603
+ return false , err
2604
+ }
2605
+
2606
+ if found && currentImage == desiredImage {
2607
+ klog .Infof ("Postgres Cluster CR %s image updated to the desired image in configmap %s/%s" ,
2608
+ constant .CSPGCluster , b .CSData .OperatorNs , configMapName )
2609
+ return true , nil
2610
+ }
2611
+
2612
+ klog .Infof ("Postgres Cluster CR %s image is not updated, waiting for update to the desired image in configmap %s/%s" ,
2613
+ constant .CSPGCluster , b .CSData .OperatorNs , configMapName )
2614
+ return false , nil
2615
+ })
2616
+ }
2617
+
2618
+ // getPostgresImageConfigMap gets the configmap containing PostgreSQL image information
2619
+ // It first tries to get the configmap deployed with Postgres Operator,
2620
+ // and if not found, it looks for the configmap created by CS operator
2621
+ func (b * Bootstrap ) getPostgresImageConfigMap (ctx context.Context ) (* corev1.ConfigMap , error ) {
2622
+ configMap := & corev1.ConfigMap {}
2623
+ configMapName := constant .PostgreSQLImageConfigMap
2624
+
2625
+ if err := b .Client .Get (ctx , types.NamespacedName {
2626
+ Name : configMapName ,
2627
+ Namespace : b .CSData .OperatorNs ,
2628
+ }, configMap ); err != nil && errors .IsNotFound (err ) {
2629
+ // If the configmap is not found, find configmap created by CS operator
2630
+ configMapName = constant .CSPostgreSQLImageConfigMap
2631
+
2632
+ if err := b .Client .Get (ctx , types.NamespacedName {
2633
+ Name : configMapName ,
2634
+ Namespace : b .CSData .OperatorNs ,
2635
+ }, configMap ); err != nil {
2636
+ if errors .IsNotFound (err ) {
2637
+
2638
+ return nil , nil
2639
+ }
2640
+ klog .Errorf ("Failed to get configmap %s in namespace %s: %v" , configMapName , b .CSData .OperatorNs , err )
2641
+ return nil , err
2642
+ }
2643
+ } else if err != nil {
2644
+ klog .Errorf ("Failed to get configmap %s in namespace %s: %v" , configMapName , b .CSData .OperatorNs , err )
2645
+ return nil , err
2646
+ }
2647
+
2648
+ return configMap , nil
2649
+ }
2650
+
2651
+ // updateConfigMapWithODLMMetadata adds ODLM-specific labels and annotations to a ConfigMap
2652
+ // to ensure it's properly reconciled by the Operand Deployment Lifecycle Manager
2653
+ func (b * Bootstrap ) updateConfigMapWithODLMMetadata (ctx context.Context , configMap * corev1.ConfigMap ) error {
2654
+ // Check if the configmap has the required label and annotation
2655
+ needsLabelUpdate := false
2656
+ cmLabels := configMap .GetLabels ()
2657
+ if cmLabels == nil {
2658
+ cmLabels = make (map [string ]string )
2659
+ needsLabelUpdate = true
2660
+ }
2661
+
2662
+ if _ , exists := cmLabels [constant .ODLMWatchLabel ]; ! exists {
2663
+ cmLabels [constant .ODLMWatchLabel ] = "true"
2664
+ needsLabelUpdate = true
2665
+ }
2666
+
2667
+ cmAnnotations := configMap .GetAnnotations ()
2668
+ if cmAnnotations == nil {
2669
+ cmAnnotations = make (map [string ]string )
2670
+ needsLabelUpdate = true
2671
+ }
2672
+
2673
+ expectedAnnotation := fmt .Sprintf ("OperandConfig.%s.common-service" , b .CSData .ServicesNs )
2674
+ if cmAnnotations [constant .ODLMReferenceAnno ] != expectedAnnotation {
2675
+ cmAnnotations [constant .ODLMReferenceAnno ] = expectedAnnotation
2676
+ needsLabelUpdate = true
2677
+ }
2678
+
2679
+ if needsLabelUpdate {
2680
+ klog .Infof ("Updating configmap %s/%s with ODLM labels and annotations to trigger the ODLM reconciliation" , configMap .Namespace , configMap .Name )
2681
+ configMap .SetLabels (cmLabels )
2682
+ configMap .SetAnnotations (cmAnnotations )
2683
+ if err := b .Client .Update (ctx , configMap ); err != nil {
2684
+ return err
2685
+ }
2686
+ }
2687
+
2688
+ return nil
2689
+ }
0 commit comments