@@ -31,6 +31,8 @@ import (
3131
3232 csi "github.com/container-storage-interface/spec/lib/go/csi"
3333
34+ "k8s.io/client-go/kubernetes"
35+ "k8s.io/client-go/rest"
3436 "k8s.io/klog/v2"
3537 "k8s.io/mount-utils"
3638
@@ -101,7 +103,12 @@ const (
101103 // doc https://cloud.google.com/compute/docs/memory-optimized-machines#x4_disks
102104 x4HyperdiskLimit int64 = 39
103105 // doc https://cloud.google.com/compute/docs/accelerator-optimized-machines#a4-disks
104- a4HyperdiskLimit int64 = 127
106+ a4HyperdiskLimit int64 = 127
107+ // doc https://cloud.google.com/compute/docs/storage-optimized-machines#z3_disks
108+ // doc https://cloud.google.com/compute/docs/accelerator-optimized-machines#a3-disks
109+ gen3HyperdiskLimit int64 = 31
110+ // doc https://cloud.google.com/compute/docs/compute-optimized-machines#h3_disks
111+ h3HyperdiskLimit int64 = 7 // Use limit for Hyperdisk Balanced
105112 defaultLinuxFsType = "ext4"
106113 defaultWindowsFsType = "ntfs"
107114 fsTypeExt3 = "ext3"
@@ -571,7 +578,7 @@ func (ns *GCENodeServer) NodeGetInfo(ctx context.Context, req *csi.NodeGetInfoRe
571578
572579 nodeID := common .CreateNodeID (ns .MetadataService .GetProject (), ns .MetadataService .GetZone (), ns .MetadataService .GetName ())
573580
574- volumeLimits , err := ns .GetVolumeLimits ()
581+ volumeLimits , err := ns .GetVolumeLimits (ctx )
575582 if err != nil {
576583 klog .Errorf ("GetVolumeLimits failed: %v" , err .Error ())
577584 }
@@ -731,7 +738,7 @@ func (ns *GCENodeServer) NodeExpandVolume(ctx context.Context, req *csi.NodeExpa
731738 }, nil
732739}
733740
734- func (ns * GCENodeServer ) GetVolumeLimits () (int64 , error ) {
741+ func (ns * GCENodeServer ) GetVolumeLimits (ctx context. Context ) (int64 , error ) {
735742 // Machine-type format: n1-type-CPUS or custom-CPUS-RAM or f1/g1-type
736743 machineType := ns .MetadataService .GetMachineType ()
737744
@@ -741,6 +748,22 @@ func (ns *GCENodeServer) GetVolumeLimits() (int64, error) {
741748 return volumeLimitSmall , nil
742749 }
743750 }
751+
752+ // Get attach limit override from label
753+ attachLimitOverride , err := GetAttachLimitsOverrideFromNodeLabel (ctx , ns .MetadataService .GetName ())
754+ if err == nil && attachLimitOverride > 0 && attachLimitOverride < 128 {
755+ return attachLimitOverride , nil
756+ } else {
757+ // If there is an error or the range is not valid, still proceed to get defaults for the machine type
758+ if err != nil {
759+ klog .Warningf ("using default value due to err getting node-restriction.kubernetes.io/gke-volume-attach-limit-override: %v" , err )
760+ }
761+ if attachLimitOverride != 0 {
762+ klog .Warningf ("using default value due to invalid node-restriction.kubernetes.io/gke-volume-attach-limit-override: %d" , attachLimitOverride )
763+ }
764+ }
765+
766+ // Process gen4 machine attach limits
744767 gen4MachineTypesPrefix := []string {"c4a-" , "c4-" , "n4-" }
745768 for _ , gen4Prefix := range gen4MachineTypesPrefix {
746769 if strings .HasPrefix (machineType , gen4Prefix ) {
@@ -760,5 +783,59 @@ func (ns *GCENodeServer) GetVolumeLimits() (int64, error) {
760783 }
761784 }
762785
786+ // Process gen3 machine attach limits
787+ gen3MachineTypesPrefix := []string {"c3-" , "c3d-" }
788+ for _ , gen3Prefix := range gen3MachineTypesPrefix {
789+ if strings .HasPrefix (machineType , gen3Prefix ) {
790+ cpus , err := common .ExtractCPUFromMachineType (machineType )
791+ if err != nil {
792+ return volumeLimitSmall , err
793+ }
794+ if cpus <= 8 || strings .Contains (machineType , "metal" ) {
795+ return volumeLimitSmall , nil
796+ }
797+ return gen3HyperdiskLimit , nil
798+
799+ }
800+ if strings .HasPrefix (machineType , "z3-" ) {
801+ return gen3HyperdiskLimit , nil
802+ }
803+ if strings .HasPrefix (machineType , "h3-" ) {
804+ return h3HyperdiskLimit , nil
805+ }
806+ if strings .HasPrefix (machineType , "a3-" ) {
807+ if machineType == "a3-ultragpu-8g" {
808+ return volumeLimitBig , nil
809+ } else {
810+ return gen3HyperdiskLimit , nil
811+ }
812+ }
813+
814+ }
815+
763816 return volumeLimitBig , nil
764817}
818+
819+ func GetAttachLimitsOverrideFromNodeLabel (ctx context.Context , nodeName string ) (int64 , error ) {
820+ cfg , err := rest .InClusterConfig ()
821+ if err != nil {
822+ return 0 , err
823+ }
824+ kubeClient , err := kubernetes .NewForConfig (cfg )
825+ if err != nil {
826+ return 0 , err
827+ }
828+ node , err := getNodeWithRetry (ctx , kubeClient , nodeName )
829+ if err != nil {
830+ return 0 , err
831+ }
832+ if val , found := node .GetLabels ()[fmt .Sprintf (common .NodeRestrictionLabelPrefix , common .AttachLimitOverrideLabel )]; found {
833+ attachLimitOverrideForNode , err := strconv .ParseInt (val , 10 , 64 )
834+ if err != nil {
835+ return 0 , fmt .Errorf ("error getting attach limit override from node label: %v" , err )
836+ }
837+ klog .V (4 ).Infof ("attach limit override for the node: %v" , attachLimitOverrideForNode )
838+ return attachLimitOverrideForNode , nil
839+ }
840+ return 0 , nil
841+ }
0 commit comments