Skip to content
This repository was archived by the owner on May 6, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions pkg/driver/dra_hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ func (np *NetworkDriver) PublishResources(ctx context.Context) {
err := np.draPlugin.PublishResources(ctx, resources)
if err != nil {
klog.Error(err, "unexpected error trying to publish resources")
} else {
lastPublishedTime.SetToCurrentTime()
}
case <-ctx.Done():
klog.Error(ctx.Err(), "context canceled")
Expand Down
43 changes: 41 additions & 2 deletions pkg/driver/dra_hooks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,17 @@ package driver

import (
"context"
"fmt"
"strings"
"testing"

"github.com/google/dranet/pkg/apis"
"github.com/google/dranet/pkg/inventory"
"github.com/prometheus/client_golang/prometheus/testutil"
resourcev1 "k8s.io/api/resource/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/dynamic-resource-allocation/kubeletplugin"

)

func TestPublishResourcesPrometheusMetrics(t *testing.T) {
Expand Down Expand Up @@ -142,7 +143,7 @@ func TestPrepareResourceClaimsMetrics(t *testing.T) {
draPluginRequestsLatencySeconds.Reset()

np := &NetworkDriver{
netdb: inventory.New(),
netdb: newFakeInventoryDB(),
driverName: "test.driver",
}

Expand Down Expand Up @@ -239,3 +240,41 @@ func TestUnprepareResourceClaimsMetrics(t *testing.T) {
}
})
}

func TestPublishResourcesMetrics(t *testing.T) {
ctx, cancel := context.WithCancel(t.Context())
defer cancel()

fakeDraPlugin := newFakePluginHelper()
fakeNetDB := newFakeInventoryDB()

np := &NetworkDriver{
draPlugin: fakeDraPlugin,
netdb: fakeNetDB,
nodeName: "test-node",
}

go np.PublishResources(ctx)

t.Run("Success", func(t *testing.T) {
lastPublishedTime.Set(0)
fakeNetDB.resources <- []resourcev1.Device{}
<-fakeDraPlugin.publishCalled

if testutil.ToFloat64(lastPublishedTime) == 0 {
t.Errorf("lastPublishedTime should have been updated, but it is 0")
}
})

t.Run("Failure", func(t *testing.T) {
lastPublishedTime.Set(0)
fakeDraPlugin.publishErr = fmt.Errorf("mock publish error")
fakeNetDB.resources <- []resourcev1.Device{}
<-fakeDraPlugin.publishCalled

if testutil.ToFloat64(lastPublishedTime) != 0 {
t.Errorf("lastPublishedTime should not have been updated, but it is %f", testutil.ToFloat64(lastPublishedTime))
}
})
}

24 changes: 22 additions & 2 deletions pkg/driver/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,13 @@ import (
"github.com/containerd/nri/pkg/stub"
"github.com/vishvananda/netlink"

resourceapi "k8s.io/api/resource/v1"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/kubernetes"
"k8s.io/dynamic-resource-allocation/kubeletplugin"
"k8s.io/dynamic-resource-allocation/resourceslice"
"k8s.io/klog/v2"
registerapi "k8s.io/kubelet/pkg/apis/pluginregistration/v1"
)

const (
Expand All @@ -46,6 +49,23 @@ const (
maxAttempts = 5
)

Comment thread
gauravkghildiyal marked this conversation as resolved.
// This interface is our internal contract for the behavior we need from a *kubeletplugin.Helper, created specifically so we can fake it in tests.
type pluginHelper interface {
PublishResources(context.Context, resourceslice.DriverResources) error
Stop()
RegistrationStatus() *registerapi.RegistrationStatus
}

// This interface is our internal contract for the behavior we need from a *inventory.DB, created specifically so we can fake it in tests.
type inventoryDB interface {
Run(context.Context) error
GetResources(context.Context) <-chan []resourceapi.Device
GetNetInterfaceName(string) (string, error)
AddPodNetNs(podKey string, netNs string)
RemovePodNetNs(podKey string)
GetPodNetNs(podKey string) (netNs string)
}

// WithFilter
func WithFilter(filter cel.Program) Option {
return func(o *NetworkDriver) {
Expand All @@ -57,11 +77,11 @@ type NetworkDriver struct {
driverName string
nodeName string
kubeClient kubernetes.Interface
draPlugin *kubeletplugin.Helper
draPlugin pluginHelper
nriPlugin stub.Stub

// contains the host interfaces
netdb *inventory.DB
netdb inventoryDB
celProgram cel.Program

// Cache the rdma shared mode state
Expand Down
67 changes: 67 additions & 0 deletions pkg/driver/driver_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package driver

import (
"context"
resourcev1 "k8s.io/api/resource/v1"
"k8s.io/dynamic-resource-allocation/resourceslice"
registerapi "k8s.io/kubelet/pkg/apis/pluginregistration/v1"
)

// fakeDraPlugin is a mock implementation of the pluginHelper interface for testing.
type fakePluginHelper struct {
publishErr error
publishCalled chan struct{}
registrationStatus *registerapi.RegistrationStatus
}

func newFakePluginHelper() *fakePluginHelper {
return &fakePluginHelper{
publishCalled: make(chan struct{}, 1),
}
}

func (m *fakePluginHelper) PublishResources(_ context.Context, _ resourceslice.DriverResources) error {
if m.publishCalled != nil {
m.publishCalled <- struct{}{}
}
return m.publishErr
}

func (m *fakePluginHelper) Stop() {}

func (m *fakePluginHelper) RegistrationStatus() *registerapi.RegistrationStatus {
return m.registrationStatus
}

// mockNetDB is a mock implementation of the inventoryDB interface for testing.
type fakeInventoryDB struct {
resources chan []resourcev1.Device
podNetNs map[string]string
}

func newFakeInventoryDB() *fakeInventoryDB {
return &fakeInventoryDB{
resources: make(chan []resourcev1.Device, 1),
podNetNs: make(map[string]string),
}
}

func (m *fakeInventoryDB) Run(_ context.Context) error { return nil }

func (m *fakeInventoryDB) GetResources(_ context.Context) <-chan []resourcev1.Device {
return m.resources
}

func (m *fakeInventoryDB) GetNetInterfaceName(_ string) (string, error) { return "", nil }

func (m *fakeInventoryDB) AddPodNetNs(podKey string, netNs string) {
m.podNetNs[podKey] = netNs
}

func (m *fakeInventoryDB) RemovePodNetNs(podKey string) {
delete(m.podNetNs, podKey)
}

func (m *fakeInventoryDB) GetPodNetNs(podKey string) string {
return m.podNetNs[podKey]
}
8 changes: 7 additions & 1 deletion pkg/driver/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ func registerMetrics() {
prometheus.MustRegister(nriPluginRequestsTotal)
prometheus.MustRegister(nriPluginRequestsLatencySeconds)
prometheus.MustRegister(publishedDevicesTotal)
prometheus.MustRegister(lastPublishedTime)
})
}

Expand Down Expand Up @@ -79,5 +80,10 @@ var (
Name: "published_devices_total",
Help: "Total number of published devices.",
}, []string{"feature"})
lastPublishedTime = prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: "dranet",
Subsystem: "driver",
Name: "last_published_time_seconds",
Help: "The timestamp of the last successful resource publication.",
})
)

Loading