@@ -82,7 +82,6 @@ func AddClusterControllerToManager(ctx *context.ControllerManagerContext, mgr ma
8282 Recorder : record .New (mgr .GetEventRecorderFor (controllerNameLong )),
8383 Logger : ctx .Logger .WithName (controllerNameShort ),
8484 }
85-
8685 reconciler := clusterReconciler {ControllerContext : controllerContext }
8786
8887 return ctrl .NewControllerManagedBy (mgr ).
@@ -116,6 +115,14 @@ func AddClusterControllerToManager(ctx *context.ControllerManagerContext, mgr ma
116115 ToRequests : handler .ToRequestsFunc (reconciler .loadBalancerToCluster ),
117116 },
118117 ).
118+ // Watch the Vsphere deployment zone with the Server field matching the
119+ // server field of the VSphereCluster.
120+ Watches (
121+ & source.Kind {Type : & infrav1.VSphereDeploymentZone {}},
122+ & handler.EnqueueRequestsFromMapFunc {
123+ ToRequests : handler .ToRequestsFunc (reconciler .deploymentZoneToCluster ),
124+ },
125+ ).
119126 // Watch a GenericEvent channel for the controlled resource.
120127 //
121128 // This is useful when there are events outside of Kubernetes that
@@ -280,6 +287,15 @@ func (r clusterReconciler) reconcileNormal(ctx *context.ClusterContext) (reconci
280287 // If the VSphereCluster doesn't have our finalizer, add it.
281288 ctrlutil .AddFinalizer (ctx .VSphereCluster , infrav1 .ClusterFinalizer )
282289
290+ ok , err := r .reconcileDeploymentZones (ctx )
291+ if err != nil {
292+ return reconcile.Result {}, err
293+ }
294+ if ! ok {
295+ ctx .Logger .Info ("waiting for failure domains to be reconciled" )
296+ return reconcile.Result {RequeueAfter : 10 * time .Second }, nil
297+ }
298+
283299 if err := r .reconcileIdentitySecret (ctx ); err != nil {
284300 conditions .MarkFalse (ctx .VSphereCluster , infrav1 .VCenterAvailableCondition , infrav1 .VCenterUnreachableReason , clusterv1 .ConditionSeverityError , err .Error ())
285301 return reconcile.Result {}, err
@@ -565,6 +581,50 @@ func (r clusterReconciler) reconcileLoadBalancer(ctx *context.ClusterContext) (b
565581 return true , nil
566582}
567583
584+ func (r clusterReconciler ) reconcileDeploymentZones (ctx * context.ClusterContext ) (bool , error ) {
585+ var deploymentZoneList infrav1.VSphereDeploymentZoneList
586+ err := r .Client .List (ctx , & deploymentZoneList )
587+ if err != nil {
588+ return false , errors .Wrap (err , "unable to list deployment zones" )
589+ }
590+
591+ readyNotReported , notReady := 0 , 0
592+ failureDomains := clusterv1.FailureDomains {}
593+ for _ , zone := range deploymentZoneList .Items {
594+ if zone .Spec .Server == ctx .VSphereCluster .Spec .Server {
595+ if zone .Status .Ready == nil {
596+ readyNotReported ++
597+ failureDomains [zone .Name ] = clusterv1.FailureDomainSpec {
598+ ControlPlane : * zone .Spec .ControlPlane ,
599+ }
600+ } else {
601+ if * zone .Status .Ready {
602+ failureDomains [zone .Name ] = clusterv1.FailureDomainSpec {
603+ ControlPlane : * zone .Spec .ControlPlane ,
604+ }
605+ } else {
606+ notReady ++
607+ }
608+ }
609+ }
610+ }
611+
612+ ctx .VSphereCluster .Status .FailureDomains = failureDomains
613+ if readyNotReported > 0 {
614+ conditions .MarkFalse (ctx .VSphereCluster , infrav1 .FailureDomainsAvailableCondition , infrav1 .WaitingForFailureDomainStatusReason , clusterv1 .ConditionSeverityInfo , "waiting for failure domains to report ready status" )
615+ return false , nil
616+ }
617+
618+ if len (failureDomains ) > 0 {
619+ if notReady > 0 {
620+ conditions .MarkFalse (ctx .VSphereCluster , infrav1 .FailureDomainsAvailableCondition , infrav1 .FailureDomainsSkippedReason , clusterv1 .ConditionSeverityInfo , "one or more failure domains are not ready" )
621+ } else {
622+ conditions .MarkTrue (ctx .VSphereCluster , infrav1 .FailureDomainsAvailableCondition )
623+ }
624+ }
625+ return true , nil
626+ }
627+
568628var (
569629 // apiServerTriggers is used to prevent multiple goroutines for a single
570630 // Cluster that poll to see if the target API server is online.
@@ -971,3 +1031,32 @@ func (r clusterReconciler) loadBalancerToCluster(o handler.MapObject) []ctrl.Req
9711031 },
9721032 }}
9731033}
1034+
1035+ func (r clusterReconciler ) deploymentZoneToCluster (o handler.MapObject ) []reconcile.Request {
1036+ var requests []ctrl.Request
1037+ obj , ok := o .Object .(* infrav1.VSphereDeploymentZone )
1038+ if ! ok {
1039+ r .Logger .Error (nil , fmt .Sprintf ("expected an infrav1.VSphereDeploymentZone but got a %T" , o ))
1040+ return nil
1041+ }
1042+
1043+ var clusterList infrav1.VSphereClusterList
1044+ err := r .Client .List (r .Context , & clusterList )
1045+ if err != nil {
1046+ r .Logger .Error (err , fmt .Sprintf ("unable to list clusters" ))
1047+ return requests
1048+ }
1049+
1050+ for _ , cluster := range clusterList .Items {
1051+ if obj .Spec .Server == cluster .Spec .Server {
1052+ r := reconcile.Request {
1053+ NamespacedName : types.NamespacedName {
1054+ Name : cluster .Name ,
1055+ Namespace : cluster .Namespace ,
1056+ },
1057+ }
1058+ requests = append (requests , r )
1059+ }
1060+ }
1061+ return requests
1062+ }
0 commit comments