Skip to content

Commit e0797e8

Browse files
committed
Initial impl for VSphereMachine AAF changes
Signed-off-by: Sagar Muchhal <[email protected]>
1 parent ac3ea96 commit e0797e8

File tree

2 files changed

+147
-10
lines changed

2 files changed

+147
-10
lines changed

pkg/services/vmoperator/constants.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package vmoperator
1919

2020
const (
2121
kubeTopologyZoneLabelKey = "topology.kubernetes.io/zone"
22+
kubeHostNameLabelKey = "kubernetes.io/hostname"
2223

2324
// ControlPlaneVMClusterModuleGroupName is the name used for the control plane Cluster Module.
2425
ControlPlaneVMClusterModuleGroupName = "control-plane-group"

pkg/services/vmoperator/vmopmachine.go

Lines changed: 146 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import (
4141

4242
infrav1 "sigs.k8s.io/cluster-api-provider-vsphere/apis/v1beta1"
4343
vmwarev1 "sigs.k8s.io/cluster-api-provider-vsphere/apis/vmware/v1beta1"
44+
"sigs.k8s.io/cluster-api-provider-vsphere/feature"
4445
capvcontext "sigs.k8s.io/cluster-api-provider-vsphere/pkg/context"
4546
"sigs.k8s.io/cluster-api-provider-vsphere/pkg/context/vmware"
4647
infrautilv1 "sigs.k8s.io/cluster-api-provider-vsphere/pkg/util"
@@ -163,6 +164,15 @@ func (v *VmopMachineService) SyncFailureReason(_ context.Context, machineCtx cap
163164
return supervisorMachineCtx.VSphereMachine.Status.FailureReason != nil || supervisorMachineCtx.VSphereMachine.Status.FailureMessage != nil, nil
164165
}
165166

167+
type affinityInfo struct {
168+
vmAffinitySpec *vmoprv1.VirtualMachineAffinitySpec
169+
vmGroupName string
170+
failureDomain *string
171+
172+
// TODO: is this needed for the single zone case?
173+
// zones []topologyv1.Zone
174+
}
175+
166176
// ReconcileNormal reconciles create and update events for VM Operator VMs.
167177
func (v *VmopMachineService) ReconcileNormal(ctx context.Context, machineCtx capvcontext.MachineContext) (bool, error) {
168178
log := ctrl.LoggerFrom(ctx)
@@ -171,10 +181,6 @@ func (v *VmopMachineService) ReconcileNormal(ctx context.Context, machineCtx cap
171181
return false, errors.New("received unexpected SupervisorMachineContext type")
172182
}
173183

174-
if supervisorMachineCtx.Machine.Spec.FailureDomain != "" {
175-
supervisorMachineCtx.VSphereMachine.Spec.FailureDomain = ptr.To(supervisorMachineCtx.Machine.Spec.FailureDomain)
176-
}
177-
178184
// If debug logging is enabled, report the number of vms in the cluster before and after the reconcile
179185
if log.V(5).Enabled() {
180186
vms, err := v.getVirtualMachinesInCluster(ctx, supervisorMachineCtx)
@@ -188,6 +194,101 @@ func (v *VmopMachineService) ReconcileNormal(ctx context.Context, machineCtx cap
188194
// Set the VM state. Will get reset throughout the reconcile
189195
supervisorMachineCtx.VSphereMachine.Status.VMStatus = vmwarev1.VirtualMachineStatePending
190196

197+
// var vmAffinitySpec *vmoprv1.VirtualMachineAffinitySpec
198+
var affInfo affinityInfo
199+
if feature.Gates.Enabled(feature.NodeAutoPlacement) &&
200+
!infrautilv1.IsControlPlaneMachine(machineCtx.GetVSphereMachine()) {
201+
// Check for the presence of a VirtualMachineGroup with the name and namespace same as the name of the Cluster
202+
vmOperatorVMGroup := &vmoprv1.VirtualMachineGroup{}
203+
key := client.ObjectKey{
204+
Namespace: supervisorMachineCtx.Cluster.Namespace,
205+
Name: supervisorMachineCtx.Cluster.Name,
206+
}
207+
err := v.Client.Get(ctx, key, vmOperatorVMGroup)
208+
if err != nil {
209+
if !apierrors.IsNotFound(err) {
210+
return false, err
211+
}
212+
if apierrors.IsNotFound(err) {
213+
log.V(4).Info("VirtualMachineGroup not found, requeueing")
214+
return true, nil
215+
}
216+
}
217+
218+
// Check if the current machine is a member of the boot order
219+
// in the VirtualMachineGroup.
220+
if !v.checkVirtualMachineGroupMembership(vmOperatorVMGroup, supervisorMachineCtx) {
221+
log.V(4).Info("Waiting for VirtualMachineGroup membership, requeueing")
222+
return true, nil
223+
}
224+
225+
// Initialize the affinityInfo for the VM
226+
affInfo = affinityInfo{
227+
vmGroupName: vmOperatorVMGroup.Name,
228+
}
229+
230+
// Check the presence of the node-pool label on the VirtualMachineGroup object
231+
nodePool := supervisorMachineCtx.Machine.Labels[clusterv1.MachineDeploymentNameLabel]
232+
if zone, ok := vmOperatorVMGroup.Labels[fmt.Sprintf("zone.cluster.x-k8s.io/%s", nodePool)]; ok && zone != "" {
233+
affInfo.failureDomain = ptr.To(zone)
234+
}
235+
236+
affInfo.vmAffinitySpec = &vmoprv1.VirtualMachineAffinitySpec{
237+
VMAffinity: &vmoprv1.VirtualMachineAffinityVMAffinitySpec{
238+
RequiredDuringSchedulingIgnoredDuringExecution: []vmoprv1.VMAffinityTerm{
239+
{
240+
LabelSelector: &metav1.LabelSelector{
241+
MatchLabels: map[string]string{
242+
clusterv1.MachineDeploymentNameLabel: nodePool,
243+
},
244+
},
245+
TopologyKey: kubeTopologyZoneLabelKey,
246+
},
247+
},
248+
},
249+
VMAntiAffinity: &vmoprv1.VirtualMachineAntiAffinityVMAffinitySpec{
250+
PreferredDuringSchedulingPreferredDuringExecution: []vmoprv1.VMAffinityTerm{
251+
{
252+
LabelSelector: &metav1.LabelSelector{
253+
MatchLabels: map[string]string{
254+
clusterv1.MachineDeploymentNameLabel: nodePool,
255+
},
256+
MatchExpressions: []metav1.LabelSelectorRequirement{
257+
{
258+
Key: clusterv1.MachineControlPlaneLabel,
259+
Operator: metav1.LabelSelectorOpDoesNotExist,
260+
},
261+
},
262+
},
263+
TopologyKey: kubeHostNameLabelKey,
264+
},
265+
},
266+
PreferredDuringSchedulingIgnoredDuringExecution: []vmoprv1.VMAffinityTerm{
267+
{
268+
LabelSelector: &metav1.LabelSelector{
269+
MatchExpressions: []metav1.LabelSelectorRequirement{
270+
{
271+
Key: clusterv1.MachineDeploymentNameLabel,
272+
Operator: metav1.LabelSelectorOpNotIn,
273+
Values: []string{nodePool},
274+
},
275+
{
276+
Key: clusterv1.MachineControlPlaneLabel,
277+
Operator: metav1.LabelSelectorOpDoesNotExist,
278+
},
279+
},
280+
},
281+
TopologyKey: kubeTopologyZoneLabelKey,
282+
},
283+
},
284+
},
285+
}
286+
}
287+
288+
if supervisorMachineCtx.Machine.Spec.FailureDomain != "" {
289+
supervisorMachineCtx.VSphereMachine.Spec.FailureDomain = ptr.To(supervisorMachineCtx.Machine.Spec.FailureDomain)
290+
}
291+
191292
// Check for the presence of an existing object
192293
vmOperatorVM := &vmoprv1.VirtualMachine{}
193294
key, err := virtualMachineObjectKey(supervisorMachineCtx.Machine.Name, supervisorMachineCtx.Machine.Namespace, supervisorMachineCtx.VSphereMachine.Spec.NamingStrategy)
@@ -208,7 +309,7 @@ func (v *VmopMachineService) ReconcileNormal(ctx context.Context, machineCtx cap
208309
}
209310

210311
// Reconcile the VM Operator VirtualMachine.
211-
if err := v.reconcileVMOperatorVM(ctx, supervisorMachineCtx, vmOperatorVM); err != nil {
312+
if err := v.reconcileVMOperatorVM(ctx, supervisorMachineCtx, vmOperatorVM, &affInfo); err != nil {
212313
v1beta1conditions.MarkFalse(supervisorMachineCtx.VSphereMachine, infrav1.VMProvisionedCondition, vmwarev1.VMCreationFailedReason, clusterv1beta1.ConditionSeverityWarning,
213314
"failed to create or update VirtualMachine: %v", err)
214315
v1beta2conditions.Set(supervisorMachineCtx.VSphereMachine, metav1.Condition{
@@ -378,7 +479,7 @@ func (v *VmopMachineService) GetHostInfo(ctx context.Context, machineCtx capvcon
378479
return vmOperatorVM.Status.Host, nil
379480
}
380481

381-
func (v *VmopMachineService) reconcileVMOperatorVM(ctx context.Context, supervisorMachineCtx *vmware.SupervisorMachineContext, vmOperatorVM *vmoprv1.VirtualMachine) error {
482+
func (v *VmopMachineService) reconcileVMOperatorVM(ctx context.Context, supervisorMachineCtx *vmware.SupervisorMachineContext, vmOperatorVM *vmoprv1.VirtualMachine, affinityInfo *affinityInfo) error {
382483
// All Machine resources should define the version of Kubernetes to use.
383484
if supervisorMachineCtx.Machine.Spec.Version == "" {
384485
return errors.Errorf(
@@ -472,7 +573,7 @@ func (v *VmopMachineService) reconcileVMOperatorVM(ctx context.Context, supervis
472573
}
473574

474575
// Assign the VM's labels.
475-
vmOperatorVM.Labels = getVMLabels(supervisorMachineCtx, vmOperatorVM.Labels)
576+
vmOperatorVM.Labels = getVMLabels(supervisorMachineCtx, vmOperatorVM.Labels, affinityInfo)
476577

477578
addResourcePolicyAnnotations(supervisorMachineCtx, vmOperatorVM)
478579

@@ -494,6 +595,15 @@ func (v *VmopMachineService) reconcileVMOperatorVM(ctx context.Context, supervis
494595
vmOperatorVM = typedModified
495596
}
496597

598+
if affinityInfo != nil && affinityInfo.vmAffinitySpec != nil {
599+
if vmOperatorVM.Spec.Affinity == nil {
600+
vmOperatorVM.Spec.Affinity = affinityInfo.vmAffinitySpec
601+
}
602+
if vmOperatorVM.Spec.GroupName == "" {
603+
vmOperatorVM.Spec.GroupName = affinityInfo.vmGroupName
604+
}
605+
}
606+
497607
// Make sure the VSphereMachine owns the VM Operator VirtualMachine.
498608
if err := ctrlutil.SetControllerReference(supervisorMachineCtx.VSphereMachine, vmOperatorVM, v.Client.Scheme()); err != nil {
499609
return errors.Wrapf(err, "failed to mark %s %s/%s as owner of %s %s/%s",
@@ -777,7 +887,7 @@ func (v *VmopMachineService) addVolumes(ctx context.Context, supervisorMachineCt
777887
}
778888

779889
// getVMLabels returns the labels applied to a VirtualMachine.
780-
func getVMLabels(supervisorMachineCtx *vmware.SupervisorMachineContext, vmLabels map[string]string) map[string]string {
890+
func getVMLabels(supervisorMachineCtx *vmware.SupervisorMachineContext, vmLabels map[string]string, affinityInfo *affinityInfo) map[string]string {
781891
if vmLabels == nil {
782892
vmLabels = map[string]string{}
783893
}
@@ -791,7 +901,11 @@ func getVMLabels(supervisorMachineCtx *vmware.SupervisorMachineContext, vmLabels
791901

792902
// Get the labels that determine the VM's placement inside of a stretched
793903
// cluster.
794-
topologyLabels := getTopologyLabels(supervisorMachineCtx)
904+
var failureDomain *string
905+
if affinityInfo != nil && affinityInfo.failureDomain != nil {
906+
failureDomain = affinityInfo.failureDomain
907+
}
908+
topologyLabels := getTopologyLabels(supervisorMachineCtx, failureDomain)
795909
for k, v := range topologyLabels {
796910
vmLabels[k] = v
797911
}
@@ -800,6 +914,9 @@ func getVMLabels(supervisorMachineCtx *vmware.SupervisorMachineContext, vmLabels
800914
// resources associated with the target cluster.
801915
vmLabels[clusterv1.ClusterNameLabel] = supervisorMachineCtx.GetClusterContext().Cluster.Name
802916

917+
// Ensure the VM has the machine deployment name label
918+
vmLabels[clusterv1.MachineDeploymentNameLabel] = supervisorMachineCtx.Machine.Labels[clusterv1.MachineDeploymentNameLabel]
919+
803920
return vmLabels
804921
}
805922

@@ -809,12 +926,18 @@ func getVMLabels(supervisorMachineCtx *vmware.SupervisorMachineContext, vmLabels
809926
//
810927
// and thus the code is optimized as such. However, in the future
811928
// this function may return a more diverse topology.
812-
func getTopologyLabels(supervisorMachineCtx *vmware.SupervisorMachineContext) map[string]string {
929+
func getTopologyLabels(supervisorMachineCtx *vmware.SupervisorMachineContext, failureDomain *string) map[string]string {
930+
// TODO: Make it so that we always set the zone label, might require enquiring the zones present (when unset)
813931
if fd := supervisorMachineCtx.VSphereMachine.Spec.FailureDomain; fd != nil && *fd != "" {
814932
return map[string]string{
815933
kubeTopologyZoneLabelKey: *fd,
816934
}
817935
}
936+
if failureDomain != nil && *failureDomain != "" {
937+
return map[string]string{
938+
kubeTopologyZoneLabelKey: *failureDomain,
939+
}
940+
}
818941
return nil
819942
}
820943

@@ -823,3 +946,16 @@ func getTopologyLabels(supervisorMachineCtx *vmware.SupervisorMachineContext) ma
823946
func getMachineDeploymentNameForCluster(cluster *clusterv1.Cluster) string {
824947
return fmt.Sprintf("%s-workers-0", cluster.Name)
825948
}
949+
950+
// checkVirtualMachineGroupMembership checks if the machine is in the first boot order group
951+
// and performs logic if a match is found.
952+
func (v *VmopMachineService) checkVirtualMachineGroupMembership(vmOperatorVMGroup *vmoprv1.VirtualMachineGroup, supervisorMachineCtx *vmware.SupervisorMachineContext) bool {
953+
if len(vmOperatorVMGroup.Spec.BootOrder) > 0 {
954+
for _, member := range vmOperatorVMGroup.Spec.BootOrder[0].Members {
955+
if member.Name == supervisorMachineCtx.Machine.Name {
956+
return true
957+
}
958+
}
959+
}
960+
return false
961+
}

0 commit comments

Comments
 (0)