Skip to content

Commit 2a6b6a0

Browse files
committed
Support for Failure Domain for VSphereCluster
- Adds logic to add the reconciliation of deployment zones associated to the cluster based on matching Spec.Server field. Signed-off-by: Sagar Muchhal <[email protected]>
1 parent e37a54a commit 2a6b6a0

File tree

4 files changed

+354
-55
lines changed

4 files changed

+354
-55
lines changed

api/v1alpha3/condition_consts.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,20 @@ const (
4747
// while installing the container storage interface addon; those kind of errors are usually transient
4848
// the operation is automatically re-tried by the controller.
4949
CSIProvisioningFailedReason = "CSIProvisioningFailed"
50+
51+
// FailureDomainsAvailableCondition documents the status of the failure domains
52+
// associated to the VSphereCluster.
53+
FailureDomainsAvailableCondition clusterv1.ConditionType = "FailureDomainsAvailable"
54+
55+
// FailureDomainsSkippedReason (Severity=Info) documents that some of the failure domain statuses
56+
// associated to the VSphereCluster are reported as not ready.
57+
FailureDomainsSkippedReason = "FailureDomainsSkipped"
58+
59+
// WaitingForFailureDomainStatusReason (Severity=Info) documents that some of the failure domains
60+
// associated to the VSphereCluster are not reporting the Ready status.
61+
// Instead of reporting a false ready status, these failure domains are still under the process of reconciling
62+
// and hence not yet reporting their status.
63+
WaitingForFailureDomainStatusReason = "WaitingForFailureDomainStatus"
5064
)
5165

5266
// Conditions and condition Reasons for the VSphereMachine and the VSphereVM object.

controllers/vspherecluster_controller.go

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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+
568628
var (
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

Comments
 (0)