@@ -28,16 +28,17 @@ const hostPathRoot = "/proc/1/root"
2828
2929// BlockDeviceMetric represents enhanced block device metrics with accurate sector sizes
3030type BlockDeviceMetric struct {
31- Name string `avro:"name"`
32- NodeName string `avro:"node_name"`
33- NodeTemplate * string `avro:"node_template"`
34- Path string `avro:"path"`
35- SizeBytes * int64 `avro:"size_bytes"`
36- DiskType string `avro:"disk_type"` // HDD, SSD
37- PartitionOf string `avro:"partition_of"` // parent device for partitions
38- Holders []string `avro:"holders"` // devices using this device
39- IsVirtual bool `avro:"is_virtual"` // dm-* or md* devices
40- RaidLevel string `avro:"raid_level"` // raid0, raid1, raid5, etc
31+ Name string `avro:"name"`
32+ NodeName string `avro:"node_name"`
33+ NodeTemplate * string `avro:"node_template"`
34+ Path string `avro:"path"`
35+ SizeBytes * int64 `avro:"size_bytes"`
36+ DiskType string `avro:"disk_type"` // HDD, SSD
37+ PartitionOf string `avro:"partition_of"` // parent device for partitions
38+ Holders []string `avro:"holders"` // devices using this device
39+ IsVirtual bool `avro:"is_virtual"` // dm-* or md* devices
40+ RaidLevel string `avro:"raid_level"` // raid0, raid1, raid5, etc
41+ LVMInfo map [string ]string `avro:"lvm_info"` // LVM metadata for this device
4142
4243 ReadIOPS float64 `avro:"read_iops"`
4344 WriteIOPS float64 `avro:"write_iops"`
@@ -136,8 +137,8 @@ type storageMetricsState struct {
136137}
137138
138139type StorageInfoProvider interface {
139- BuildFilesystemMetrics (ctx context.Context , timestamp time.Time ) ([]FilesystemMetric , error )
140- BuildBlockDeviceMetrics (timestamp time.Time ) ([]BlockDeviceMetric , error )
140+ CollectFilesystemMetrics (ctx context.Context , timestamp time.Time ) ([]FilesystemMetric , error )
141+ CollectBlockDeviceMetrics (timestamp time.Time ) ([]BlockDeviceMetric , error )
141142 CollectNodeStatsSummary (ctx context.Context ) (* NodeStatsSummaryMetric , error )
142143 CollectPodVolumeMetrics (ctx context.Context ) ([]K8sPodVolumeMetric , error )
143144 CollectCloudVolumeMetrics (ctx context.Context ) ([]CloudVolumeMetric , error )
@@ -448,7 +449,7 @@ func (s *SysfsStorageInfoProvider) CollectCloudVolumeMetrics(ctx context.Context
448449 return metrics , nil
449450}
450451
451- func (s * SysfsStorageInfoProvider ) BuildFilesystemMetrics (ctx context.Context , timestamp time.Time ) ([]FilesystemMetric , error ) {
452+ func (s * SysfsStorageInfoProvider ) CollectFilesystemMetrics (ctx context.Context , timestamp time.Time ) ([]FilesystemMetric , error ) {
452453 // Read mount information from /proc/1/mountinfo
453454 mounts , err := readMountInfo ("/proc/1/mountinfo" )
454455 if err != nil {
@@ -621,7 +622,7 @@ func (s *SysfsStorageInfoProvider) getLVMDMDevice(device string) []string {
621622 }
622623}
623624
624- func (s * SysfsStorageInfoProvider ) BuildBlockDeviceMetrics (timestamp time.Time ) ([]BlockDeviceMetric , error ) {
625+ func (s * SysfsStorageInfoProvider ) CollectBlockDeviceMetrics (timestamp time.Time ) ([]BlockDeviceMetric , error ) {
625626 // Read stats from /proc/diskstats
626627 diskStats , err := readProcDiskStats ()
627628 if err != nil {
@@ -662,6 +663,7 @@ func (s *SysfsStorageInfoProvider) buildBlockDeviceMetric(blockName string, stat
662663 holders := s .getHolders (blockName )
663664 raidLevel := s .getRaidLevel (blockName )
664665 logicalSectorSize := s .getLogicalSectorSize (blockName )
666+ lvmInfo := s .getLVMInfo (blockName )
665667
666668 diskSize , err := s .getDeviceSize (blockName )
667669 if err != nil {
@@ -684,6 +686,7 @@ func (s *SysfsStorageInfoProvider) buildBlockDeviceMetric(blockName string, stat
684686 Holders : holders ,
685687 IsVirtual : isVirtualDevice (blockName ),
686688 RaidLevel : raidLevel ,
689+ LVMInfo : lvmInfo ,
687690 Timestamp : timestamp ,
688691 InFlightRequests : safeUint64ToInt64 (stats .InFlight ),
689692
@@ -930,6 +933,74 @@ func (s *SysfsStorageInfoProvider) getHolders(deviceName string) []string {
930933 return holders
931934}
932935
936+ // getLVMInfo returns LVM metadata (dm_name, lv_name, vg_name) for device-mapper devices
937+ func (s * SysfsStorageInfoProvider ) getLVMInfo (deviceName string ) map [string ]string {
938+ if ! strings .HasPrefix (deviceName , "dm-" ) {
939+ return nil
940+ }
941+
942+ requiredTags := map [string ]string {
943+ "DM_NAME" : "dm_name" ,
944+ "DM_LV_NAME" : "lv_name" ,
945+ "DM_VG_NAME" : "vg_name" ,
946+ }
947+
948+ // Read device major:minor from /sys/block/<device>/dev
949+ devPath := filepath .Join (s .sysBlockPrefix , "sys" , "block" , deviceName , "dev" )
950+ devData , err := os .ReadFile (devPath )
951+ if err != nil {
952+ return nil
953+ }
954+
955+ majorMinor := strings .TrimSpace (string (devData ))
956+ if majorMinor == "" {
957+ return nil
958+ }
959+
960+ // Open udev database file from host: /proc/1/root/run/udev/data/b<major>:<minor>
961+ udevDBPath := filepath .Join (s .hostRootPath , "run" , "udev" , "data" , "b" + majorMinor )
962+ udevDBFile , err := os .Open (udevDBPath )
963+ if err != nil {
964+ return nil
965+ }
966+ defer udevDBFile .Close ()
967+
968+ tags := make (map [string ]string )
969+
970+ scanner := bufio .NewScanner (udevDBFile )
971+ for scanner .Scan () {
972+ line := scanner .Text ()
973+
974+ // Only process device property lines (E:)
975+ if ! strings .HasPrefix (line , "E:" ) {
976+ continue
977+ }
978+ property := strings .TrimPrefix (line , "E:" )
979+
980+ parts := strings .SplitN (property , "=" , 2 )
981+ if len (parts ) != 2 {
982+ continue
983+ }
984+
985+ key , value := parts [0 ], parts [1 ]
986+ if name , ok := requiredTags [key ]; ok && value != "" {
987+ tags [name ] = value
988+ }
989+
990+ // Exit early if desired tags are found
991+ if len (tags ) == len (requiredTags ) {
992+ break
993+ }
994+ }
995+
996+ if err := scanner .Err (); err != nil {
997+ s .log .Errorf ("failed to scan udev database for device %s: %v" , deviceName , err )
998+ return nil
999+ }
1000+
1001+ return tags
1002+ }
1003+
9331004func safeUint64ToInt64 (val uint64 ) int64 {
9341005 if val > math .MaxInt64 {
9351006 return math .MaxInt64
0 commit comments