disk.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. package node
  2. import (
  3. "io/ioutil"
  4. "k8s.io/klog/v2"
  5. "path"
  6. "regexp"
  7. "strconv"
  8. "strings"
  9. )
  10. var blockDevice = regexp.MustCompile(`^(dm-\d+|(s|h|xv|v)d[a-z]|md\d+|nvme\d+n\d+|rbd\d+)`)
  11. type DevStat struct {
  12. Name string
  13. MajorMinor string
  14. ReadOps float64
  15. WriteOps float64
  16. BytesRead float64
  17. BytesWritten float64
  18. ReadTimeSeconds float64
  19. WriteTimeSeconds float64
  20. IoTimeSeconds float64
  21. }
  22. type Disks struct {
  23. byMajorMinor map[string]DevStat
  24. }
  25. func (disks *Disks) BlockDevices() []DevStat {
  26. var res []DevStat
  27. for _, d := range disks.byMajorMinor {
  28. groups := blockDevice.FindStringSubmatch(d.Name)
  29. if len(groups) < 2 {
  30. continue
  31. }
  32. if groups[1] == d.Name {
  33. res = append(res, d)
  34. }
  35. }
  36. return res
  37. }
  38. func (disks *Disks) GetParentBlockDevice(majorMinor string) *DevStat {
  39. dev, ok := disks.byMajorMinor[majorMinor]
  40. if !ok {
  41. return nil
  42. }
  43. groups := blockDevice.FindStringSubmatch(dev.Name)
  44. if len(groups) < 2 {
  45. return nil
  46. }
  47. parentName := groups[1]
  48. for _, d := range disks.byMajorMinor {
  49. if d.Name == parentName {
  50. return &d
  51. }
  52. }
  53. return nil
  54. }
  55. func GetDisks() (*Disks, error) {
  56. data, err := ioutil.ReadFile(path.Join(procRoot, "diskstats"))
  57. if err != nil {
  58. return nil, err
  59. }
  60. disks := &Disks{
  61. byMajorMinor: map[string]DevStat{},
  62. }
  63. for _, line := range strings.Split(string(data), "\n") {
  64. fields := strings.Fields(line)
  65. if len(fields) < 14 {
  66. continue
  67. }
  68. deviceName := fields[2]
  69. values, err := parseFloats(fields[3:])
  70. if err != nil {
  71. klog.Warningf(`invalid diskstats line "%s": %s`, line, err)
  72. continue
  73. }
  74. majorMinor := fields[0] + ":" + fields[1]
  75. disks.byMajorMinor[majorMinor] = DevStat{
  76. Name: deviceName,
  77. MajorMinor: majorMinor,
  78. ReadOps: values[0],
  79. BytesRead: values[2] * 512,
  80. ReadTimeSeconds: values[3] / 1000,
  81. WriteOps: values[4],
  82. BytesWritten: values[6] * 512,
  83. WriteTimeSeconds: values[7] / 1000,
  84. IoTimeSeconds: values[9] / 1000,
  85. }
  86. }
  87. return disks, nil
  88. }
  89. func parseFloats(input []string) ([]float64, error) {
  90. res := make([]float64, len(input))
  91. for i, strValue := range input {
  92. v, err := strconv.ParseFloat(strValue, 64)
  93. if err != nil {
  94. return nil, err
  95. }
  96. res[i] = v
  97. }
  98. return res, nil
  99. }