From 502014a54295d0313fdac5a6f2308ed3194872aa Mon Sep 17 00:00:00 2001 From: Talor Itzhak Date: Thu, 26 Sep 2024 11:20:14 +0300 Subject: [PATCH] test-unit: emulating upgrade to 4.18 Emulating an integration test that emulates an upgrade from 4.1X -> 4.18 and verifies that the MachineConfigs are deleted. Signed-off-by: Talor Itzhak --- .../numaresourcesoperator_controller_test.go | 142 ++++++++++++++++++ internal/objects/objects.go | 14 ++ 2 files changed, 156 insertions(+) diff --git a/controllers/numaresourcesoperator_controller_test.go b/controllers/numaresourcesoperator_controller_test.go index 11b581e07..3365d6e51 100644 --- a/controllers/numaresourcesoperator_controller_test.go +++ b/controllers/numaresourcesoperator_controller_test.go @@ -46,6 +46,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/reconcile" nropv1 "github.com/openshift-kni/numaresources-operator/api/numaresourcesoperator/v1" + "github.com/openshift-kni/numaresources-operator/internal/api/features" "github.com/openshift-kni/numaresources-operator/pkg/images" "github.com/openshift-kni/numaresources-operator/pkg/objectnames" "github.com/openshift-kni/numaresources-operator/pkg/objectstate/rte" @@ -210,6 +211,43 @@ var _ = Describe("Test NUMAResourcesOperator Reconcile", func() { } Expect(reconciler.Client.Get(context.TODO(), mcp2DSKey, ds)).To(Succeed()) }) + When("NRO created without the custom policy annotation", func() { + BeforeEach(func() { + // check we have at least two NodeGroups + Expect(len(nro.Spec.NodeGroups)).To(BeNumerically(">", 1)) + + By("Update NRO to have both NodeGroups") + key := client.ObjectKeyFromObject(nro) + nro := &nropv1.NUMAResourcesOperator{} + Expect(reconciler.Client.Get(context.TODO(), key, nro)).NotTo(HaveOccurred()) + + nro.Spec.NodeGroups = []nropv1.NodeGroup{{ + MachineConfigPoolSelector: &metav1.LabelSelector{MatchLabels: label1}}, + {MachineConfigPoolSelector: &metav1.LabelSelector{MatchLabels: label2}}} + Expect(reconciler.Client.Update(context.TODO(), nro)).NotTo(HaveOccurred()) + + thirdLoopResult, err := reconciler.Reconcile(context.TODO(), reconcile.Request{NamespacedName: key}) + Expect(err).ToNot(HaveOccurred()) + Expect(thirdLoopResult).To(Equal(reconcile.Result{RequeueAfter: 5 * time.Second})) + }) + It("should not create a machine config", func() { + mc := &machineconfigv1.MachineConfig{} + + // Check mc1 not created + mc1Key := client.ObjectKey{ + Name: objectnames.GetMachineConfigName(nro.Name, mcp1.Name), + } + err := reconciler.Client.Get(context.TODO(), mc1Key, mc) + Expect(apierrors.IsNotFound(err)).To(BeTrue(), "MachineConfig %s is expected to not be found", mc1Key.String()) + + // Check mc1 not created + mc2Key := client.ObjectKey{ + Name: objectnames.GetMachineConfigName(nro.Name, mcp2.Name), + } + err = reconciler.Client.Get(context.TODO(), mc2Key, mc) + Expect(apierrors.IsNotFound(err)).To(BeTrue(), "MachineConfig %s is expected to not be found", mc2Key.String()) + }) + }) When("a NodeGroup is deleted", func() { BeforeEach(func() { // check we have at least two NodeGroups @@ -223,6 +261,7 @@ var _ = Describe("Test NUMAResourcesOperator Reconcile", func() { nro.Spec.NodeGroups = []nropv1.NodeGroup{{ MachineConfigPoolSelector: &metav1.LabelSelector{MatchLabels: label1}, }} + nro.Annotations = map[string]string{features.ForceCustomSELinuxPolicyAnnotation: ""} Expect(reconciler.Client.Update(context.TODO(), nro)).NotTo(HaveOccurred()) thirdLoopResult, err := reconciler.Reconcile(context.TODO(), reconcile.Request{NamespacedName: key}) @@ -319,6 +358,7 @@ var _ = Describe("Test NUMAResourcesOperator Reconcile", func() { {MatchLabels: label1}, {MatchLabels: label2}, }) + nro.Annotations = map[string]string{features.ForceCustomSELinuxPolicyAnnotation: ""} mcp1 = testobjs.NewMachineConfigPool("test1", label1, &metav1.LabelSelector{MatchLabels: label1}, &metav1.LabelSelector{MatchLabels: label1}) mcp2 = testobjs.NewMachineConfigPool("test2", label2, &metav1.LabelSelector{MatchLabels: label2}, &metav1.LabelSelector{MatchLabels: label2}) @@ -558,6 +598,7 @@ var _ = Describe("Test NUMAResourcesOperator Reconcile", func() { }, }, } + nro.Annotations = map[string]string{features.ForceCustomSELinuxPolicyAnnotation: ""} }) When("machine config selector matches machine config labels", func() { @@ -1088,6 +1129,107 @@ var _ = Describe("Test NUMAResourcesOperator Reconcile", func() { Expect(ds.Spec.Template.Spec.Tolerations).To(Equal(reconciler.RTEManifests.DaemonSet.Spec.Template.Spec.Tolerations), "DS tolerations not restored to defaults") }) }) + Context("emulating upgrade from 4.1X to 4.18 which has a built-in selinux policy for RTE pods", func() { + var nro *nropv1.NUMAResourcesOperator + var mcp1 *machineconfigv1.MachineConfigPool + var mcp2 *machineconfigv1.MachineConfigPool + var mc1 *machineconfigv1.MachineConfig + var mc2 *machineconfigv1.MachineConfig + + var reconciler *NUMAResourcesOperatorReconciler + var label1, label2 map[string]string + + BeforeEach(func() { + label1 = map[string]string{ + "test1": "test1", + } + label2 = map[string]string{ + "test2": "test2", + } + + nro = testobjs.NewNUMAResourcesOperator(objectnames.DefaultNUMAResourcesOperatorCrName, []*metav1.LabelSelector{ + {MatchLabels: label1}, + {MatchLabels: label2}, + }) + + mcp1 = testobjs.NewMachineConfigPool("test1", label1, &metav1.LabelSelector{MatchLabels: label1}, &metav1.LabelSelector{MatchLabels: label1}) + mcp2 = testobjs.NewMachineConfigPool("test2", label2, &metav1.LabelSelector{MatchLabels: label2}, &metav1.LabelSelector{MatchLabels: label2}) + + mc1 = testobjs.NewMachineConfig(objectnames.GetMachineConfigName(nro.Name, mcp1.Name), label1) + mc2 = testobjs.NewMachineConfig(objectnames.GetMachineConfigName(nro.Name, mcp2.Name), label2) + + var err error + reconciler, err = NewFakeNUMAResourcesOperatorReconciler(platform.OpenShift, defaultOCPVersion, nro, mcp1, mcp2, mc1, mc2) + Expect(err).ToNot(HaveOccurred()) + + key := client.ObjectKeyFromObject(nro) + firstLoopResult, err := reconciler.Reconcile(context.TODO(), reconcile.Request{NamespacedName: key}) + Expect(err).ToNot(HaveOccurred()) + Expect(firstLoopResult).To(Equal(reconcile.Result{RequeueAfter: time.Minute})) + + // Ensure mcp1 is ready + Expect(reconciler.Client.Get(context.TODO(), client.ObjectKeyFromObject(mcp1), mcp1)).To(Succeed()) + mcp1.Status.Configuration.Source = []corev1.ObjectReference{ + { + Name: objectnames.GetMachineConfigName(nro.Name, mcp1.Name), + }, + } + mcp1.Status.Conditions = []machineconfigv1.MachineConfigPoolCondition{ + { + Type: machineconfigv1.MachineConfigPoolUpdated, + Status: corev1.ConditionTrue, + }, + } + Expect(reconciler.Client.Update(context.TODO(), mcp1)).To(Succeed()) + + // ensure mcp2 is ready + Expect(reconciler.Client.Get(context.TODO(), client.ObjectKeyFromObject(mcp2), mcp2)).To(Succeed()) + mcp2.Status.Configuration.Source = []corev1.ObjectReference{ + { + Name: objectnames.GetMachineConfigName(nro.Name, mcp2.Name), + }, + } + mcp2.Status.Conditions = []machineconfigv1.MachineConfigPoolCondition{ + { + Type: machineconfigv1.MachineConfigPoolUpdated, + Status: corev1.ConditionTrue, + }, + } + Expect(reconciler.Client.Update(context.TODO(), mcp2)).To(Succeed()) + + secondLoopResult, err := reconciler.Reconcile(context.TODO(), reconcile.Request{NamespacedName: key}) + Expect(err).ToNot(HaveOccurred()) + Expect(secondLoopResult).To(Equal(reconcile.Result{RequeueAfter: 5 * time.Second})) + + By("Check DaemonSets are created") + mcp1DSKey := client.ObjectKey{ + Name: objectnames.GetComponentName(nro.Name, mcp1.Name), + Namespace: testNamespace, + } + ds := &appsv1.DaemonSet{} + Expect(reconciler.Client.Get(context.TODO(), mcp1DSKey, ds)).ToNot(HaveOccurred()) + + mcp2DSKey := client.ObjectKey{ + Name: objectnames.GetComponentName(nro.Name, mcp2.Name), + Namespace: testNamespace, + } + Expect(reconciler.Client.Get(context.TODO(), mcp2DSKey, ds)).To(Succeed()) + }) + It("should delete existing mc", func() { + mc1Key := client.ObjectKey{ + Name: mc1.Name, + } + mc := &machineconfigv1.MachineConfig{} + err := reconciler.Client.Get(context.TODO(), mc1Key, mc) + Expect(apierrors.IsNotFound(err)).To(BeTrue(), "MachineConfig %s expected to be deleted; err=%v", mc1Key.Name, err) + + mc2Key := client.ObjectKey{ + Name: mc1.Name, + } + err = reconciler.Client.Get(context.TODO(), mc2Key, mc) + Expect(apierrors.IsNotFound(err)).To(BeTrue(), "MachineConfig %s expected to be deleted; err=%v", mc2Key.Name, err) + }) + }) }) func getConditionByType(conditions []metav1.Condition, conditionType string) *metav1.Condition { diff --git a/internal/objects/objects.go b/internal/objects/objects.go index 55e61ff50..2fa1dd55e 100644 --- a/internal/objects/objects.go +++ b/internal/objects/objects.go @@ -107,6 +107,20 @@ func NewMachineConfigPool(name string, labels map[string]string, machineConfigSe } } +func NewMachineConfig(name string, labels map[string]string) *machineconfigv1.MachineConfig { + return &machineconfigv1.MachineConfig{ + TypeMeta: metav1.TypeMeta{ + Kind: "MachineConfig", + APIVersion: machineconfigv1.GroupVersion.String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Labels: labels, + }, + Spec: machineconfigv1.MachineConfigSpec{}, + } +} + func NewKubeletConfig(name string, labels map[string]string, machineConfigSelector *metav1.LabelSelector, kubeletConfig *kubeletconfigv1beta1.KubeletConfiguration) *machineconfigv1.KubeletConfig { data, _ := json.Marshal(kubeletConfig) return NewKubeletConfigWithData(name, labels, machineConfigSelector, data)