Skip to content

Commit b745c58

Browse files
committed
MULTIARCH-5369: adding tests for updated labels
1 parent 12c5914 commit b745c58

File tree

5 files changed

+325
-5
lines changed

5 files changed

+325
-5
lines changed

controllers/podplacement/pod_model_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,7 @@ func TestPod_SetPreferredArchNodeAffinityWithCPPC(t *testing.T) {
549549
WithName(common.SingletonResourceObjectName).
550550
WithNodeAffinityScoring(true).
551551
WithNodeAffinityScoringTerm(utils.ArchitectureAmd64, 1).Build()
552-
pod.SetPreferredArchNodeAffinity(cppc.Spec.Plugins.NodeAffinityScoring)
552+
pod.SetPreferredArchNodeAffinity(cppc.Spec.Plugins.NodeAffinityScoring, v1beta1.ClusterPodPlacementConfigKind)
553553
g.Expect(pod.Spec.Affinity).Should(Equal(tt.want.Spec.Affinity))
554554
imageInspectionCache = mmoimage.FacadeSingleton()
555555
})
@@ -599,13 +599,13 @@ func TestPod_SetPreferredArchNodeAffinityPPC(t *testing.T) {
599599
WithNodeAffinityScoring(true).
600600
WithPriority(10).
601601
WithNodeAffinityScoringTerm(utils.ArchitectureAmd64, 1).Build()
602-
pod.SetPreferredArchNodeAffinity(ppc.Spec.Plugins.NodeAffinityScoring)
602+
pod.SetPreferredArchNodeAffinity(ppc.Spec.Plugins.NodeAffinityScoring, "PodPlacementConfig/test-high-priority")
603603
ppc = NewPodPlacementConfig().
604604
WithName("test-low-priority").
605605
WithNodeAffinityScoring(true).
606606
WithPriority(5).
607607
WithNodeAffinityScoringTerm(utils.ArchitectureAmd64, 5).Build()
608-
pod.SetPreferredArchNodeAffinity(ppc.Spec.Plugins.NodeAffinityScoring)
608+
pod.SetPreferredArchNodeAffinity(ppc.Spec.Plugins.NodeAffinityScoring, "PodPlacementConfig/test-low-priority")
609609
g.Expect(pod.Spec.Affinity).Should(Equal(tt.want.Spec.Affinity))
610610
imageInspectionCache = mmoimage.FacadeSingleton()
611611
})
@@ -644,7 +644,7 @@ func TestPod_SetPreferredArchNodeAffinity(t *testing.T) {
644644
},
645645
},
646646
}
647-
pod.SetPreferredArchNodeAffinity(cppc.Spec.Plugins.NodeAffinityScoring)
647+
pod.SetPreferredArchNodeAffinity(cppc.Spec.Plugins.NodeAffinityScoring, v1beta1.ClusterPodPlacementConfigKind)
648648
g.Expect(pod.Spec.Affinity).Should(Equal(tt.want.Spec.Affinity))
649649
imageInspectionCache = mmoimage.FacadeSingleton()
650650
})

controllers/podplacement/pod_reconciler_test.go

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
. "github.com/onsi/gomega"
1414

1515
corev1 "k8s.io/api/core/v1"
16+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1617
crclient "sigs.k8s.io/controller-runtime/pkg/client"
1718

1819
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
@@ -865,6 +866,209 @@ var _ = Describe("Controllers/Podplacement/PodReconciler", func() {
865866
}).Should(Succeed(), "failed to set preferred node affinity in pod")
866867

