@@ -2,6 +2,7 @@ package controller
22
33import (
44 "context"
5+ "encoding/json"
56 "errors"
67 "fmt"
78 "reflect"
@@ -31,6 +32,7 @@ import (
3132 ctrl "sigs.k8s.io/controller-runtime"
3233 "sigs.k8s.io/controller-runtime/pkg/client"
3334 "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
35+ "sigs.k8s.io/controller-runtime/pkg/log"
3436)
3537
3638const (
@@ -253,6 +255,11 @@ func (r *Reconciler) GetLastPod(
253255 maxPodWorkflowStep := 0
254256
255257 for _ , pod := range podList .Items {
258+ // Skip pods that are being deleted
259+ if pod .DeletionTimestamp != nil {
260+ continue
261+ }
262+
256263 workflowStep , err := strconv .Atoi (pod .Labels [workflowStepLabel ])
257264 if err != nil {
258265 return & corev1.Pod {}, err
@@ -489,8 +496,8 @@ func (r *Reconciler) EnsureLogsPVCExists(
489496}
490497
491498// GetLogger returns the logger instance
492- func (r * Reconciler ) GetLogger () logr.Logger {
493- return r . Log
499+ func (r * Reconciler ) GetLogger (ctx context. Context ) logr.Logger {
500+ return log . FromContext ( ctx )
494501}
495502
496503// GetScheme returns the runtime scheme
@@ -555,7 +562,7 @@ func (r *Reconciler) AcquireLock(
555562
556563// ReleaseLock releases the lock for the given instance
557564func (r * Reconciler ) ReleaseLock (ctx context.Context , instance client.Object ) (bool , error ) {
558- Log := r .GetLogger ()
565+ Log := r .GetLogger (ctx )
559566
560567 cm , err := r .GetLockInfo (ctx , instance )
561568 if err != nil && k8s_errors .IsNotFound (err ) {
@@ -913,3 +920,78 @@ func MergeSections(main interface{}, workflow interface{}) {
913920 }
914921 }
915922}
923+
924+ // CalculateConfigHash calculates a hash of the entire Spec to detect any changes
925+ func CalculateConfigHash (instance client.Object ) string {
926+ v := reflect .ValueOf (instance )
927+ spec , err := SafetyCheck (v , "Spec" )
928+ if err != nil {
929+ return ""
930+ }
931+
932+ data , err := json .Marshal (spec .Interface ())
933+ if err != nil {
934+ return ""
935+ }
936+
937+ hash := sha256 .Sum256 (data )
938+ return fmt .Sprintf ("%x" , hash [:8 ])
939+ }
940+
941+ // CheckConfigChange checks if the spec has changed and recreates all pods related to the instance if needed
942+ func (r * Reconciler ) CheckConfigChange (
943+ ctx context.Context ,
944+ instance client.Object ,
945+ newHash string ,
946+ ) (ctrl.Result , error ) {
947+ Log := r .GetLogger (ctx )
948+
949+ if newHash == "" {
950+ return ctrl.Result {}, nil
951+ }
952+
953+ labels := map [string ]string {instanceNameLabel : instance .GetName ()}
954+ podList := & corev1.PodList {}
955+ err := r .Client .List (ctx , podList ,
956+ client .InNamespace (instance .GetNamespace ()),
957+ client .MatchingLabels (labels ))
958+ if err != nil {
959+ return ctrl.Result {}, err
960+ }
961+
962+ var currentHash string
963+ for _ , pod := range podList .Items {
964+ if pod .DeletionTimestamp != nil {
965+ continue
966+ }
967+
968+ currentHash = pod .Annotations ["test.openstack.org/config-hash" ]
969+ if currentHash != "" && currentHash != newHash {
970+ break
971+ }
972+ currentHash = ""
973+ }
974+
975+ if currentHash == "" || currentHash == newHash {
976+ return ctrl.Result {}, nil
977+ }
978+
979+ Log .Info ("Configuration changed, deleting all related pods for recreation" ,
980+ "instance" , instance .GetName (),
981+ "currentHash" , currentHash ,
982+ "newHash" , newHash )
983+
984+ for _ , pod := range podList .Items {
985+ if pod .DeletionTimestamp != nil {
986+ continue
987+ }
988+
989+ Log .Info ("Deleting pod" , "pod" , pod .Name )
990+
991+ if err := r .Client .Delete (ctx , & pod ); err != nil && ! k8s_errors .IsNotFound (err ) {
992+ return ctrl.Result {}, err
993+ }
994+ }
995+
996+ return ctrl.Result {Requeue : true }, nil
997+ }
0 commit comments