@@ -36,6 +36,7 @@ import (
3636
3737 grpcprom "github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus"
3838 corev1 "k8s.io/api/core/v1"
39+ apierrors "k8s.io/apimachinery/pkg/api/errors"
3940 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
4041 "k8s.io/apimachinery/pkg/types"
4142 k8stypes "k8s.io/apimachinery/pkg/types"
@@ -50,6 +51,11 @@ import (
5051 "k8s.io/mount-utils"
5152 "k8s.io/utils/ptr"
5253
54+ "k8s.io/apimachinery/pkg/runtime/schema"
55+ "k8s.io/client-go/metadata"
56+ "k8s.io/client-go/metadata/metadatainformer"
57+ "k8s.io/client-go/tools/cache"
58+
5359 consts "sigs.k8s.io/azuredisk-csi-driver/pkg/azureconstants"
5460 "sigs.k8s.io/azuredisk-csi-driver/pkg/azureutils"
5561 csicommon "sigs.k8s.io/azuredisk-csi-driver/pkg/csi-common"
@@ -156,6 +162,9 @@ type Driver struct {
156162 enableMigrationMonitor bool
157163 // whether to convert ReadWrite cachingMode to ReadOnly for intree PVs to avoid issues
158164 convertRWCachingModeForIntreePV bool
165+ nodeLister cache.GenericLister
166+ nodeInformerSynced cache.InformerSynced
167+ nodeInformerFactory metadatainformer.SharedInformerFactory
159168}
160169
161170// NewDriver Creates a NewCSIDriver object. Assumes vendor version is equal to driver version &
@@ -240,10 +249,17 @@ func NewDriver(options *DriverOptions) *Driver {
240249 userAgent := GetUserAgent (driver .Name , driver .customUserAgent , driver .userAgentSuffix )
241250 klog .V (2 ).Infof ("driver userAgent: %s" , userAgent )
242251
243- kubeClient , err := azureutils .GetKubeClient (options .Kubeconfig , options .KubeAPIQPS , options .KubeAPIBurst )
252+ kubeConfig , err := azureutils .GetKubeConfig (options .Kubeconfig , options .KubeAPIQPS , options .KubeAPIBurst )
244253 if err != nil {
245254 klog .Warningf ("get kubeconfig(%s) failed with error: %v" , options .Kubeconfig , err )
246255 }
256+ var kubeClient clientset.Interface
257+ if kubeConfig != nil {
258+ kubeClient , err = clientset .NewForConfig (kubeConfig )
259+ if err != nil {
260+ klog .Warningf ("get kubeclient failed with error: %v" , err )
261+ }
262+ }
247263 driver .kubeClient = kubeClient
248264
249265 cloud , err := azureutils .GetCloudProviderFromClient (context .Background (), kubeClient , driver .cloudConfigSecretName , driver .cloudConfigSecretNamespace ,
@@ -325,6 +341,23 @@ func NewDriver(options *DriverOptions) *Driver {
325341 }
326342 }
327343
344+ if kubeConfig != nil && driver .checkDiskCountForBatching && driver .NodeID == "" {
345+ // Create a metadata-only node informer to cache node labels locally (controller only)
346+ metadataClient , err := metadata .NewForConfig (kubeConfig )
347+ if err != nil {
348+ klog .Warningf ("failed to create metadata client: %v, node informer will not be used" , err )
349+ } else {
350+ driver .nodeInformerFactory = metadatainformer .NewSharedInformerFactory (metadataClient , 0 )
351+ nodeGVR := schema.GroupVersionResource {Group : "" , Version : "v1" , Resource : "nodes" }
352+ nodeInformer := driver .nodeInformerFactory .ForResource (nodeGVR )
353+ driver .nodeLister = nodeInformer .Lister ()
354+ driver .nodeInformerSynced = nodeInformer .Informer ().HasSynced
355+ if driver .diskController != nil {
356+ driver .diskController .nodeLister = driver .nodeLister
357+ }
358+ }
359+ }
360+
328361 driver .deviceHelper = optimization .NewSafeDeviceHelper ()
329362
330363 if driver .getPerfOptimizationEnabled () {
@@ -413,6 +446,19 @@ func (d *Driver) Run(ctx context.Context) error {
413446 csi .RegisterControllerServer (s , d )
414447 csi .RegisterNodeServer (s , d )
415448
449+ // Start the node informer if it was set up during driver initialization
450+ if d .nodeInformerFactory != nil {
451+ d .nodeInformerFactory .Start (ctx .Done ())
452+ syncCtx , syncCancel := context .WithTimeout (ctx , 30 * time .Second )
453+ defer syncCancel ()
454+ if ! cache .WaitForCacheSync (syncCtx .Done (), d .nodeInformerSynced ) {
455+ klog .Warningf ("metadata node informer cache has not synced yet, will continue to sync in background" )
456+ } else {
457+ klog .V (2 ).Infof ("metadata node informer cache synced successfully" )
458+ }
459+ klog .V (2 ).Infof ("started metadata node informer for GetNodeInfoFromLabels caching" )
460+ }
461+
416462 go func () {
417463 //graceful shutdown
418464 <- ctx .Done ()
@@ -422,6 +468,11 @@ func (d *Driver) Run(ctx context.Context) error {
422468 d .migrationMonitor .Stop ()
423469 }
424470
471+ // Shutdown node informer if it was started
472+ if d .nodeInformerFactory != nil {
473+ d .nodeInformerFactory .Shutdown ()
474+ }
475+
425476 s .GracefulStop ()
426477 }()
427478 // Driver d act as IdentityServer, ControllerServer and NodeServer
@@ -665,8 +716,38 @@ func (d *Driver) getUsedLunsFromNode(ctx context.Context, nodeName types.NodeNam
665716 return usedLuns , nil
666717}
667718
668- // getNodeInfoFromLabels get zone, instanceType from node labels
669- func getNodeInfoFromLabels (ctx context.Context , nodeName string , kubeClient clientset.Interface ) (string , string , error ) {
719+ // GetNodeInfoFromNodeLister gets zone, instanceType from node labels using the cached nodeLister.
720+ func GetNodeInfoFromNodeLister (nodeName string , nodeLister cache.GenericLister ) (string , string , error ) {
721+ if nodeLister == nil {
722+ return "" , "" , fmt .Errorf ("nodeLister is nil" )
723+ }
724+
725+ obj , err := nodeLister .Get (nodeName )
726+ if err != nil {
727+ if apierrors .IsNotFound (err ) {
728+ klog .V (4 ).Infof ("GetNodeInfoFromNodeLister: node(%s) not found in lister cache" , nodeName )
729+ return "" , "" , nil
730+ }
731+ return "" , "" , fmt .Errorf ("get node(%s) from lister failed: %v" , nodeName , err )
732+ }
733+
734+ pom , ok := obj .(* metav1.PartialObjectMetadata )
735+ if ! ok {
736+ return "" , "" , fmt .Errorf ("node(%s) from lister is not *metav1.PartialObjectMetadata" , nodeName )
737+ }
738+
739+ if len (pom .Labels ) == 0 {
740+ return "" , "" , fmt .Errorf ("node(%s) label is empty" , nodeName )
741+ }
742+
743+ zone := pom .Labels [consts .WellKnownTopologyKey ]
744+ instanceType := pom .Labels [consts .InstanceTypeKey ]
745+ klog .V (4 ).Infof ("GetNodeInfoFromNodeLister: node(%s): zone=%s, instanceType=%s" , nodeName , zone , instanceType )
746+ return zone , instanceType , nil
747+ }
748+
749+ // GetNodeInfoFromLabels gets zone, instanceType from node labels via the kubeClient API server.
750+ func GetNodeInfoFromLabels (ctx context.Context , nodeName string , kubeClient clientset.Interface ) (string , string , error ) {
670751 if kubeClient == nil || kubeClient .CoreV1 () == nil {
671752 return "" , "" , fmt .Errorf ("kubeClient is nil" )
672753 }
@@ -679,7 +760,11 @@ func getNodeInfoFromLabels(ctx context.Context, nodeName string, kubeClient clie
679760 if len (node .Labels ) == 0 {
680761 return "" , "" , fmt .Errorf ("node(%s) label is empty" , nodeName )
681762 }
682- return node .Labels [consts .WellKnownTopologyKey ], node .Labels [consts .InstanceTypeKey ], nil
763+
764+ zone := node .Labels [consts .WellKnownTopologyKey ]
765+ instanceType := node .Labels [consts .InstanceTypeKey ]
766+ klog .V (4 ).Infof ("GetNodeInfoFromLabels: node(%s) from API server: zone=%s, instanceType=%s" , nodeName , zone , instanceType )
767+ return zone , instanceType , nil
683768}
684769
685770// getDefaultDiskIOPSReadWrite according to requestGiB
0 commit comments