867868
})
869+
It("should set source label tracking for PPC preferences", func() {
870+
By("Create an ephemeral namespace")
871+
ns := NewEphemeralNamespace()
872+
err := k8sClient.Create(ctx, ns)
873+
Expect(err).NotTo(HaveOccurred())
874+
//nolint:errcheck
875+
defer k8sClient.Delete(ctx, ns)
876+
By("Creating a PodPlacementConfig")
877+
ppc1 := NewPodPlacementConfig().
878+
WithName("test-ppc-source").
879+
WithNamespace(ns.Name).
880+
WithPriority(100).
881+
WithNodeAffinityScoring(true).
882+
WithNodeAffinityScoringTerm(utils.ArchitecturePpc64le, 50).
883+
Build()
884+
Expect(k8sClient.Create(ctx, ppc1)).To(Succeed())
885+
By("Creating a matching pod")
886+
pod := NewPod().
887+
WithContainersImages(fmt.Sprintf("%s/%s/%s:latest", registryAddress,
888+
registry.PublicRepo, registry.ComputeNameByMediaType(imgspecv1.MediaTypeImageManifest))).
889+
WithGenerateName("test-pod-").
890+
WithNamespace(ns.Name).
891+
Build()
892+
Expect(k8sClient.Create(ctx, pod)).To(Succeed())
893+
By("Waiting for the pod to be reconciled")
894+
Eventually(func(g Gomega) {
895+
err := k8sClient.Get(ctx, crclient.ObjectKeyFromObject(pod), pod)
896+
g.Expect(err).NotTo(HaveOccurred())
897+
g.Expect(pod.Spec.SchedulingGates).NotTo(ContainElement(corev1.PodSchedulingGate{
898+
Name: utils.SchedulingGateName,
899+
}), "scheduling gate not removed")
900+
}).Should(Succeed())
901+
By("Verifying the source label is correctly set")
902+
Eventually(func(g Gomega) {
903+
// Get pod from the API server
904+
err := k8sClient.Get(ctx, crclient.ObjectKeyFromObject(pod), pod)
905+
g.Expect(err).NotTo(HaveOccurred(), "failed to get pod", err)
906+
g.Expect(pod.Labels).To(HaveKeyWithValue(utils.PreferredNodeAffinityLabel, utils.NodeAffinityLabelValueSet),
907+
"preferred node affinity label not found")
908+
g.Expect(pod.Labels).To(HaveKeyWithValue(utils.PreferredNodeAffinitySourceLabel, "PodPlacementConfig/test-ppc-source"),
909+
"source label should indicate PPC")
910+
}).Should(Succeed(), "failed to set source label")
911+
})
912+
It("should set all-duplicates label when lower-priority PPC is blocked", func() {
913+
By("Create an ephemeral namespace")
914+
ns := NewEphemeralNamespace()
915+
err := k8sClient.Create(ctx, ns)
916+
Expect(err).NotTo(HaveOccurred())
917+
//nolint:errcheck
918+
defer k8sClient.Delete(ctx, ns)
919+
By("Creating high-priority PPC that sets ppc64le")
920+
ppcHigh := NewPodPlacementConfig().
921+
WithName("test-ppc-high").
922+
WithNamespace(ns.Name).
923+
WithPriority(100).
924+
WithNodeAffinityScoring(true).
925+
WithNodeAffinityScoringTerm(utils.ArchitecturePpc64le, 50).
926+
Build()
927+
Expect(k8sClient.Create(ctx, ppcHigh)).To(Succeed())
928+
By("Creating lower-priority PPC that also tries to set ppc64le")
929+
ppcLow := NewPodPlacementConfig().
930+
WithName("test-ppc-low").
931+
WithNamespace(ns.Name).
932+
WithPriority(50).
933+
WithNodeAffinityScoring(true).
934+
WithNodeAffinityScoringTerm(utils.ArchitecturePpc64le, 30).
935+
Build()
936+
Expect(k8sClient.Create(ctx, ppcLow)).To(Succeed())
937+
By("Creating a matching pod")
938+
pod := NewPod().
939+
WithContainersImages(fmt.Sprintf("%s/%s/%s:latest", registryAddress,
940+
registry.PublicRepo, registry.ComputeNameByMediaType(imgspecv1.MediaTypeImageManifest))).
941+
WithGenerateName("test-pod-").
942+
WithNamespace(ns.Name).
943+
Build()
944+
Expect(k8sClient.Create(ctx, pod)).To(Succeed())
945+
By("Waiting for the pod to be reconciled")
946+
Eventually(func(g Gomega) {
947+
err := k8sClient.Get(ctx, crclient.ObjectKeyFromObject(pod), pod)
948+
g.Expect(err).NotTo(HaveOccurred())
949+
g.Expect(pod.Spec.SchedulingGates).NotTo(ContainElement(corev1.PodSchedulingGate{
950+
Name: utils.SchedulingGateName,
951+
}), "scheduling gate not removed")
952+
}).Should(Succeed())
953+
By("Verifying the preferred affinity is set by high-priority PPC only")
954+
Eventually(func(g Gomega) {
955+
// Get pod from the API server
956+
err := k8sClient.Get(ctx, crclient.ObjectKeyFromObject(pod), pod)
957+
g.Expect(err).NotTo(HaveOccurred(), "failed to get pod", err)
958+
g.Expect(pod.Labels).To(HaveKeyWithValue(utils.PreferredNodeAffinitySourceLabel, "PodPlacementConfig/test-ppc-high"),
959+
"source should be high-priority PPC")
960+
preferences := []NodeAffinityTerm{
961+
{Arch: []string{utils.ArchitecturePpc64le}, Weight: 50},
962+
}
963+
g.Expect(*pod).To(HaveEquivalentPreferredNodeAffinity(
964+
NewNodeAffinityBuilder().WithPreferredNodeAffinity(preferences).Build()),
965+
"should only have high-priority PPC preferences")
966+
}).Should(Succeed(), "failed to apply correct preferences")
967+
})
968+
It("should apply PPC only to pods matching label selector", func() {
969+
By("Create an ephemeral namespace")
970+
ns := NewEphemeralNamespace()
971+
err := k8sClient.Create(ctx, ns)
972+
Expect(err).NotTo(HaveOccurred())
973+
//nolint:errcheck
974+
defer k8sClient.Delete(ctx, ns)
975+
By("Creating a PPC with label selector app=backend")
976+
ppc := NewPodPlacementConfig().
977+
WithName("test-ppc-selector").
978+
WithNamespace(ns.Name).
979+
WithPriority(100).
980+
WithNodeAffinityScoring(true).
981+
WithNodeAffinityScoringTerm(utils.ArchitecturePpc64le, 60).
982+
WithLabelSelector(&metav1.LabelSelector{
983+
MatchLabels: map[string]string{"app": "backend"},
984+
}).
985+
Build()
986+
Expect(k8sClient.Create(ctx, ppc)).To(Succeed())
987+
By("Creating a matching pod with app=backend label")
988+
matchingPod := NewPod().
989+
WithContainersImages(fmt.Sprintf("%s/%s/%s:latest", registryAddress,
990+
registry.PublicRepo, registry.ComputeNameByMediaType(imgspecv1.MediaTypeImageManifest))).
991+
WithGenerateName("matching-pod-").
992+
WithNamespace(ns.Name).
993+
WithLabels("app", "backend").
994+
Build()
995+
Expect(k8sClient.Create(ctx, matchingPod)).To(Succeed())
996+
By("Creating a non-matching pod with app=frontend label")
997+
nonMatchingPod := NewPod().
998+
WithContainersImages(fmt.Sprintf("%s/%s/%s:latest", registryAddress,
999+
registry.PublicRepo, registry.ComputeNameByMediaType(imgspecv1.MediaTypeImageManifest))).
1000+
WithGenerateName("non-matching-pod-").
1001+
WithNamespace(ns.Name).
1002+
WithLabels("app", "frontend").
1003+
Build()
1004+
Expect(k8sClient.Create(ctx, nonMatchingPod)).To(Succeed())
1005+
By("Waiting for matching pod to be reconciled")
1006+
Eventually(func(g Gomega) {
1007+
err := k8sClient.Get(ctx, crclient.ObjectKeyFromObject(matchingPod), matchingPod)
1008+
g.Expect(err).NotTo(HaveOccurred())
1009+
g.Expect(matchingPod.Spec.SchedulingGates).NotTo(ContainElement(corev1.PodSchedulingGate{
1010+
Name: utils.SchedulingGateName,
1011+
}), "scheduling gate not removed")
1012+
}).Should(Succeed())
1013+
By("Verifying matching pod gets PPC preferences")
1014+
Eventually(func(g Gomega) {
1015+
err := k8sClient.Get(ctx, crclient.ObjectKeyFromObject(matchingPod), matchingPod)
1016+
g.Expect(err).NotTo(HaveOccurred())
1017+
g.Expect(matchingPod.Labels).To(HaveKeyWithValue(utils.PreferredNodeAffinitySourceLabel, "PodPlacementConfig/test-ppc-selector"))
1018+
}).Should(Succeed())
1019+
By("Verifying non-matching pod gets CPPC preferences")
1020+
Eventually(func(g Gomega) {
1021+
err := k8sClient.Get(ctx, crclient.ObjectKeyFromObject(nonMatchingPod), nonMatchingPod)
1022+
g.Expect(err).NotTo(HaveOccurred())
1023+
g.Expect(nonMatchingPod.Labels).To(HaveKeyWithValue(utils.PreferredNodeAffinitySourceLabel, v1beta1.ClusterPodPlacementConfigKind))
1024+
}).Should(Succeed())
1025+
})
1026+
It("should apply PPC with empty label selector to all pods", func() {
1027+
By("Create an ephemeral namespace")
1028+
ns := NewEphemeralNamespace()
1029+
err := k8sClient.Create(ctx, ns)
1030+
Expect(err).NotTo(HaveOccurred())
1031+
//nolint:errcheck
1032+
defer k8sClient.Delete(ctx, ns)
1033+
By("Creating a PPC with nil label selector")
1034+
ppc := NewPodPlacementConfig().
1035+
WithName("test-ppc-empty-selector").
1036+
WithNamespace(ns.Name).
1037+
WithPriority(100).
1038+
WithNodeAffinityScoring(true).
1039+
WithNodeAffinityScoringTerm(utils.ArchitecturePpc64le, 70).
1040+
Build()
1041+
Expect(k8sClient.Create(ctx, ppc)).To(Succeed())
1042+
By("Creating a pod without specific labels")
1043+
pod := NewPod().
1044+
WithContainersImages(fmt.Sprintf("%s/%s/%s:latest", registryAddress,
1045+
registry.PublicRepo, registry.ComputeNameByMediaType(imgspecv1.MediaTypeImageManifest))).
1046+
WithGenerateName("test-pod-").
1047+
WithNamespace(ns.Name).
1048+
Build()
1049+
Expect(k8sClient.Create(ctx, pod)).To(Succeed())
1050+
By("Waiting for the pod to be reconciled")
1051+
Eventually(func(g Gomega) {
1052+
err := k8sClient.Get(ctx, crclient.ObjectKeyFromObject(pod), pod)
1053+
g.Expect(err).NotTo(HaveOccurred())
1054+
g.Expect(pod.Spec.SchedulingGates).NotTo(ContainElement(corev1.PodSchedulingGate{
1055+
Name: utils.SchedulingGateName,
1056+
}), "scheduling gate not removed")
1057+
}).Should(Succeed())
1058+
By("Verifying pod gets PPC preferences (empty selector matches all)")
1059+
Eventually(func(g Gomega) {
1060+
err := k8sClient.Get(ctx, crclient.ObjectKeyFromObject(pod), pod)
1061+
g.Expect(err).NotTo(HaveOccurred())
1062+
g.Expect(pod.Labels).To(HaveKeyWithValue(utils.PreferredNodeAffinitySourceLabel, "PodPlacementConfig/test-ppc-empty-selector"))
1063+
preferences := []NodeAffinityTerm{
1064+
{Arch: []string{utils.ArchitecturePpc64le}, Weight: 70},
1065+
{Arch: []string{utils.ArchitectureArm64}, Weight: 50},
1066+
}
1067+
g.Expect(*pod).To(HaveEquivalentPreferredNodeAffinity(
1068+
NewNodeAffinityBuilder().WithPreferredNodeAffinity(preferences).Build()),
1069+
"should have PPC and CPPC preferences")
1070+
}).Should(Succeed())
1071+
})
8681072
})
8691073
})
8701074
})

