1
0
Fork 0
mirror of https://github.com/kubernetes-sigs/node-feature-discovery.git synced 2025-03-31 04:04:51 +00:00

topology-updater: ditch apihelper

Stop using pkg/apihelper for accessing the Kubernetes API. Modify unit
tests to use the fake kubernetes client instead of mocked apihelper
interface.
This commit is contained in:
Markus Lehtonen 2024-01-22 15:24:16 +02:00
parent 5d30be1013
commit c581a25a39
3 changed files with 50 additions and 56 deletions

View file

@ -26,12 +26,12 @@ import (
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
k8sclient "k8s.io/client-go/kubernetes"
"k8s.io/klog/v2" "k8s.io/klog/v2"
kubeletconfigv1beta1 "k8s.io/kubelet/config/v1beta1" kubeletconfigv1beta1 "k8s.io/kubelet/config/v1beta1"
"github.com/k8stopologyawareschedwg/noderesourcetopology-api/pkg/apis/topology/v1alpha2" "github.com/k8stopologyawareschedwg/noderesourcetopology-api/pkg/apis/topology/v1alpha2"
topologyclientset "github.com/k8stopologyawareschedwg/noderesourcetopology-api/pkg/generated/clientset/versioned" topologyclientset "github.com/k8stopologyawareschedwg/noderesourcetopology-api/pkg/generated/clientset/versioned"
"sigs.k8s.io/node-feature-discovery/pkg/apihelper"
"sigs.k8s.io/node-feature-discovery/pkg/nfd-topology-updater/kubeletnotifier" "sigs.k8s.io/node-feature-discovery/pkg/nfd-topology-updater/kubeletnotifier"
"sigs.k8s.io/node-feature-discovery/pkg/podres" "sigs.k8s.io/node-feature-discovery/pkg/podres"
"sigs.k8s.io/node-feature-discovery/pkg/resourcemonitor" "sigs.k8s.io/node-feature-discovery/pkg/resourcemonitor"
@ -74,7 +74,6 @@ type NfdTopologyUpdater interface {
type nfdTopologyUpdater struct { type nfdTopologyUpdater struct {
nodeName string nodeName string
args Args args Args
apihelper apihelper.APIHelpers
topoClient topologyclientset.Interface topoClient topologyclientset.Interface
resourcemonitorArgs resourcemonitor.Args resourcemonitorArgs resourcemonitor.Args
stop chan struct{} // channel for signaling stop stop chan struct{} // channel for signaling stop
@ -137,13 +136,17 @@ func (w *nfdTopologyUpdater) Run() error {
if err != nil { if err != nil {
return err return err
} }
w.apihelper = apihelper.K8sHelpers{Kubeconfig: kubeconfig}
topoClient, err := topologyclientset.NewForConfig(kubeconfig) topoClient, err := topologyclientset.NewForConfig(kubeconfig)
if err != nil { if err != nil {
return nil return nil
} }
w.topoClient = topoClient w.topoClient = topoClient
k8sClient, err := k8sclient.NewForConfig(kubeconfig)
if err != nil {
return err
}
if err := w.configure(); err != nil { if err := w.configure(); err != nil {
return fmt.Errorf("faild to configure Node Feature Discovery Topology Updater: %w", err) return fmt.Errorf("faild to configure Node Feature Discovery Topology Updater: %w", err)
} }
@ -160,7 +163,7 @@ func (w *nfdTopologyUpdater) Run() error {
var resScan resourcemonitor.ResourcesScanner var resScan resourcemonitor.ResourcesScanner
resScan, err = resourcemonitor.NewPodResourcesScanner(w.resourcemonitorArgs.Namespace, podResClient, w.apihelper, w.resourcemonitorArgs.PodSetFingerprint) resScan, err = resourcemonitor.NewPodResourcesScanner(w.resourcemonitorArgs.Namespace, podResClient, k8sClient, w.resourcemonitorArgs.PodSetFingerprint)
if err != nil { if err != nil {
return fmt.Errorf("failed to initialize ResourceMonitor instance: %w", err) return fmt.Errorf("failed to initialize ResourceMonitor instance: %w", err)
} }

View file

@ -23,11 +23,11 @@ import (
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
client "k8s.io/client-go/kubernetes"
"k8s.io/klog/v2" "k8s.io/klog/v2"
podresourcesapi "k8s.io/kubelet/pkg/apis/podresources/v1" podresourcesapi "k8s.io/kubelet/pkg/apis/podresources/v1"
"sigs.k8s.io/node-feature-discovery/pkg/apihelper"
"github.com/k8stopologyawareschedwg/noderesourcetopology-api/pkg/apis/topology/v1alpha2" "github.com/k8stopologyawareschedwg/noderesourcetopology-api/pkg/apis/topology/v1alpha2"
"github.com/k8stopologyawareschedwg/podfingerprint" "github.com/k8stopologyawareschedwg/podfingerprint"
) )
@ -35,16 +35,16 @@ import (
type PodResourcesScanner struct { type PodResourcesScanner struct {
namespace string namespace string
podResourceClient podresourcesapi.PodResourcesListerClient podResourceClient podresourcesapi.PodResourcesListerClient
apihelper apihelper.APIHelpers k8sClient client.Interface
podFingerprint bool podFingerprint bool
} }
// NewPodResourcesScanner creates a new ResourcesScanner instance // NewPodResourcesScanner creates a new ResourcesScanner instance
func NewPodResourcesScanner(namespace string, podResourceClient podresourcesapi.PodResourcesListerClient, kubeApihelper apihelper.APIHelpers, podFingerprint bool) (ResourcesScanner, error) { func NewPodResourcesScanner(namespace string, podResourceClient podresourcesapi.PodResourcesListerClient, k8sClient client.Interface, podFingerprint bool) (ResourcesScanner, error) {
resourcemonitorInstance := &PodResourcesScanner{ resourcemonitorInstance := &PodResourcesScanner{
namespace: namespace, namespace: namespace,
podResourceClient: podResourceClient, podResourceClient: podResourceClient,
apihelper: kubeApihelper, k8sClient: k8sClient,
podFingerprint: podFingerprint, podFingerprint: podFingerprint,
} }
if resourcemonitorInstance.namespace != "*" { if resourcemonitorInstance.namespace != "*" {
@ -58,11 +58,7 @@ func NewPodResourcesScanner(namespace string, podResourceClient podresourcesapi.
// isWatchable tells if the the given namespace should be watched. // isWatchable tells if the the given namespace should be watched.
func (resMon *PodResourcesScanner) isWatchable(podNamespace string, podName string, hasDevice bool) (bool, bool, error) { func (resMon *PodResourcesScanner) isWatchable(podNamespace string, podName string, hasDevice bool) (bool, bool, error) {
cli, err := resMon.apihelper.GetClient() pod, err := resMon.k8sClient.CoreV1().Pods(podNamespace).Get(context.TODO(), podName, metav1.GetOptions{})
if err != nil {
return false, false, err
}
pod, err := resMon.apihelper.GetPod(cli, podNamespace, podName)
if err != nil { if err != nil {
return false, false, err return false, false, err
} }

View file

@ -25,22 +25,16 @@ import (
"github.com/k8stopologyawareschedwg/podfingerprint" "github.com/k8stopologyawareschedwg/podfingerprint"
. "github.com/smartystreets/goconvey/convey" . "github.com/smartystreets/goconvey/convey"
"github.com/stretchr/testify/mock" "github.com/stretchr/testify/mock"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
k8sclient "k8s.io/client-go/kubernetes" fakeclient "k8s.io/client-go/kubernetes/fake"
v1 "k8s.io/kubelet/pkg/apis/podresources/v1" v1 "k8s.io/kubelet/pkg/apis/podresources/v1"
"sigs.k8s.io/node-feature-discovery/pkg/apihelper" mockpodres "sigs.k8s.io/node-feature-discovery/pkg/podres/mocks"
mockv1 "sigs.k8s.io/node-feature-discovery/pkg/podres/mocks"
) )
func TestPodScanner(t *testing.T) { func TestPodScanner(t *testing.T) {
var resScan ResourcesScanner
var err error
// PodFingerprint only depends on Name/Namespace of the pods running on a Node // PodFingerprint only depends on Name/Namespace of the pods running on a Node
// so we can precalculate the expected value // so we can precalculate the expected value
expectedFingerprintCompute := func(pods []*corev1.Pod) (string, error) { expectedFingerprintCompute := func(pods []*corev1.Pod) (string, error) {
@ -54,11 +48,11 @@ func TestPodScanner(t *testing.T) {
} }
Convey("When I scan for pod resources using fake client and no namespace", t, func() { Convey("When I scan for pod resources using fake client and no namespace", t, func() {
mockPodResClient := new(mockv1.PodResourcesListerClient) mockPodResClient := new(mockpodres.PodResourcesListerClient)
mockAPIHelper := new(apihelper.MockAPIHelpers)
mockClient := &k8sclient.Clientset{} fakeCli := fakeclient.NewSimpleClientset()
computePodFingerprint := true computePodFingerprint := true
resScan, err = NewPodResourcesScanner("*", mockPodResClient, mockAPIHelper, computePodFingerprint) resScan, err := NewPodResourcesScanner("*", mockPodResClient, fakeCli, computePodFingerprint)
Convey("Creating a Resources Scanner using a mock client", func() { Convey("Creating a Resources Scanner using a mock client", func() {
So(err, ShouldBeNil) So(err, ShouldBeNil)
@ -172,8 +166,9 @@ func TestPodScanner(t *testing.T) {
}, },
}, },
} }
mockAPIHelper.On("GetClient").Return(mockClient, nil)
mockAPIHelper.On("GetPod", mock.AnythingOfType("*kubernetes.Clientset"), "default", "test-pod-0").Return(pod, nil) fakeCli := fakeclient.NewSimpleClientset(pod)
resScan.(*PodResourcesScanner).k8sClient = fakeCli
res, err := resScan.Scan() res, err := resScan.Scan()
Convey("Error is nil", func() { Convey("Error is nil", func() {
@ -286,8 +281,9 @@ func TestPodScanner(t *testing.T) {
}, },
}, },
} }
mockAPIHelper.On("GetClient").Return(mockClient, nil)
mockAPIHelper.On("GetPod", mock.AnythingOfType("*kubernetes.Clientset"), "default", "test-pod-0").Return(pod, nil) fakeCli = fakeclient.NewSimpleClientset(pod)
resScan.(*PodResourcesScanner).k8sClient = fakeCli
res, err := resScan.Scan() res, err := resScan.Scan()
Convey("Error is nil", func() { Convey("Error is nil", func() {
@ -373,8 +369,8 @@ func TestPodScanner(t *testing.T) {
}, },
}, },
} }
mockAPIHelper.On("GetClient").Return(mockClient, nil) fakeCli = fakeclient.NewSimpleClientset(pod)
mockAPIHelper.On("GetPod", mock.AnythingOfType("*kubernetes.Clientset"), "default", "test-pod-0").Return(pod, nil) resScan.(*PodResourcesScanner).k8sClient = fakeCli
res, err := resScan.Scan() res, err := resScan.Scan()
Convey("Error is nil", func() { Convey("Error is nil", func() {
@ -463,8 +459,8 @@ func TestPodScanner(t *testing.T) {
}, },
}, },
} }
mockAPIHelper.On("GetClient").Return(mockClient, nil) fakeCli = fakeclient.NewSimpleClientset(pod)
mockAPIHelper.On("GetPod", mock.AnythingOfType("*kubernetes.Clientset"), "default", "test-pod-0").Return(pod, nil) resScan.(*PodResourcesScanner).k8sClient = fakeCli
res, err := resScan.Scan() res, err := resScan.Scan()
Convey("Error is nil", func() { Convey("Error is nil", func() {
@ -541,8 +537,8 @@ func TestPodScanner(t *testing.T) {
}, },
}, },
} }
mockAPIHelper.On("GetClient").Return(mockClient, nil) fakeCli = fakeclient.NewSimpleClientset(pod)
mockAPIHelper.On("GetPod", mock.AnythingOfType("*kubernetes.Clientset"), "default", "test-pod-0").Return(pod, nil) resScan.(*PodResourcesScanner).k8sClient = fakeCli
res, err := resScan.Scan() res, err := resScan.Scan()
Convey("Error is nil", func() { Convey("Error is nil", func() {
@ -633,8 +629,8 @@ func TestPodScanner(t *testing.T) {
}, },
}, },
} }
mockAPIHelper.On("GetClient").Return(mockClient, nil) fakeCli = fakeclient.NewSimpleClientset(pod)
mockAPIHelper.On("GetPod", mock.AnythingOfType("*kubernetes.Clientset"), "default", "test-pod-0").Return(pod, nil) resScan.(*PodResourcesScanner).k8sClient = fakeCli
res, err := resScan.Scan() res, err := resScan.Scan()
Convey("Error is nil", func() { Convey("Error is nil", func() {
@ -676,11 +672,10 @@ func TestPodScanner(t *testing.T) {
}) })
Convey("When I scan for pod resources using fake client and given namespace", t, func() { Convey("When I scan for pod resources using fake client and given namespace", t, func() {
mockPodResClient := new(mockv1.PodResourcesListerClient) mockPodResClient := new(mockpodres.PodResourcesListerClient)
mockAPIHelper := new(apihelper.MockAPIHelpers) fakeCli := fakeclient.NewSimpleClientset()
mockClient := &k8sclient.Clientset{}
computePodFingerprint := false computePodFingerprint := false
resScan, err = NewPodResourcesScanner("pod-res-test", mockPodResClient, mockAPIHelper, computePodFingerprint) resScan, err := NewPodResourcesScanner("pod-res-test", mockPodResClient, fakeCli, computePodFingerprint)
Convey("Creating a Resources Scanner using a mock client", func() { Convey("Creating a Resources Scanner using a mock client", func() {
So(err, ShouldBeNil) So(err, ShouldBeNil)
@ -752,12 +747,12 @@ func TestPodScanner(t *testing.T) {
Name: "test-cnt-0", Name: "test-cnt-0",
Resources: corev1.ResourceRequirements{ Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{ Requests: corev1.ResourceList{
corev1.ResourceCPU: *resource.NewQuantity(2, resource.DecimalSI), corev1.ResourceCPU: *resource.NewQuantity(1, resource.DecimalSI),
corev1.ResourceName("fake.io/resource"): *resource.NewQuantity(1, resource.DecimalSI), corev1.ResourceName("fake.io/resource"): *resource.NewQuantity(1, resource.DecimalSI),
corev1.ResourceMemory: *resource.NewQuantity(100, resource.DecimalSI), corev1.ResourceMemory: *resource.NewQuantity(100, resource.DecimalSI),
}, },
Limits: corev1.ResourceList{ Limits: corev1.ResourceList{
corev1.ResourceCPU: *resource.NewQuantity(2, resource.DecimalSI), corev1.ResourceCPU: *resource.NewQuantity(1, resource.DecimalSI),
corev1.ResourceName("fake.io/resource"): *resource.NewQuantity(1, resource.DecimalSI), corev1.ResourceName("fake.io/resource"): *resource.NewQuantity(1, resource.DecimalSI),
corev1.ResourceMemory: *resource.NewQuantity(100, resource.DecimalSI), corev1.ResourceMemory: *resource.NewQuantity(100, resource.DecimalSI),
}, },
@ -766,8 +761,8 @@ func TestPodScanner(t *testing.T) {
}, },
}, },
} }
mockAPIHelper.On("GetClient").Return(mockClient, nil) fakeCli = fakeclient.NewSimpleClientset(pod)
mockAPIHelper.On("GetPod", mock.AnythingOfType("*kubernetes.Clientset"), "default", "test-pod-0").Return(pod, nil) resScan.(*PodResourcesScanner).k8sClient = fakeCli
res, err := resScan.Scan() res, err := resScan.Scan()
Convey("Error is nil", func() { Convey("Error is nil", func() {
@ -831,8 +826,8 @@ func TestPodScanner(t *testing.T) {
}, },
}, },
} }
mockAPIHelper.On("GetClient").Return(mockClient, nil) fakeCli = fakeclient.NewSimpleClientset(pod)
mockAPIHelper.On("GetPod", mock.AnythingOfType("*kubernetes.Clientset"), "pod-res-test", "test-pod-0").Return(pod, nil) resScan.(*PodResourcesScanner).k8sClient = fakeCli
res, err := resScan.Scan() res, err := resScan.Scan()
Convey("Error is nil", func() { Convey("Error is nil", func() {
@ -911,8 +906,8 @@ func TestPodScanner(t *testing.T) {
}, },
}, },
} }
mockAPIHelper.On("GetClient").Return(mockClient, nil) fakeCli = fakeclient.NewSimpleClientset(pod)
mockAPIHelper.On("GetPod", mock.AnythingOfType("*kubernetes.Clientset"), "default", "test-pod-0").Return(pod, nil) resScan.(*PodResourcesScanner).k8sClient = fakeCli
res, err := resScan.Scan() res, err := resScan.Scan()
Convey("Error is nil", func() { Convey("Error is nil", func() {
@ -977,8 +972,8 @@ func TestPodScanner(t *testing.T) {
}, },
}, },
} }
mockAPIHelper.On("GetClient").Return(mockClient, nil) fakeCli = fakeclient.NewSimpleClientset(pod)
mockAPIHelper.On("GetPod", mock.AnythingOfType("*kubernetes.Clientset"), "default", "test-pod-0").Return(pod, nil) resScan.(*PodResourcesScanner).k8sClient = fakeCli
res, err := resScan.Scan() res, err := resScan.Scan()
Convey("Error is nil", func() { Convey("Error is nil", func() {
@ -1035,8 +1030,8 @@ func TestPodScanner(t *testing.T) {
}, },
}, },
} }
mockAPIHelper.On("GetClient").Return(mockClient, nil) fakeCli = fakeclient.NewSimpleClientset(pod)
mockAPIHelper.On("GetPod", mock.AnythingOfType("*kubernetes.Clientset"), "pod-res-test", "test-pod-0").Return(pod, nil) resScan.(*PodResourcesScanner).k8sClient = fakeCli
res, err := resScan.Scan() res, err := resScan.Scan()
Convey("Error is nil", func() { Convey("Error is nil", func() {
@ -1119,8 +1114,8 @@ func TestPodScanner(t *testing.T) {
}, },
}, },
} }
mockAPIHelper.On("GetClient").Return(mockClient, nil) fakeCli = fakeclient.NewSimpleClientset(pod)
mockAPIHelper.On("GetPod", mock.AnythingOfType("*kubernetes.Clientset"), "pod-res-test", "test-pod-0").Return(pod, nil) resScan.(*PodResourcesScanner).k8sClient = fakeCli
res, err := resScan.Scan() res, err := resScan.Scan()
Convey("Error is nil", func() { Convey("Error is nil", func() {