@@ -39,6 +39,7 @@ import (
3939 "sigs.k8s.io/cluster-api/util/annotations"
4040 v1beta1conditions "sigs.k8s.io/cluster-api/util/deprecated/v1beta1/conditions"
4141 "sigs.k8s.io/cluster-api/util/patch"
42+ "sigs.k8s.io/cluster-api/util/predicates"
4243 ctrl "sigs.k8s.io/controller-runtime"
4344 "sigs.k8s.io/controller-runtime/pkg/builder"
4445 "sigs.k8s.io/controller-runtime/pkg/client"
@@ -50,7 +51,7 @@ import (
5051 "sigs.k8s.io/controller-runtime/pkg/reconcile"
5152
5253 orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1"
53- "github.com/k-orc/openstack-resource-controller/v2/pkg/predicates"
54+ orcpredicates "github.com/k-orc/openstack-resource-controller/v2/pkg/predicates"
5455
5556 infrav1alpha1 "sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha1"
5657 infrav1 "sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1"
@@ -78,6 +79,7 @@ type OpenStackServerReconciler struct {
7879
7980// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=openstackservers,verbs=get;list;watch;create;update;patch;delete
8081// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=openstackservers/status,verbs=get;update;patch
82+ // +kubebuilder:rbac:groups=cluster.x-k8s.io,resources=clusters;clusters/status,verbs=get;list;watch
8183// +kubebuilder:rbac:groups=ipam.cluster.x-k8s.io,resources=ipaddressclaims;ipaddressclaims/status,verbs=get;watch;create;update;patch;delete
8284// +kubebuilder:rbac:groups=ipam.cluster.x-k8s.io,resources=ipaddresses;ipaddresses/status,verbs=get;list;watch
8385// +kubebuilder:rbac:groups=openstack.k-orc.cloud,resources=images,verbs=get;list;watch
@@ -105,17 +107,6 @@ func (r *OpenStackServerReconciler) Reconcile(ctx context.Context, req ctrl.Requ
105107
106108 scope .Logger ().Info ("Reconciling OpenStackServer" )
107109
108- cluster , err := getClusterFromMetadata (ctx , r .Client , openStackServer .ObjectMeta )
109- if err != nil {
110- return reconcile.Result {}, err
111- }
112- if cluster != nil {
113- if annotations .IsPaused (cluster , openStackServer ) {
114- scope .Logger ().Info ("OpenStackServer linked to a Cluster that is paused. Won't reconcile" )
115- return reconcile.Result {}, nil
116- }
117- }
118-
119110 patchHelper , err := patch .NewHelper (openStackServer , r .Client )
120111 if err != nil {
121112 return ctrl.Result {}, err
@@ -134,6 +125,7 @@ func (r *OpenStackServerReconciler) Reconcile(ctx context.Context, req ctrl.Requ
134125 }
135126 }()
136127
128+ // Handle deleted servers
137129 if ! openStackServer .DeletionTimestamp .IsZero () {
138130 // When moving a cluster, we need to populate the server status with the resources
139131 // that were in another object's status.
@@ -146,6 +138,18 @@ func (r *OpenStackServerReconciler) Reconcile(ctx context.Context, req ctrl.Requ
146138 return reconcile.Result {}, r .reconcileDelete (scope , openStackServer )
147139 }
148140
141+ // Handle non-deleted servers
142+ cluster , err := getClusterFromMetadata (ctx , r .Client , openStackServer .ObjectMeta )
143+ if err != nil {
144+ return reconcile.Result {}, err
145+ }
146+ if cluster != nil {
147+ if annotations .IsPaused (cluster , openStackServer ) {
148+ scope .Logger ().Info ("OpenStackServer linked to a Cluster that is paused. Won't reconcile" )
149+ return reconcile.Result {}, nil
150+ }
151+ }
152+
149153 return r .reconcileNormal (ctx , scope , openStackServer )
150154}
151155
@@ -218,7 +222,12 @@ func (r *OpenStackServerReconciler) SetupWithManager(ctx context.Context, mgr ct
218222 }
219223 return requests
220224 }),
221- builder .WithPredicates (predicates .NewBecameAvailable (mgr .GetLogger (), & orcv1alpha1.Image {})),
225+ builder .WithPredicates (orcpredicates .NewBecameAvailable (mgr .GetLogger (), & orcv1alpha1.Image {})),
226+ ).
227+ Watches (
228+ & clusterv1.Cluster {},
229+ handler .EnqueueRequestsFromMapFunc (r .requeueOpenStackServersForCluster (ctx )),
230+ builder .WithPredicates (predicates .ClusterPausedTransitionsOrInfrastructureProvisioned (mgr .GetScheme (), log )),
222231 ).
223232 Watches (
224233 & ipamv1.IPAddressClaim {},
@@ -752,3 +761,50 @@ func OpenStackServerReconcileComplete(log logr.Logger) predicate.Funcs {
752761 GenericFunc : func (event.GenericEvent ) bool { return false },
753762 }
754763}
764+
765+ // requeueOpenStackServersForCluster returns a handler.MapFunc that watches for
766+ // Cluster changes and triggers reconciliation of all OpenStackServers in that cluster.
767+ func (r * OpenStackServerReconciler ) requeueOpenStackServersForCluster (ctx context.Context ) handler.MapFunc {
768+ log := ctrl .LoggerFrom (ctx )
769+ return func (ctx context.Context , o client.Object ) []ctrl.Request {
770+ c , ok := o .(* clusterv1.Cluster )
771+ if ! ok {
772+ panic (fmt .Sprintf ("Expected a Cluster but got a %T" , o ))
773+ }
774+
775+ log := log .WithValues ("objectMapper" , "clusterToOpenStackServer" , "namespace" , c .Namespace , "cluster" , c .Name )
776+
777+ // Don't handle deleted clusters - servers will be cleaned up via their own deletion flow
778+ if ! c .DeletionTimestamp .IsZero () {
779+ log .V (4 ).Info ("Cluster has a deletion timestamp, skipping mapping." )
780+ return nil
781+ }
782+
783+ // List all OpenStackServers in the cluster
784+ serverList := & infrav1alpha1.OpenStackServerList {}
785+ if err := r .Client .List (
786+ ctx ,
787+ serverList ,
788+ client .InNamespace (c .Namespace ),
789+ client.MatchingLabels {clusterv1 .ClusterNameLabel : c .Name },
790+ ); err != nil {
791+ log .Error (err , "Failed to list OpenStackServers for cluster" )
792+ return nil
793+ }
794+
795+ // Create reconcile requests for all servers
796+ requests := make ([]ctrl.Request , 0 , len (serverList .Items ))
797+ for i := range serverList .Items {
798+ server := & serverList .Items [i ]
799+ requests = append (requests , ctrl.Request {
800+ NamespacedName : client.ObjectKey {
801+ Namespace : server .Namespace ,
802+ Name : server .Name ,
803+ },
804+ })
805+ log .V (5 ).Info ("Queueing OpenStackServer for reconciliation" , "server" , server .Name )
806+ }
807+
808+ return requests
809+ }
810+ }
0 commit comments