pkg/e2e/operator/pod_placement_config_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,23 @@ var _ = Describe("The Multiarch Tuning Operator", Serial, func() {
438438
Eventually(framework.VerifyPodNodeAffinity(ctx, client, ns, "app", "test", *archLabelNSTs), e2e.WaitShort).Should(Succeed())
439439
By("The pod should not have any preferred affinities")
440440
Eventually(framework.VerifyPodPreferredNodeAffinity(ctx, client, ns, "app", "test", nil), e2e.WaitShort).Should(Succeed())
441+
By("Verify the plugin disabled event was emitted")
442+
Eventually(func(g Gomega) {
443+
events := &corev1.EventList{}
444+
err := client.List(ctx, events, runtimeclient.InNamespace(ns.Name))
445+
g.Expect(err).NotTo(HaveOccurred())
446+
447+
found := false
448+
for _, event := range events.Items {
449+
if event.Reason == "ArchAwarePreferredAffinityPluginDisabled" &&
450+
event.InvolvedObject.Kind == "Pod" {
451+
found = true
452+
g.Expect(event.Message).To(ContainSubstring("NodeAffinityScoring plugin is not enabled"))
453+
break
454+
}
455+
}
456+
g.Expect(found).To(BeTrue(), "ArchitecturePreferredAffinityPluginDisabled event not found")
457+
}).Should(Succeed())
441458
})
442459
It("Should create a pod when plugin NodeAffinityScoring is nil", func() {
443460
var err error

0 commit comments

Comments
 (0)