@@ -26,10 +26,13 @@ import (
2626 "k8s.io/apimachinery/pkg/runtime"
2727 "k8s.io/client-go/kubernetes"
2828 ctrl "sigs.k8s.io/controller-runtime"
29+ "sigs.k8s.io/controller-runtime/pkg/builder"
2930 "sigs.k8s.io/controller-runtime/pkg/client"
3031 "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
32+ "sigs.k8s.io/controller-runtime/pkg/event"
3133 "sigs.k8s.io/controller-runtime/pkg/handler"
3234 "sigs.k8s.io/controller-runtime/pkg/log"
35+ "sigs.k8s.io/controller-runtime/pkg/predicate"
3336 "sigs.k8s.io/controller-runtime/pkg/reconcile"
3437
3538 "github.com/go-logr/logr"
@@ -82,6 +85,8 @@ func (r *OpenStackVersionReconciler) GetLogger(ctx context.Context) logr.Logger
8285// +kubebuilder:rbac:groups=core.openstack.org,resources=openstackversions/finalizers,verbs=update;patch
8386// +kubebuilder:rbac:groups=core.openstack.org,resources=openstackcontrolplanes,verbs=get;list;watch
8487// +kubebuilder:rbac:groups=dataplane.openstack.org,resources=openstackdataplanenodesets,verbs=get;list;watch
88+ // +kubebuilder:rbac:groups=dataplane.openstack.org,resources=openstackdataplanedeployments,verbs=get;list;watch
89+ // +kubebuilder:rbac:groups=dataplane.openstack.org,resources=openstackdataplaneservices,verbs=get;list;watch
8590
8691// Reconcile is part of the main kubernetes reconciliation loop which aims to
8792// move the current state of the cluster closer to the desired state.
@@ -344,16 +349,24 @@ func (r *OpenStackVersionReconciler) Reconcile(ctx context.Context, req ctrl.Req
344349 prevOvnDataplaneCond := savedConditions .Get (corev1beta1 .OpenStackVersionMinorUpdateOVNDataplane )
345350 if prevOvnDataplaneCond == nil ||
346351 prevOvnDataplaneCond .Reason != condition .RequestedReason {
347- // We have never observed a running OVN deployment in
348- // this update cycle — the deployment has not been
349- // created yet. Keep waiting.
350- instance .Status .Conditions .Set (condition .FalseCondition (
351- corev1beta1 .OpenStackVersionMinorUpdateOVNDataplane ,
352- condition .InitReason ,
353- condition .SeverityInfo ,
354- corev1beta1 .OpenStackVersionMinorUpdateReadyRunningMessage ))
355- Log .Info ("Waiting for OVN Dataplane deployment to be created (OVN image unchanged between versions)" )
356- return ctrl.Result {}, nil
352+ // The saved condition doesn't show we observed a running
353+ // deployment (may be due to reconcile race). Check if a
354+ // completed deployment already exists for the target version.
355+ ovnDeploymentCompleted , err := openstack .IsDataplaneDeploymentCompletedForServiceType (
356+ ctx , versionHelper , instance .Namespace , dataplaneNodesets , "ovn" , instance .Spec .TargetVersion )
357+ if err != nil {
358+ return ctrl.Result {}, err
359+ }
360+ if ! ovnDeploymentCompleted {
361+ instance .Status .Conditions .Set (condition .FalseCondition (
362+ corev1beta1 .OpenStackVersionMinorUpdateOVNDataplane ,
363+ condition .InitReason ,
364+ condition .SeverityInfo ,
365+ corev1beta1 .OpenStackVersionMinorUpdateReadyRunningMessage ))
366+ Log .Info ("Waiting for OVN Dataplane deployment to be created (OVN image unchanged between versions)" )
367+ return ctrl.Result {}, nil
368+ }
369+ Log .Info ("OVN Dataplane deployment completed (found completed deployment for target version)" )
357370 }
358371 // Previously saw a running OVN deployment (condition was
359372 // False/RequestedReason), now no OVN deployment is running
@@ -526,9 +539,38 @@ func (r *OpenStackVersionReconciler) SetupWithManager(mgr ctrl.Manager) error {
526539 return nil
527540 })
528541
542+ // Only reconcile when a deployment's Deployed status changes,
543+ // not on every status update during deployment execution.
544+ // The dataplane controller sets Deployed and DeployedVersion
545+ // in the same status update, so checking Deployed alone is sufficient.
546+ deploymentStatusPredicate := predicate.Funcs {
547+ CreateFunc : func (_ event.CreateEvent ) bool {
548+ return true
549+ },
550+ UpdateFunc : func (e event.UpdateEvent ) bool {
551+ oldDepl , ok := e .ObjectOld .(* dataplanev1.OpenStackDataPlaneDeployment )
552+ if ! ok {
553+ return false
554+ }
555+ newDepl , ok := e .ObjectNew .(* dataplanev1.OpenStackDataPlaneDeployment )
556+ if ! ok {
557+ return false
558+ }
559+ return oldDepl .Status .Deployed != newDepl .Status .Deployed
560+ },
561+ DeleteFunc : func (_ event.DeleteEvent ) bool {
562+ return false
563+ },
564+ GenericFunc : func (_ event.GenericEvent ) bool {
565+ return false
566+ },
567+ }
568+
529569 return ctrl .NewControllerManagedBy (mgr ).
530570 Watches (& corev1beta1.OpenStackControlPlane {}, versionFunc ).
531571 Watches (& dataplanev1.OpenStackDataPlaneNodeSet {}, versionFunc ).
572+ Watches (& dataplanev1.OpenStackDataPlaneDeployment {}, versionFunc ,
573+ builder .WithPredicates (deploymentStatusPredicate )).
532574 For (& corev1beta1.OpenStackVersion {}).
533575 Complete (r )
534576}
0 commit comments