@@ -19,6 +19,7 @@ package vmoperator
1919import (
2020 "context"
2121 "fmt"
22+ "slices"
2223 "testing"
2324 "time"
2425
@@ -68,8 +69,7 @@ func updateReconciledVMStatus(ctx context.Context, vmService VmopMachineService,
6869 Expect (err ).ShouldNot (HaveOccurred ())
6970}
7071
71- // verifyVMAffinityRules is a helper method to assert the VM affinity rules.
72- func verifyVMAffinityRules (vmopVM * vmoprv1.VirtualMachine , machineDeploymentName , clusterName string ) {
72+ func verifyVMAffinityRules (vmopVM * vmoprv1.VirtualMachine , machineDeploymentName string ) {
7373 Expect (vmopVM .Spec .Affinity .VMAffinity ).ShouldNot (BeNil ())
7474 Expect (vmopVM .Spec .Affinity .VMAffinity .RequiredDuringSchedulingPreferredDuringExecution ).To (HaveLen (1 ))
7575
@@ -78,21 +78,38 @@ func verifyVMAffinityRules(vmopVM *vmoprv1.VirtualMachine, machineDeploymentName
7878 Expect (vmAffinityTerm .TopologyKey ).To (Equal (corev1 .LabelTopologyZone ))
7979}
8080
81- // verifyVMAntiAffinityRules is a helper method to assert the VM anti-affinity rules.
82- func verifyVMAntiAffinityRules (vmopVM * vmoprv1.VirtualMachine , machineDeploymentName , clusterName string ) {
81+ func verifyVMAntiAffinityRules (vmopVM * vmoprv1.VirtualMachine , machineDeploymentName string , extraMDs ... string ) {
8382 Expect (vmopVM .Spec .Affinity .VMAntiAffinity ).ShouldNot (BeNil ())
84- Expect (vmopVM .Spec .Affinity .VMAntiAffinity .PreferredDuringSchedulingPreferredDuringExecution ).To (HaveLen (2 ))
8583
86- // First anti-affinity term - same machine deployment, different hosts
87- antiAffinityTerm1 := vmopVM .Spec .Affinity .VMAntiAffinity .PreferredDuringSchedulingPreferredDuringExecution [0 ]
84+ expectedNumAntiAffinityTerms := 1
85+ if len (extraMDs ) > 0 {
86+ expectedNumAntiAffinityTerms = 2
87+ }
88+
89+ antiAffinityTerms := vmopVM .Spec .Affinity .VMAntiAffinity .PreferredDuringSchedulingPreferredDuringExecution
90+ Expect (antiAffinityTerms ).To (HaveLen (expectedNumAntiAffinityTerms ))
91+
92+ // First anti-affinity constraint - same machine deployment, different hosts
93+ antiAffinityTerm1 := antiAffinityTerms [0 ]
8894 Expect (antiAffinityTerm1 .LabelSelector .MatchLabels ).To (HaveKeyWithValue (clusterv1 .MachineDeploymentNameLabel , machineDeploymentName ))
8995 Expect (antiAffinityTerm1 .TopologyKey ).To (Equal (corev1 .LabelHostname ))
9096
9197 // Second anti-affinity term - different machine deployments
92- antiAffinityTerm2 := vmopVM .Spec .Affinity .VMAntiAffinity .PreferredDuringSchedulingPreferredDuringExecution [1 ]
93- Expect (antiAffinityTerm2 .LabelSelector .MatchExpressions ).To (HaveLen (1 ))
94- Expect (antiAffinityTerm2 .LabelSelector .MatchExpressions [0 ].Key ).To (Equal (clusterv1 .MachineDeploymentNameLabel ))
95- Expect (antiAffinityTerm2 .LabelSelector .MatchExpressions [0 ].Operator ).To (Equal (metav1 .LabelSelectorOpIn ))
98+ if len (extraMDs ) > 0 {
99+ isSortedAlphabetically := func (actual []string ) (bool , error ) {
100+ return slices .IsSorted (actual ), nil
101+ }
102+ antiAffinityTerm2 := antiAffinityTerms [1 ]
103+ Expect (antiAffinityTerm2 .LabelSelector .MatchExpressions ).To (HaveLen (1 ))
104+ Expect (antiAffinityTerm2 .LabelSelector .MatchExpressions [0 ].Key ).To (Equal (clusterv1 .MachineDeploymentNameLabel ))
105+ Expect (antiAffinityTerm2 .LabelSelector .MatchExpressions [0 ].Operator ).To (Equal (metav1 .LabelSelectorOpIn ))
106+
107+ Expect (antiAffinityTerm2 .LabelSelector .MatchExpressions [0 ].Values ).To (HaveLen (len (extraMDs )))
108+ Expect (antiAffinityTerm2 .LabelSelector .MatchExpressions [0 ].Values ).To (
109+ WithTransform (isSortedAlphabetically , BeTrue ()),
110+ "Expected extra machine deployments to be sorted alphabetically" ,
111+ )
112+ }
96113}
97114
98115const (
@@ -111,6 +128,32 @@ const (
111128 clusterNameLabel = clusterv1 .ClusterNameLabel
112129)
113130
131+ func createMachineDeployment (name , namespace , clusterName , failureDomain string ) * clusterv1.MachineDeployment {
132+ md := & clusterv1.MachineDeployment {
133+ ObjectMeta : metav1.ObjectMeta {
134+ Name : name ,
135+ Namespace : namespace ,
136+ Labels : map [string ]string {
137+ clusterv1 .ClusterNameLabel : clusterName ,
138+ },
139+ },
140+ Spec : clusterv1.MachineDeploymentSpec {
141+ Template : clusterv1.MachineTemplateSpec {
142+ Spec : clusterv1.MachineSpec {
143+ // FailureDomain will be set conditionally below
144+ },
145+ },
146+ },
147+ }
148+
149+ // Only set failure domain if it's provided and not empty
150+ if failureDomain != "" {
151+ md .Spec .Template .Spec .FailureDomain = failureDomain
152+ }
153+
154+ return md
155+ }
156+
114157var _ = Describe ("VirtualMachine tests" , func () {
115158
116159 var (
@@ -779,22 +822,7 @@ var _ = Describe("VirtualMachine tests", func() {
779822 Expect (vmService .Client .Create (ctx , vmGroup )).To (Succeed ())
780823
781824 // Create a MachineDeployment for the worker
782- machineDeployment := & clusterv1.MachineDeployment {
783- ObjectMeta : metav1.ObjectMeta {
784- Name : machineDeploymentName ,
785- Namespace : corev1 .NamespaceDefault ,
786- Labels : map [string ]string {
787- clusterv1 .ClusterNameLabel : clusterName ,
788- },
789- },
790- Spec : clusterv1.MachineDeploymentSpec {
791- Template : clusterv1.MachineTemplateSpec {
792- Spec : clusterv1.MachineSpec {
793- // No failure domain set
794- },
795- },
796- },
797- }
825+ machineDeployment := createMachineDeployment (machineDeploymentName , corev1 .NamespaceDefault , clusterName , "" )
798826 Expect (vmService .Client .Create (ctx , machineDeployment )).To (Succeed ())
799827 })
800828
@@ -831,10 +859,10 @@ var _ = Describe("VirtualMachine tests", func() {
831859 Expect (vmopVM .Spec .Affinity ).ShouldNot (BeNil ())
832860
833861 By ("Verify VM affinity rules are set correctly" )
834- verifyVMAffinityRules (vmopVM , machineDeploymentName , clusterName )
862+ verifyVMAffinityRules (vmopVM , machineDeploymentName )
835863
836864 By ("Verify VM anti-affinity rules are set correctly" )
837- verifyVMAntiAffinityRules (vmopVM , machineDeploymentName , clusterName )
865+ verifyVMAntiAffinityRules (vmopVM , machineDeploymentName )
838866
839867 By ("Verify that worker machine has machine deploymet label set" )
840868 Expect (vmopVM .Labels [clusterv1 .MachineDeploymentNameLabel ]).To (Equal (machineDeploymentName ))
@@ -895,22 +923,7 @@ var _ = Describe("VirtualMachine tests", func() {
895923 Expect (vmService .Client .Create (ctx , vmGroup )).To (Succeed ())
896924
897925 // Create a MachineDeployment for the worker with no explicit failure domain
898- machineDeployment := & clusterv1.MachineDeployment {
899- ObjectMeta : metav1.ObjectMeta {
900- Name : machineDeploymentName ,
901- Namespace : corev1 .NamespaceDefault ,
902- Labels : map [string ]string {
903- clusterv1 .ClusterNameLabel : fdClusterName ,
904- },
905- },
906- Spec : clusterv1.MachineDeploymentSpec {
907- Template : clusterv1.MachineTemplateSpec {
908- Spec : clusterv1.MachineSpec {
909- // No failure domain set on template
910- },
911- },
912- },
913- }
926+ machineDeployment := createMachineDeployment (machineDeploymentName , corev1 .NamespaceDefault , fdClusterName , "" )
914927 Expect (vmService .Client .Create (ctx , machineDeployment )).To (Succeed ())
915928
916929 // Provide valid bootstrap data
@@ -940,10 +953,10 @@ var _ = Describe("VirtualMachine tests", func() {
940953 Expect (vmopVM .Spec .Affinity ).ShouldNot (BeNil ())
941954
942955 By ("Verify VM affinity rules are set correctly" )
943- verifyVMAffinityRules (vmopVM , machineDeploymentName , fdClusterName )
956+ verifyVMAffinityRules (vmopVM , machineDeploymentName )
944957
945958 By ("Verify VM anti-affinity rules are set correctly" )
946- verifyVMAntiAffinityRules (vmopVM , machineDeploymentName , fdClusterName )
959+ verifyVMAntiAffinityRules (vmopVM , machineDeploymentName )
947960
948961 By ("Verify that worker machine has correct labels including topology" )
949962 Expect (vmopVM .Labels [clusterv1 .MachineDeploymentNameLabel ]).To (Equal (machineDeploymentName ))
@@ -952,6 +965,64 @@ var _ = Describe("VirtualMachine tests", func() {
952965 By ("Verify that GroupName is set from VirtualMachineGroup" )
953966 Expect (vmopVM .Spec .GroupName ).To (Equal (fdClusterName ))
954967 })
968+
969+ Context ("For multiple machine deployments" , func () {
970+ const (
971+ otherMdName1 = "other-md-1"
972+ otherMdName2 = "other-md-2"
973+ )
974+
975+ BeforeEach (func () {
976+ otherMd1 := createMachineDeployment (otherMdName1 , corev1 .NamespaceDefault , clusterName , "" )
977+ Expect (vmService .Client .Create (ctx , otherMd1 )).To (Succeed ())
978+
979+ otherMd2 := createMachineDeployment (otherMdName2 , corev1 .NamespaceDefault , clusterName , "" )
980+ Expect (vmService .Client .Create (ctx , otherMd2 )).To (Succeed ())
981+
982+ // Create a MachineDeployment with failure domain
983+ otherMdWithFd := createMachineDeployment ("other-md-with-fd" , corev1 .NamespaceDefault , clusterName , "zone-1" )
984+ Expect (vmService .Client .Create (ctx , otherMdWithFd )).To (Succeed ())
985+ })
986+
987+ Specify ("Reconcile valid machine with additional anti-affinity term added" , func () {
988+ expectReconcileError = false
989+ expectVMOpVM = true
990+ expectedImageName = imageName
991+ expectedRequeue = true
992+
993+ // Provide valid bootstrap data
994+ By ("bootstrap data is created" )
995+ secretName := machine .GetName () + "-data"
996+ secret := & corev1.Secret {
997+ ObjectMeta : metav1.ObjectMeta {
998+ Name : secretName ,
999+ Namespace : machine .GetNamespace (),
1000+ },
1001+ Data : map [string ][]byte {
1002+ "value" : []byte (bootstrapData ),
1003+ },
1004+ }
1005+ Expect (vmService .Client .Create (ctx , secret )).To (Succeed ())
1006+
1007+ machine .Spec .Bootstrap .DataSecretName = & secretName
1008+
1009+ By ("VirtualMachine is created" )
1010+ requeue , err = vmService .ReconcileNormal (ctx , supervisorMachineContext )
1011+ Expect (err ).ShouldNot (HaveOccurred ())
1012+ Expect (requeue ).Should (BeTrue ())
1013+
1014+ By ("Verify that worker machine has affinity spec set" )
1015+ vmopVM = getReconciledVM (ctx , vmService , supervisorMachineContext )
1016+ Expect (vmopVM ).ShouldNot (BeNil ())
1017+ Expect (vmopVM .Spec .Affinity ).ShouldNot (BeNil ())
1018+
1019+ By ("Verify VM affinity rules are set correctly" )
1020+ verifyVMAffinityRules (vmopVM , machineDeploymentName )
1021+
1022+ By ("Verify VM anti-affinity rules are set correctly" )
1023+ verifyVMAntiAffinityRules (vmopVM , machineDeploymentName , otherMdName1 , otherMdName2 )
1024+ })
1025+ })
9551026 })
9561027
9571028 })
0 commit comments