Skip to content

Commit bab7415

Browse files
committed
Address review comments
- Refine VMG controller watch - Refine naming, logging, godoc - Miscellaneous Signed-off-by: Gong Zhang <[email protected]>
1 parent e3078c9 commit bab7415

File tree

5 files changed

+100
-84
lines changed

5 files changed

+100
-84
lines changed

config/rbac/role.yaml

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ rules:
250250
- vmoperator.vmware.com
251251
resources:
252252
- virtualmachinegroups
253+
- virtualmachinegroups/status
253254
- virtualmachineimages
254255
- virtualmachineimages/status
255256
- virtualmachines
@@ -265,12 +266,6 @@ rules:
265266
- patch
266267
- update
267268
- watch
268-
- apiGroups:
269-
- vmoperator.vmware.com
270-
resources:
271-
- virtualmachinegroups/status
272-
verbs:
273-
- get
274269
- apiGroups:
275270
- vmware.com
276271
resources:

controllers/vmware/virtualmachinegroup_controller.go

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ import (
4040
// +kubebuilder:rbac:groups=cluster.x-k8s.io,resources=clusters,verbs=get;list;watch
4141
// +kubebuilder:rbac:groups=cluster.x-k8s.io,resources=clusters/status,verbs=get
4242
// +kubebuilder:rbac:groups=vmoperator.vmware.com,resources=virtualmachinegroups,verbs=get;list;watch;create;update;patch;delete
43-
// +kubebuilder:rbac:groups=vmoperator.vmware.com,resources=virtualmachinegroups/status,verbs=get
43+
// +kubebuilder:rbac:groups=vmoperator.vmware.com,resources=virtualmachinegroups/status,verbs=get;list;watch;create;update;patch;delete
4444
// +kubebuilder:rbac:groups=vmware.infrastructure.cluster.x-k8s.io,resources=vspheremachines,verbs=get;list;watch
4545
// +kubebuilder:rbac:groups=cluster.x-k8s.io,resources=machinedeployments,verbs=get;list;watch
4646
// +kubebuilder:rbac:groups=cluster.x-k8s.io,resources=machines,verbs=get;list;watch
@@ -62,15 +62,24 @@ func AddVirtualMachineGroupControllerToManager(ctx context.Context, controllerMa
6262
Watches(
6363
&vmoprv1.VirtualMachineGroup{},
6464
handler.EnqueueRequestForOwner(mgr.GetScheme(), reconciler.Client.RESTMapper(), &clusterv1.Cluster{}),
65+
ctrlbldr.WithPredicates(predicates.ResourceIsChanged(mgr.GetScheme(), predicateLog)),
6566
).
6667
Watches(
6768
&vmwarev1.VSphereMachine{},
6869
handler.EnqueueRequestsFromMapFunc(reconciler.VSphereMachineToCluster),
6970
ctrlbldr.WithPredicates(
7071
predicate.Funcs{
71-
UpdateFunc: func(event.UpdateEvent) bool { return false },
72-
CreateFunc: func(event.CreateEvent) bool { return true },
73-
DeleteFunc: func(event.DeleteEvent) bool { return true },
72+
UpdateFunc: func(event.UpdateEvent) bool { return false },
73+
CreateFunc: func(e event.CreateEvent) bool {
74+
// Only handle VSphereMachine which belongs to a MachineDeployment
75+
_, found := e.Object.GetLabels()[clusterv1.MachineDeploymentNameLabel]
76+
return found
77+
},
78+
DeleteFunc: func(e event.DeleteEvent) bool {
79+
// Only handle VSphereMachine which belongs to a MachineDeployment
80+
_, found := e.Object.GetLabels()[clusterv1.MachineDeploymentNameLabel]
81+
return found
82+
},
7483
GenericFunc: func(event.GenericEvent) bool { return false },
7584
}),
7685
).
@@ -80,9 +89,7 @@ func AddVirtualMachineGroupControllerToManager(ctx context.Context, controllerMa
8089
}
8190

8291
// VSphereMachineToCluster maps VSphereMachine events to Cluster reconcile requests.
83-
// This handler only processes VSphereMachine objects for Day-2 operations when VMG could be found, ensuring
84-
// VMG member list in sync with VSphereMachines. If no corresponding VMG is found, this is a no-op.
85-
func (r *VirtualMachineGroupReconciler) VSphereMachineToCluster(ctx context.Context, a ctrlclient.Object) []reconcile.Request {
92+
func (r *VirtualMachineGroupReconciler) VSphereMachineToCluster(_ context.Context, a ctrlclient.Object) []reconcile.Request {
8693
vSphereMachine, ok := a.(*vmwarev1.VSphereMachine)
8794
if !ok {
8895
return nil
@@ -93,17 +100,10 @@ func (r *VirtualMachineGroupReconciler) VSphereMachineToCluster(ctx context.Cont
93100
return nil
94101
}
95102

96-
vmg := &vmoprv1.VirtualMachineGroup{}
97-
err := r.Client.Get(ctx, apitypes.NamespacedName{Namespace: vSphereMachine.Namespace, Name: clusterName}, vmg)
98-
99-
if err != nil {
100-
return nil
101-
}
102-
103103
return []reconcile.Request{{
104104
NamespacedName: apitypes.NamespacedName{
105-
Namespace: vmg.Namespace,
106-
Name: vmg.Name,
105+
Namespace: vSphereMachine.Namespace,
106+
Name: clusterName,
107107
},
108108
}}
109109
}

controllers/vmware/virtualmachinegroup_reconciler.go

Lines changed: 43 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ const (
4545
// reconciliationDelay is the delay time for requeueAfter.
4646
reconciliationDelay = 10 * time.Second
4747
// ZoneAnnotationPrefix is the prefix used for placement decision annotations which will be set on VirtualMachineGroup.
48-
ZoneAnnotationPrefix = "zone.cluster.x-k8s.io"
48+
ZoneAnnotationPrefix = "zone.vmware.infrastructure.cluster.x-k8s.io"
4949
)
5050

5151
// VirtualMachineGroupReconciler reconciles VirtualMachineGroup.
@@ -66,13 +66,13 @@ type VirtualMachineGroupReconciler struct {
6666
// the VirtualMachineGroup (VMG) object with respect to the worker VSphereMachines in the Cluster.
6767
//
6868
// - Batch Coordination: Gating the initial creation of the VMG until all expected worker
69-
// VSphereMachines are present. This ensures the complete VM member list is sent to the VM
70-
// Service in a single batch operation due to a limitation of underlying service.
69+
// VSphereMachines are present. It will compare the desired count of VirtualMachines
70+
// derived from the sum of all desired MachineDeployment Replicas) against the count
71+
// of existing, matching VSphereMachine objects.
7172
//
7273
// - Placement Persistence: Persisting the MachineDeployment-to-Zone mapping (placement decision) as a
73-
// metadata annotation on the VMG object. This decision is crucial for guiding newer VMs created
74-
// during Day-2 operations such as scaling, upgrades, and remediations, ensuring consistency. This is also due to
75-
// a known limitation of underlying services.
74+
// metadata annotation on the VMG object. The same decision must be respected also for placement
75+
// of machines created after initial placement.
7676
//
7777
// - Membership Maintenance: Dynamically updating the VMG's member list to reflect the current
7878
// state of VMs belonging to MachineDeployments (handling scale-up/down events).
@@ -111,49 +111,49 @@ func (r *VirtualMachineGroupReconciler) Reconcile(ctx context.Context, req ctrl.
111111
func (r *VirtualMachineGroupReconciler) createOrUpdateVirtualMachineGroup(ctx context.Context, cluster *clusterv1.Cluster) (reconcile.Result, error) {
112112
log := ctrl.LoggerFrom(ctx)
113113

114-
// Calculate current Machines of all MachineDeployments.
115-
current, err := getCurrentVSphereMachines(ctx, r.Client, cluster.Namespace, cluster.Name)
114+
// Get current VSphereMachines of all MachineDeployments.
115+
currentVSphereMachines, err := getCurrentVSphereMachines(ctx, r.Client, cluster.Namespace, cluster.Name)
116116
if err != nil {
117117
return reconcile.Result{}, errors.Wrapf(err, "failed to get current VSphereMachine of cluster %s/%s",
118118
cluster.Name, cluster.Namespace)
119119
}
120120

121-
desiredVMG := &vmoprv1.VirtualMachineGroup{}
121+
vmg := &vmoprv1.VirtualMachineGroup{}
122122
key := &client.ObjectKey{
123123
Namespace: cluster.Namespace,
124124
Name: cluster.Name,
125125
}
126126

127-
if err := r.Client.Get(ctx, *key, desiredVMG); err != nil {
127+
if err := r.Client.Get(ctx, *key, vmg); err != nil {
128128
if !apierrors.IsNotFound(err) {
129-
log.Error(err, "failed to get VirtualMachineGroup")
129+
log.Error(err, "failed to get VirtualMachineGroup", "namespacedName", *key)
130130
return reconcile.Result{}, err
131131
}
132132

133-
// Calculate expected Machines of all MachineDeployments.
134-
// CAPV retrieves placement decisions from the VirtualMachineGroup to guide
135-
// day-2 VM placement. At least one VM is required for each MachineDeployment.
136-
expected, err := getExpectedVSphereMachineCount(ctx, r.Client, cluster)
133+
// Calculate expected VSphereMachine count of all MachineDeployments.
134+
expectedVSphereMachineCount, err := getExpectedVSphereMachineCount(ctx, r.Client, cluster)
137135
if err != nil {
138-
log.Error(err, "failed to get expected Machines of all MachineDeployment")
136+
log.Error(err, "failed to get expected Machines of all MachineDeployment", "Cluster", klog.KObj(cluster))
139137
return reconcile.Result{}, err
140138
}
141139

142-
if expected == 0 {
140+
// Since CAPV retrieves placement decisions from the VirtualMachineGroup to guide
141+
// day-2 VM placement. At least one VM is required for each MachineDeployment during initial Cluster creation.
142+
if expectedVSphereMachineCount == 0 {
143143
errMsg := fmt.Sprintf("Found 0 desired VSphereMachine for Cluster %s/%s", cluster.Name, cluster.Namespace)
144144
log.Error(nil, errMsg)
145145
return reconcile.Result{}, errors.New(errMsg)
146146
}
147147

148148
// Wait for all intended VSphereMachines corresponding to MachineDeployment to exist only during initial Cluster creation.
149-
current := int32(len(current))
150-
if current < expected {
151-
log.Info("current VSphereMachines do not match expected", "Expected:", expected,
152-
"Current:", current, "ClusterName", cluster.Name, "Namespace", cluster.Namespace)
149+
currentVSphereMachineCount := int32(len(currentVSphereMachines))
150+
if currentVSphereMachineCount < expectedVSphereMachineCount {
151+
log.Info("Waiting for expected VSphereMachines to be created", "Expected:", expectedVSphereMachineCount,
152+
"Current:", currentVSphereMachineCount, "ClusterName", cluster.Name, "Namespace", cluster.Namespace)
153153
return reconcile.Result{RequeueAfter: reconciliationDelay}, nil
154154
}
155155

156-
desiredVMG = &vmoprv1.VirtualMachineGroup{
156+
vmg = &vmoprv1.VirtualMachineGroup{
157157
ObjectMeta: metav1.ObjectMeta{
158158
Name: key.Name,
159159
Namespace: key.Namespace,
@@ -162,8 +162,8 @@ func (r *VirtualMachineGroupReconciler) createOrUpdateVirtualMachineGroup(ctx co
162162
}
163163

164164
// Generate VM names according to the naming strategy set on the VSphereMachine.
165-
vmNames := make([]string, 0, len(current))
166-
for _, machine := range current {
165+
vmNames := make([]string, 0, len(currentVSphereMachines))
166+
for _, machine := range currentVSphereMachines {
167167
name, err := GenerateVirtualMachineName(machine.Name, machine.Spec.NamingStrategy)
168168
if err != nil {
169169
return reconcile.Result{}, err
@@ -175,7 +175,7 @@ func (r *VirtualMachineGroupReconciler) createOrUpdateVirtualMachineGroup(ctx co
175175
return vmNames[i] < vmNames[j]
176176
})
177177

178-
members := make([]vmoprv1.GroupMember, 0, len(current))
178+
members := make([]vmoprv1.GroupMember, 0, len(currentVSphereMachines))
179179
for _, name := range vmNames {
180180
members = append(members, vmoprv1.GroupMember{
181181
Name: name,
@@ -196,50 +196,51 @@ func (r *VirtualMachineGroupReconciler) createOrUpdateVirtualMachineGroup(ctx co
196196
}
197197

198198
// Use CreateOrPatch to create or update the VirtualMachineGroup.
199-
_, err = controllerutil.CreateOrPatch(ctx, r.Client, desiredVMG, func() error {
200-
return r.reconcileVirtualMachineState(ctx, desiredVMG, cluster, members, mdNames)
199+
_, err = controllerutil.CreateOrPatch(ctx, r.Client, vmg, func() error {
200+
return r.reconcileVirtualMachineState(ctx, vmg, cluster, members, mdNames)
201201
})
202202

203203
return reconcile.Result{}, err
204204
}
205205

206-
// reconcileVirtualMachineState mutates the desiredVMG object to reflect the necessary spec and metadata changes.
207-
func (r *VirtualMachineGroupReconciler) reconcileVirtualMachineState(ctx context.Context, desiredVMG *vmoprv1.VirtualMachineGroup, cluster *clusterv1.Cluster, members []vmoprv1.GroupMember, mdNames []string) error {
206+
// reconcileVirtualMachineState mutates the VirtualMachineGroup object to reflect the necessary spec and metadata changes.
207+
func (r *VirtualMachineGroupReconciler) reconcileVirtualMachineState(ctx context.Context, vmg *vmoprv1.VirtualMachineGroup, cluster *clusterv1.Cluster, members []vmoprv1.GroupMember, mdNames []string) error {
208208
// Set the desired labels
209-
if desiredVMG.Labels == nil {
210-
desiredVMG.Labels = make(map[string]string)
211-
desiredVMG.Labels[clusterv1.ClusterNameLabel] = cluster.Name
209+
if vmg.Labels == nil {
210+
vmg.Labels = make(map[string]string)
212211
}
212+
// Always ensure cluster name label is set
213+
vmg.Labels[clusterv1.ClusterNameLabel] = cluster.Name
213214

214-
if desiredVMG.Annotations == nil {
215-
desiredVMG.Annotations = make(map[string]string)
215+
if vmg.Annotations == nil {
216+
vmg.Annotations = make(map[string]string)
216217
}
217218

218219
// Add per-md-zone label for day-2 operations once placement of a VM belongs to MachineDeployment is done.
219220
// Do not update per-md-zone label once set, as placement decision should not change without user explicitly
220221
// set failureDomain.
221-
placementAnnotations, err := GenerateVirtualMachineGroupAnnotations(ctx, r.Client, desiredVMG, mdNames)
222+
placementAnnotations, err := GenerateVirtualMachineGroupAnnotations(ctx, r.Client, vmg, mdNames)
222223
if err != nil {
223224
return err
224225
}
225226
if len(placementAnnotations) > 0 {
226227
for k, v := range placementAnnotations {
227-
if _, exists := desiredVMG.Annotations[k]; !exists {
228-
desiredVMG.Annotations[k] = v
228+
if _, exists := vmg.Annotations[k]; !exists {
229+
vmg.Annotations[k] = v
229230
}
230231
}
231232
}
232233

233234
// Set the BootOrder spec as the
234-
desiredVMG.Spec.BootOrder = []vmoprv1.VirtualMachineGroupBootOrderGroup{
235+
vmg.Spec.BootOrder = []vmoprv1.VirtualMachineGroupBootOrderGroup{
235236
{
236237
Members: members,
237238
},
238239
}
239240

240241
// Set the owner reference
241-
if err := controllerutil.SetControllerReference(cluster, desiredVMG, r.Client.Scheme()); err != nil {
242-
return errors.Wrapf(err, "failed to mark %s as owner of %s", klog.KObj(cluster), klog.KObj(desiredVMG))
242+
if err := controllerutil.SetControllerReference(cluster, vmg, r.Client.Scheme()); err != nil {
243+
return errors.Wrapf(err, "failed to mark %s as owner of %s", klog.KObj(cluster), klog.KObj(vmg))
243244
}
244245

245246
return nil
@@ -279,7 +280,7 @@ func getCurrentVSphereMachines(ctx context.Context, kubeClient client.Client, cl
279280
client.MatchingLabels{clusterv1.ClusterNameLabel: clusterName},
280281
client.HasLabels{clusterv1.MachineDeploymentNameLabel},
281282
); err != nil {
282-
return nil, errors.Wrapf(err, "failed to list VSphereMachines in namespace %s", clusterNamespace)
283+
return nil, errors.Wrapf(err, "failed to list VSphereMachines")
283284
}
284285

285286
var result []vmwarev1.VSphereMachine
@@ -352,7 +353,7 @@ func GenerateVirtualMachineGroupAnnotations(ctx context.Context, kubeClient clie
352353
}
353354

354355
// Check if this VM belongs to any of our target MachineDeployments.
355-
// Annotation format is "zone.cluster.x-k8s.io/{machine-deployment-name}".
356+
// Annotation format is "zone.vmware.infrastructure.cluster.x-k8s.io/{machine-deployment-name}".
356357
for _, md := range machineDeployments {
357358
if mdNameFromLabel != md {
358359
continue

0 commit comments

Comments
 (0)