diff --git a/go.mod b/go.mod index d22651944..0954cc17e 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.22.0 require ( github.com/go-logr/logr v1.2.4 + github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.1.2-0.20221215110210-ad3f3381681f github.com/onsi/ginkgo/v2 v2.9.4 github.com/onsi/gomega v1.27.6 github.com/pkg/errors v0.9.1 @@ -52,7 +53,6 @@ require ( github.com/imdario/mergo v0.3.15 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.1.2-0.20221215110210-ad3f3381681f // indirect github.com/kubernetes-csi/external-snapshotter/client/v4 v4.2.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect diff --git a/pkg/pool-manager/pod_pool.go b/pkg/pool-manager/pod_pool.go index 998fb972d..dcbd0cbad 100644 --- a/pkg/pool-manager/pod_pool.go +++ b/pkg/pool-manager/pod_pool.go @@ -28,6 +28,8 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" + + networkv1 "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1" ) const tempPodName = "tempPodName" @@ -40,7 +42,7 @@ func (p *PoolManager) AllocatePodMac(pod *corev1.Pod, isNotDryRun bool) error { "macmap", p.macPoolMap, "currentMac", p.currentMac.String()) - networkValue, ok := pod.Annotations[NetworksAnnotation] + networkValue, ok := pod.Annotations[networkv1.NetworkAttachmentAnnot] if !ok { return nil } @@ -49,7 +51,7 @@ func (p *PoolManager) AllocatePodMac(pod *corev1.Pod, isNotDryRun bool) error { // we want to connect the allocated mac from the webhook to a pod object in the podToMacPoolMap // run it before multus added the status annotation // this mean the pod is not ready - if _, ok := pod.Annotations[networksStatusAnnotation]; ok { + if _, ok := pod.Annotations[networkv1.NetworkStatusAnnot]; ok { return nil } @@ -97,7 +99,7 @@ func (p *PoolManager) AllocatePodMac(pod *corev1.Pod, isNotDryRun bool) error { if err != nil { return err } - pod.Annotations[NetworksAnnotation] = string(networkListJson) + pod.Annotations[networkv1.NetworkAttachmentAnnot] = string(networkListJson) return nil } @@ -238,7 +240,7 @@ func (p *PoolManager) initPodMap() error { continue } - networkValue, ok := pod.Annotations[NetworksAnnotation] + networkValue, ok := pod.Annotations[networkv1.NetworkAttachmentAnnot] if !ok { continue } diff --git a/pkg/pool-manager/pool.go b/pkg/pool-manager/pool.go index fff93dd57..a155921a2 100644 --- a/pkg/pool-manager/pool.go +++ b/pkg/pool-manager/pool.go @@ -40,8 +40,6 @@ const ( RangeStartEnv = "RANGE_START" RangeEndEnv = "RANGE_END" RuntimeObjectFinalizerName = "k8s.v1.cni.cncf.io/kubeMacPool" - NetworksAnnotation = "k8s.v1.cni.cncf.io/networks" - networksStatusAnnotation = "k8s.v1.cni.cncf.io/networks-status" TransactionTimestampAnnotation = "kubemacpool.io/transaction-timestamp" mutatingWebhookConfigName = "kubemacpool-mutator" virtualMachnesWebhookName = "mutatevirtualmachines.kubemacpool.io" diff --git a/pkg/pool-manager/pool_test.go b/pkg/pool-manager/pool_test.go index 43b46f3f6..34f00260e 100644 --- a/pkg/pool-manager/pool_test.go +++ b/pkg/pool-manager/pool_test.go @@ -27,7 +27,6 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - "github.com/pkg/errors" multus "gopkg.in/k8snetworkplumbingwg/multus-cni.v3/pkg/types" admissionregistrationv1 "k8s.io/api/admissionregistration/v1" v1 "k8s.io/api/core/v1" @@ -38,6 +37,8 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/fake" logf "sigs.k8s.io/controller-runtime/pkg/log" + networkv1 "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1" + kubevirt "kubevirt.io/api/core/v1" "github.com/k8snetworkplumbingwg/kubemacpool/pkg/names" @@ -50,114 +51,35 @@ const ( ) var _ = Describe("Pool", func() { - beforeAllocationAnnotation := map[string]string{NetworksAnnotation: `[{ "name": "ovs-conf"}]`} + beforeAllocationAnnotation := map[string]string{networkv1.NetworkAttachmentAnnot: `[{ "name": "ovs-conf"}]`} afterAllocationAnnotation := func(namespace, macAddress string) map[string]string { - return map[string]string{NetworksAnnotation: `[{"name":"ovs-conf","namespace":"` + namespace + `","mac":"` + macAddress + `","cni-args":null}]`} + return map[string]string{networkv1.NetworkAttachmentAnnot: `[{"name":"ovs-conf","namespace":"` + namespace + `","mac":"` + macAddress + `","cni-args":null}]`} } - managedPodWithMacAllocated := v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "podpod", Namespace: managedNamespaceName, Annotations: afterAllocationAnnotation(managedNamespaceName, "02:00:00:00:00:00")}} - unmanagedPodWithMacAllocated := v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "unmanagedPod", Namespace: notManagedNamespaceName, Annotations: afterAllocationAnnotation(notManagedNamespaceName, "02:00:00:00:00:FF")}} - vmConfigMap := v1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Namespace: testManagerNamespace, Name: names.WAITING_VMS_CONFIGMAP}} - noneOnDryRun := admissionregistrationv1.SideEffectClassNoneOnDryRun - waitTimeSeconds := 10 - - appendOptOutModes := func(fakeObjectsForClient []runtime.Object) []runtime.Object { - mutatingWebhookConfiguration := &admissionregistrationv1.MutatingWebhookConfiguration{ - ObjectMeta: metav1.ObjectMeta{ - Name: mutatingWebhookConfigName, - }, - Webhooks: []admissionregistrationv1.MutatingWebhook{ - admissionregistrationv1.MutatingWebhook{ - Name: virtualMachnesWebhookName, - SideEffects: &noneOnDryRun, - AdmissionReviewVersions: []string{"v1", "v1beta1"}, - NamespaceSelector: &metav1.LabelSelector{ - MatchExpressions: []metav1.LabelSelectorRequirement{ - metav1.LabelSelectorRequirement{ - Key: "runlevel", - Operator: "NotIn", - Values: []string{"0", "1"}, - }, - metav1.LabelSelectorRequirement{ - Key: "openshift.io/run-level", - Operator: "NotIn", - Values: []string{"0", "1"}, - }, - metav1.LabelSelectorRequirement{ - Key: virtualMachnesWebhookName, - Operator: "NotIn", - Values: []string{"ignore"}, - }, - }, - }, - }, - admissionregistrationv1.MutatingWebhook{ - Name: podsWebhookName, - SideEffects: &noneOnDryRun, - AdmissionReviewVersions: []string{"v1", "v1beta1"}, - NamespaceSelector: &metav1.LabelSelector{ - MatchExpressions: []metav1.LabelSelectorRequirement{ - metav1.LabelSelectorRequirement{ - Key: "runlevel", - Operator: "NotIn", - Values: []string{"0", "1"}, - }, - metav1.LabelSelectorRequirement{ - Key: "openshift.io/run-level", - Operator: "NotIn", - Values: []string{"0", "1"}, - }, - metav1.LabelSelectorRequirement{ - Key: podsWebhookName, - Operator: "NotIn", - Values: []string{"ignore"}, - }, - }, - }, - }, - }, - } - managedNamespace := &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: managedNamespaceName}} - notManagedNamespace := &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: notManagedNamespaceName, Labels: map[string]string{podsWebhookName: "ignore", virtualMachnesWebhookName: "ignore"}}} - By("Setting kubemacpool MutatingWebhookConfigurations to opt-out mode on vms and pods") - fakeObjectsForClient = append(fakeObjectsForClient, mutatingWebhookConfiguration) - By("Setting managed and non-managed namespaces") - fakeObjectsForClient = append(fakeObjectsForClient, managedNamespace, notManagedNamespace) - return fakeObjectsForClient + const ( + managedNamespaceMAC = "02:00:00:00:00:00" + unmanagedNamespaceMAC = "02:00:00:00:00:FF" + ) + managedPodWithMacAllocated := v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "podpod", + Namespace: managedNamespaceName, + Annotations: afterAllocationAnnotation(managedNamespaceName, managedNamespaceMAC), + }, } - createPoolManager := func(startMacAddr, endMacAddr string, fakeObjectsForClient ...runtime.Object) *PoolManager { - fakeObjectsForClient = appendOptOutModes(fakeObjectsForClient) - fakeClient := fake.NewClientBuilder().WithScheme(scheme.Scheme).WithRuntimeObjects(fakeObjectsForClient...).Build() - startPoolRangeEnv, err := net.ParseMAC(startMacAddr) - Expect(err).ToNot(HaveOccurred(), "should successfully parse starting mac address range") - endPoolRangeEnv, err := net.ParseMAC(endMacAddr) - Expect(err).ToNot(HaveOccurred(), "should successfully parse ending mac address range") - poolManager, err := NewPoolManager(fakeClient, fakeClient, startPoolRangeEnv, endPoolRangeEnv, testManagerNamespace, false, waitTimeSeconds) - Expect(err).ToNot(HaveOccurred(), "should successfully initialize poolManager") - err = poolManager.Start() - Expect(err).ToNot(HaveOccurred(), "should successfully start poolManager routines") - return poolManager + + unmanagedPodWithMacAllocated := v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "unmanagedPod", + Namespace: notManagedNamespaceName, + Annotations: afterAllocationAnnotation(notManagedNamespaceName, unmanagedNamespaceMAC), + }, } - checkMacPoolMapEntries := func(macPoolMap map[macKey]macEntry, updatedTransactionTimestamp *time.Time, updatedMacs, notUpdatedMacs []string) error { - for _, macAddress := range updatedMacs { - macEntry, exist := macPoolMap[NewMacKey(macAddress)] - if !exist { - return errors.New(fmt.Sprintf("mac %s should exist in macPoolMap %v", macAddress, macPoolMap)) - } - if macEntry.transactionTimestamp != updatedTransactionTimestamp { - return errors.New(fmt.Sprintf("mac %s has transactionTimestamp %s, should have an updated transactionTimestamp %s", macAddress, macEntry.transactionTimestamp, updatedTransactionTimestamp)) - } - } - for _, macAddress := range notUpdatedMacs { - macEntry, exist := macPoolMap[NewMacKey(macAddress)] - if !exist { - return errors.New(fmt.Sprintf("mac %s should exist in macPoolMap %v", macAddress, macPoolMap)) - } - if macEntry.transactionTimestamp == updatedTransactionTimestamp { - return errors.New(fmt.Sprintf("mac %s has transactionTimestamp %s, should not have an updated transactionTimestamp %s", macAddress, macEntry.transactionTimestamp, updatedTransactionTimestamp)) - } - } - return nil + vmConfigMap := v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testManagerNamespace, + Name: names.WAITING_VMS_CONFIGMAP, + }, } Describe("Internal Functions", func() { @@ -283,7 +205,7 @@ var _ = Describe("Pool", func() { }) It("Should initialize the macPoolmap only with macs on the mananged pods", func() { Expect(poolManager.macPoolMap).To(HaveLen(1)) - entry, exist := poolManager.macPoolMap[NewMacKey("02:00:00:00:00:00")] + entry, exist := poolManager.macPoolMap[NewMacKey(managedNamespaceMAC)] Expect(exist).To(BeTrue(), "should include the mac allocated by the managed pod") expectMacEntry := macEntry{ instanceName: fmt.Sprintf("pod/%s/%s", managedPodWithMacAllocated.Namespace, managedPodWithMacAllocated.Name), @@ -320,9 +242,30 @@ var _ = Describe("Pool", func() { InterfaceBindingMethod: kubevirt.InterfaceBindingMethod{ Bridge: &kubevirt.InterfaceBridge{}}} - podNetwork := kubevirt.Network{Name: "pod", NetworkSource: kubevirt.NetworkSource{Pod: &kubevirt.PodNetwork{}}} - multusNetwork := kubevirt.Network{Name: "multus", NetworkSource: kubevirt.NetworkSource{Multus: &kubevirt.MultusNetwork{NetworkName: "multus"}}} - anotherMultusNetwork := kubevirt.Network{Name: "another-multus", NetworkSource: kubevirt.NetworkSource{Multus: &kubevirt.MultusNetwork{NetworkName: "another-multus"}}} + podNetwork := kubevirt.Network{ + Name: "pod", + NetworkSource: kubevirt.NetworkSource{ + Pod: &kubevirt.PodNetwork{}, + }, + } + + multusNetwork := kubevirt.Network{ + Name: "multus", + NetworkSource: kubevirt.NetworkSource{ + Multus: &kubevirt.MultusNetwork{ + NetworkName: "multus", + }, + }, + } + + anotherMultusNetwork := kubevirt.Network{ + Name: "another-multus", + NetworkSource: kubevirt.NetworkSource{ + Multus: &kubevirt.MultusNetwork{ + NetworkName: "another-multus", + }, + }, + } sampleVM := kubevirt.VirtualMachine{ObjectMeta: metav1.ObjectMeta{Namespace: "default"}, Spec: kubevirt.VirtualMachineSpec{ Template: &kubevirt.VirtualMachineInstanceTemplateSpec{ @@ -347,6 +290,7 @@ var _ = Describe("Pool", func() { Devices: kubevirt.Devices{ Interfaces: []kubevirt.Interface{masqueradeInterface, multusBridgeInterface}}}, Networks: []kubevirt.Network{podNetwork, multusNetwork}}}}} + duplicateInterfacesVM := kubevirt.VirtualMachine{ObjectMeta: metav1.ObjectMeta{Namespace: "default"}, Spec: kubevirt.VirtualMachineSpec{ Template: &kubevirt.VirtualMachineInstanceTemplateSpec{ Spec: kubevirt.VirtualMachineInstanceSpec{ @@ -354,6 +298,7 @@ var _ = Describe("Pool", func() { Devices: kubevirt.Devices{ Interfaces: []kubevirt.Interface{masqueradeInterface, multusBridgeInterface, multusBridgeInterface}}}, Networks: []kubevirt.Network{podNetwork, multusNetwork}}}}} + updateTransactionTimestamp := func(secondsPassed time.Duration) time.Time { return time.Now().Add(secondsPassed * time.Second) } @@ -389,14 +334,13 @@ var _ = Describe("Pool", func() { err := poolManager.AllocateVirtualMachineMac(&newVM, &transactionTimestamp, true, logger) Expect(err).ToNot(HaveOccurred()) - Expect(poolManager.macPoolMap).To(HaveLen(2)) - Expect(checkMacPoolMapEntries(poolManager.macPoolMap, &transactionTimestamp, []string{"02:00:00:00:00:01"}, []string{"02:00:00:00:00:00"})).To(Succeed(), "Failed to check macs in macMap") + Expect(checkMacPoolMapEntries(poolManager.macPoolMap, &transactionTimestamp, []string{"02:00:00:00:00:01"}, []string{managedNamespaceMAC})).To(Succeed(), "Failed to check macs in macMap") Expect(newVM.Spec.Template.Spec.Domain.Devices.Interfaces[0].MacAddress).To(Equal("02:00:00:00:00:01")) err = poolManager.ReleaseAllVirtualMachineMacs(VmNamespaced(&newVM), logger) Expect(err).ToNot(HaveOccurred()) Expect(poolManager.macPoolMap).To(HaveLen(1), "Should keep the pod mac in the macMap") - Expect(checkMacPoolMapEntries(poolManager.macPoolMap, &transactionTimestamp, []string{}, []string{"02:00:00:00:00:00"})).To(Succeed(), "Failed to check macs in macMap") + Expect(checkMacPoolMapEntries(poolManager.macPoolMap, &transactionTimestamp, []string{}, []string{managedNamespaceMAC})).To(Succeed(), "Failed to check macs in macMap") }) It("should allocate a new mac and release it for multiple interfaces", func() { newVM := multipleInterfacesVM.DeepCopy() @@ -406,16 +350,14 @@ var _ = Describe("Pool", func() { err := poolManager.AllocateVirtualMachineMac(newVM, &transactionTimestamp, true, logger) Expect(err).ToNot(HaveOccurred()) - Expect(poolManager.macPoolMap).To(HaveLen(3)) - Expect(checkMacPoolMapEntries(poolManager.macPoolMap, &transactionTimestamp, []string{"02:00:00:00:00:01", "02:00:00:00:00:02"}, []string{"02:00:00:00:00:00"})).To(Succeed(), "Failed to check macs in macMap") + Expect(checkMacPoolMapEntries(poolManager.macPoolMap, &transactionTimestamp, []string{"02:00:00:00:00:01", "02:00:00:00:00:02"}, []string{managedNamespaceMAC})).To(Succeed(), "Failed to check macs in macMap") Expect(newVM.Spec.Template.Spec.Domain.Devices.Interfaces[0].MacAddress).To(Equal("02:00:00:00:00:01")) Expect(newVM.Spec.Template.Spec.Domain.Devices.Interfaces[1].MacAddress).To(Equal("02:00:00:00:00:02")) err = poolManager.ReleaseAllVirtualMachineMacs(VmNamespaced(newVM), logf.Log.WithName("VirtualMachine Controller")) Expect(err).ToNot(HaveOccurred()) - Expect(poolManager.macPoolMap).To(HaveLen(1), "Should keep the pod mac in the macMap") - Expect(checkMacPoolMapEntries(poolManager.macPoolMap, &transactionTimestamp, []string{}, []string{"02:00:00:00:00:00"})).To(Succeed(), "Failed to check macs in macMap") + Expect(checkMacPoolMapEntries(poolManager.macPoolMap, &transactionTimestamp, []string{}, []string{managedNamespaceMAC})).To(Succeed(), "Failed to check macs in macMap") }) }) Describe("Update vm object", func() { @@ -821,12 +763,11 @@ var _ = Describe("Pool", func() { err := poolManager.AllocatePodMac(&newPod, true) Expect(err).ToNot(HaveOccurred()) - preAllocatedPodMac := "02:00:00:00:00:00" + preAllocatedPodMac := managedNamespaceMAC expectedAllocatedMac := "02:00:00:00:00:01" - Expect(poolManager.macPoolMap).To(HaveLen(2)) Expect(checkMacPoolMapEntries(poolManager.macPoolMap, nil, []string{preAllocatedPodMac, expectedAllocatedMac}, []string{})).To(Succeed(), "Failed to check macs in macMap") - Expect(newPod.Annotations[NetworksAnnotation]).To(Equal(afterAllocationAnnotation(managedNamespaceName, "02:00:00:00:00:01")[NetworksAnnotation])) + Expect(newPod.Annotations[networkv1.NetworkAttachmentAnnot]).To(Equal(afterAllocationAnnotation(managedNamespaceName, "02:00:00:00:00:01")[networkv1.NetworkAttachmentAnnot])) expectedMacEntry := macEntry{ transactionTimestamp: nil, instanceName: podNamespaced(&newPod), @@ -836,7 +777,6 @@ var _ = Describe("Pool", func() { err = poolManager.ReleaseAllPodMacs(podNamespaced(&newPod)) Expect(err).ToNot(HaveOccurred()) - Expect(poolManager.macPoolMap).To(HaveLen(1)) Expect(checkMacPoolMapEntries(poolManager.macPoolMap, nil, []string{preAllocatedPodMac}, []string{})).To(Succeed(), "Failed to check macs in macMap") _, exist := poolManager.macPoolMap[NewMacKey(expectedAllocatedMac)] Expect(exist).To(BeFalse()) @@ -848,7 +788,7 @@ var _ = Describe("Pool", func() { err := poolManager.AllocatePodMac(&newPod, true) Expect(err).ToNot(HaveOccurred()) - Expect(newPod.Annotations[NetworksAnnotation]).To(Equal(afterAllocationAnnotation(managedNamespaceName, "02:00:00:00:00:00")[NetworksAnnotation])) + Expect(newPod.Annotations[networkv1.NetworkAttachmentAnnot]).To(Equal(afterAllocationAnnotation(managedNamespaceName, managedNamespaceMAC)[networkv1.NetworkAttachmentAnnot])) }) }) @@ -864,14 +804,14 @@ var _ = Describe("Pool", func() { DescribeTable("should allocate mac-address correspond to the one specified in the networks annotation", func(networkRequestAnnotation string) { pod := v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "testPod", Namespace: "default"}} - pod.Annotations = map[string]string{NetworksAnnotation: fmt.Sprintf("%s", networkRequestAnnotation)} + pod.Annotations = map[string]string{networkv1.NetworkAttachmentAnnot: fmt.Sprintf("%s", networkRequestAnnotation)} By("Request specific mac-address by adding the address to the networks pod annotation") err := poolManager.AllocatePodMac(&pod, true) Expect(err).ToNot(HaveOccurred(), "should allocate mac address and ip address correspond to networks annotation") By("Convert obtained networks annotation JSON to multus.NetworkSelectionElement array") - obtainedNetworksAnnotationJson := pod.Annotations[NetworksAnnotation] + obtainedNetworksAnnotationJson := pod.Annotations[networkv1.NetworkAttachmentAnnot] obtainedNetworksAnnotation := []multus.NetworkSelectionElement{} err = json.Unmarshal([]byte(obtainedNetworksAnnotationJson), &obtainedNetworksAnnotation) Expect(err).ToNot(HaveOccurred(), "should convert obtained annotation as json to multus.NetworkSelectionElement") @@ -898,7 +838,7 @@ var _ = Describe("Pool", func() { It("should fail to allocate requested mac-address, with ip-address request as string instead of string array", func() { pod := v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "testPod", Namespace: "default"}} pod.Annotations = map[string]string{ - NetworksAnnotation: `[{"name":"ovs-conf","namespace":"default","ips":"10.10.0.1","mac":"02:00:00:00:00:00"}]`} + networkv1.NetworkAttachmentAnnot: `[{"name":"ovs-conf","namespace":"default","ips":"10.10.0.1","mac":"02:00:00:00:00:00"}]`} By("Request specific mac-address by adding the address to the networks pod annotation") err := poolManager.AllocatePodMac(&pod, true) @@ -1132,3 +1072,109 @@ var _ = Describe("Pool", func() { ) }) }) + +func appendOptOutModes(fakeObjectsForClient []runtime.Object) []runtime.Object { + noneOnDryRun := admissionregistrationv1.SideEffectClassNoneOnDryRun + mutatingWebhookConfiguration := &admissionregistrationv1.MutatingWebhookConfiguration{ + ObjectMeta: metav1.ObjectMeta{ + Name: mutatingWebhookConfigName, + }, + Webhooks: []admissionregistrationv1.MutatingWebhook{ + admissionregistrationv1.MutatingWebhook{ + Name: virtualMachnesWebhookName, + SideEffects: &noneOnDryRun, + AdmissionReviewVersions: []string{"v1", "v1beta1"}, + NamespaceSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + metav1.LabelSelectorRequirement{ + Key: "runlevel", + Operator: "NotIn", + Values: []string{"0", "1"}, + }, + metav1.LabelSelectorRequirement{ + Key: "openshift.io/run-level", + Operator: "NotIn", + Values: []string{"0", "1"}, + }, + metav1.LabelSelectorRequirement{ + Key: virtualMachnesWebhookName, + Operator: "NotIn", + Values: []string{"ignore"}, + }, + }, + }, + }, + admissionregistrationv1.MutatingWebhook{ + Name: podsWebhookName, + SideEffects: &noneOnDryRun, + AdmissionReviewVersions: []string{"v1", "v1beta1"}, + NamespaceSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + metav1.LabelSelectorRequirement{ + Key: "runlevel", + Operator: "NotIn", + Values: []string{"0", "1"}, + }, + metav1.LabelSelectorRequirement{ + Key: "openshift.io/run-level", + Operator: "NotIn", + Values: []string{"0", "1"}, + }, + metav1.LabelSelectorRequirement{ + Key: podsWebhookName, + Operator: "NotIn", + Values: []string{"ignore"}, + }, + }, + }, + }, + }, + } + managedNamespace := &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: managedNamespaceName}} + notManagedNamespace := &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: notManagedNamespaceName, Labels: map[string]string{podsWebhookName: "ignore", virtualMachnesWebhookName: "ignore"}}} + By("Setting kubemacpool MutatingWebhookConfigurations to opt-out mode on vms and pods") + fakeObjectsForClient = append(fakeObjectsForClient, mutatingWebhookConfiguration) + By("Setting managed and non-managed namespaces") + fakeObjectsForClient = append(fakeObjectsForClient, managedNamespace, notManagedNamespace) + return fakeObjectsForClient +} + +func createPoolManager(startMacAddr, endMacAddr string, fakeObjectsForClient ...runtime.Object) *PoolManager { + waitTimeSeconds := 10 + fakeObjectsForClient = appendOptOutModes(fakeObjectsForClient) + fakeClient := fake.NewClientBuilder().WithScheme(scheme.Scheme).WithRuntimeObjects(fakeObjectsForClient...).Build() + startPoolRangeEnv, err := net.ParseMAC(startMacAddr) + Expect(err).ToNot(HaveOccurred(), "should successfully parse starting mac address range") + endPoolRangeEnv, err := net.ParseMAC(endMacAddr) + Expect(err).ToNot(HaveOccurred(), "should successfully parse ending mac address range") + poolManager, err := NewPoolManager(fakeClient, fakeClient, startPoolRangeEnv, endPoolRangeEnv, testManagerNamespace, false, waitTimeSeconds) + Expect(err).ToNot(HaveOccurred(), "should successfully initialize poolManager") + err = poolManager.Start() + Expect(err).ToNot(HaveOccurred(), "should successfully start poolManager routines") + return poolManager +} + +func checkMacPoolMapEntries(macPoolMap map[macKey]macEntry, updatedTransactionTimestamp *time.Time, updatedMacs, notUpdatedMacs []string) error { + if len(macPoolMap) != len(updatedMacs)+len(notUpdatedMacs) { + return fmt.Errorf("mac pool size %d is not as expected %d, should only contain MACs %v, macPoolMap %+v", len(macPoolMap), len(updatedMacs)+len(notUpdatedMacs), append(updatedMacs, notUpdatedMacs...), macPoolMap) + } + for _, macAddress := range updatedMacs { + macEntry, exist := macPoolMap[NewMacKey(macAddress)] + if !exist { + return fmt.Errorf("mac %s should exist in macPoolMap %v", macAddress, macPoolMap) + } + if macEntry.transactionTimestamp != updatedTransactionTimestamp { + return fmt.Errorf("mac %s has transactionTimestamp %s, should have an updated transactionTimestamp %s", macAddress, macEntry.transactionTimestamp, updatedTransactionTimestamp) + } + } + for _, macAddress := range notUpdatedMacs { + macEntry, exist := macPoolMap[NewMacKey(macAddress)] + if !exist { + return fmt.Errorf("mac %s should exist in macPoolMap %v", macAddress, macPoolMap) + } + if macEntry.transactionTimestamp == updatedTransactionTimestamp { + return fmt.Errorf("mac %s has transactionTimestamp %s, should not have an updated transactionTimestamp %s", macAddress, macEntry.transactionTimestamp, updatedTransactionTimestamp) + } + } + return nil +} diff --git a/pkg/webhook/pod/pod.go b/pkg/webhook/pod/pod.go index 1ccc6360a..968817959 100644 --- a/pkg/webhook/pod/pod.go +++ b/pkg/webhook/pod/pod.go @@ -28,6 +28,8 @@ import ( "sigs.k8s.io/controller-runtime/pkg/webhook" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" + networkv1 "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1" + pool_manager "github.com/k8snetworkplumbingwg/kubemacpool/pkg/pool-manager" crwebhook "sigs.k8s.io/controller-runtime/pkg/webhook" ) @@ -78,8 +80,8 @@ func (a *podAnnotator) Handle(ctx context.Context, req admission.Request) admiss func patchPodChanges(originalPod, currentPod *corev1.Pod) admission.Response { kubemapcoolJsonPatches := []jsonpatch.Operation{} - currentNetworkAnnotation := currentPod.GetAnnotations()[pool_manager.NetworksAnnotation] - originalPodNetworkAnnotation := originalPod.GetAnnotations()[pool_manager.NetworksAnnotation] + currentNetworkAnnotation := currentPod.GetAnnotations()[networkv1.NetworkAttachmentAnnot] + originalPodNetworkAnnotation := originalPod.GetAnnotations()[networkv1.NetworkAttachmentAnnot] if originalPodNetworkAnnotation != currentNetworkAnnotation { annotationPatch := jsonpatch.NewOperation("replace", "/metadata/annotations", currentPod.GetAnnotations()) kubemapcoolJsonPatches = append(kubemapcoolJsonPatches, annotationPatch)