raiddetails.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. package raid
  2. import (
  3. "fmt"
  4. "os/exec"
  5. "strconv"
  6. "strings"
  7. "time"
  8. )
  9. // RAIDInfo represents information about a RAID array.
  10. type RAIDInfo struct {
  11. DevicePath string
  12. Version string
  13. CreationTime time.Time
  14. RaidLevel string
  15. ArraySize int
  16. UsedDevSize int
  17. RaidDevices int
  18. TotalDevices int
  19. Persistence string
  20. UpdateTime time.Time
  21. State string
  22. ActiveDevices int
  23. WorkingDevices int
  24. FailedDevices int
  25. SpareDevices int
  26. Consistency string
  27. RebuildStatus string
  28. Name string
  29. UUID string
  30. Events int
  31. DeviceInfo []DeviceInfo
  32. }
  33. // DeviceInfo represents information about a device in a RAID array.
  34. type DeviceInfo struct {
  35. State []string
  36. DevicePath string
  37. RaidDevice int //Sequence of the raid device?
  38. }
  39. // GetRAIDInfo retrieves information about a RAID array using the mdadm command.
  40. // arrayName must be in full path (e.g. /dev/md0)
  41. func (m *Manager) GetRAIDInfo(arrayName string) (*RAIDInfo, error) {
  42. cmd := exec.Command("sudo", "mdadm", "--detail", arrayName)
  43. output, err := cmd.Output()
  44. if err != nil {
  45. return nil, fmt.Errorf("error running mdadm command: %v", err)
  46. }
  47. info := parseRAIDInfo(string(output))
  48. //Fill in the device path so other service can use it more easily
  49. info.DevicePath = arrayName
  50. return info, nil
  51. }
  52. // parseRAIDInfo parses the output of mdadm --detail command and returns the RAIDInfo struct.
  53. func parseRAIDInfo(output string) *RAIDInfo {
  54. lines := strings.Split(output, "\n")
  55. raidInfo := &RAIDInfo{}
  56. for _, line := range lines {
  57. fields := strings.Fields(line)
  58. if len(fields) >= 2 {
  59. switch fields[0] {
  60. case "Version":
  61. raidInfo.Version = fields[2]
  62. case "Creation":
  63. creationTimeStr := strings.Join(fields[3:], " ")
  64. creationTime, _ := time.Parse(time.ANSIC, creationTimeStr)
  65. raidInfo.CreationTime = creationTime
  66. case "Raid":
  67. if fields[1] == "Level" {
  68. //Raid Level
  69. raidInfo.RaidLevel = fields[3]
  70. } else if fields[1] == "Devices" {
  71. raidInfo.RaidDevices, _ = strconv.Atoi(fields[3])
  72. }
  73. case "Array":
  74. raidInfo.ArraySize, _ = strconv.Atoi(fields[3])
  75. case "Used":
  76. raidInfo.UsedDevSize, _ = strconv.Atoi(fields[4])
  77. case "Total":
  78. raidInfo.TotalDevices, _ = strconv.Atoi(fields[3])
  79. case "Persistence":
  80. raidInfo.Persistence = strings.Join(fields[2:], " ")
  81. case "Update":
  82. updateTimeStr := strings.Join(fields[3:], " ")
  83. updateTime, _ := time.Parse(time.ANSIC, updateTimeStr)
  84. raidInfo.UpdateTime = updateTime
  85. case "State":
  86. raidInfo.State = strings.Join(fields[2:], " ")
  87. case "Active":
  88. raidInfo.ActiveDevices, _ = strconv.Atoi(fields[3])
  89. case "Working":
  90. raidInfo.WorkingDevices, _ = strconv.Atoi(fields[3])
  91. case "Failed":
  92. raidInfo.FailedDevices, _ = strconv.Atoi(fields[3])
  93. case "Spare":
  94. raidInfo.SpareDevices, _ = strconv.Atoi(fields[3])
  95. case "Consistency":
  96. raidInfo.Consistency = strings.Join(fields[3:], " ")
  97. case "Rebuild":
  98. raidInfo.RebuildStatus = strings.Join(fields[3:], " ")
  99. case "Name":
  100. raidInfo.Name = strings.Join(fields[2:], " ")
  101. case "UUID":
  102. raidInfo.UUID = fields[2]
  103. case "Events":
  104. raidInfo.Events, _ = strconv.Atoi(fields[2])
  105. default:
  106. if len(fields) >= 5 && fields[0] != "Number" {
  107. deviceInfo := DeviceInfo{}
  108. if len(fields) > 3 {
  109. rdNo, err := strconv.Atoi(fields[3])
  110. if err != nil {
  111. rdNo = -1
  112. }
  113. deviceInfo.RaidDevice = rdNo
  114. }
  115. if len(fields) > 5 {
  116. //Only active disks have fields > 5, e.g.
  117. // 0 8 16 0 active sync /dev/sdb
  118. deviceInfo.State = fields[4 : len(fields)-1]
  119. deviceInfo.DevicePath = fields[len(fields)-1]
  120. } else {
  121. //Failed disk, e.g.
  122. // - 0 0 1 removed
  123. deviceInfo.State = fields[4:]
  124. //TODO: Add custom tags
  125. }
  126. raidInfo.DeviceInfo = append(raidInfo.DeviceInfo, deviceInfo)
  127. }
  128. }
  129. }
  130. }
  131. return raidInfo
  132. }
  133. // PrettyPrintRAIDInfo pretty prints the RAIDInfo struct.
  134. func (info *RAIDInfo) PrettyPrintRAIDInfo() {
  135. fmt.Println("RAID Array Information:")
  136. fmt.Printf(" Version: %s\n", info.Version)
  137. fmt.Printf(" Creation Time: %s\n", info.CreationTime.Format("Mon Jan 02 15:04:05 2006"))
  138. fmt.Printf(" Raid Level: %s\n", info.RaidLevel)
  139. fmt.Printf(" Array Size: %d\n", info.ArraySize)
  140. fmt.Printf(" Used Dev Size: %d\n", info.UsedDevSize)
  141. fmt.Printf(" Raid Devices: %d\n", info.RaidDevices)
  142. fmt.Printf(" Total Devices: %d\n", info.TotalDevices)
  143. fmt.Printf(" Persistence: %s\n", info.Persistence)
  144. fmt.Printf(" Update Time: %s\n", info.UpdateTime.Format("Mon Jan 02 15:04:05 2006"))
  145. fmt.Printf(" State: %s\n", info.State)
  146. fmt.Printf(" Active Devices: %d\n", info.ActiveDevices)
  147. fmt.Printf(" Working Devices: %d\n", info.WorkingDevices)
  148. fmt.Printf(" Failed Devices: %d\n", info.FailedDevices)
  149. fmt.Printf(" Spare Devices: %d\n", info.SpareDevices)
  150. fmt.Printf(" Consistency Policy: %s\n", info.Consistency)
  151. fmt.Printf(" Name: %s\n", info.Name)
  152. fmt.Printf(" UUID: %s\n", info.UUID)
  153. fmt.Printf(" Events: %d\n", info.Events)
  154. fmt.Println("\nDevice Information:")
  155. fmt.Printf("%s %s\n", "State", "DevicePath")
  156. for _, device := range info.DeviceInfo {
  157. fmt.Printf("%s %s\n", strings.Join(device.State, ","), device.DevicePath)
  158. }
  159. }