mdadmConf.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. package raid
  2. import (
  3. "fmt"
  4. "log"
  5. "os"
  6. "os/exec"
  7. "strings"
  8. "imuslab.com/arozos/mod/utils"
  9. )
  10. /*
  11. mdadmConf.go
  12. This package handles the config modification and update for
  13. the mdadm module
  14. */
  15. // Updates the mdadm configuration file with the details of RAID arrays
  16. // so the RAID drive will still be seen after a reboot (hopefully)
  17. func (m *Manager) UpdateMDADMConfig() error {
  18. cmdMdadm := exec.Command("sudo", "mdadm", "--detail", "--scan", "--verbose")
  19. // Run the command and capture its output
  20. output, err := cmdMdadm.Output()
  21. if err != nil {
  22. return fmt.Errorf("error running mdadm command: %v", err)
  23. }
  24. //Load the config from system
  25. currentConfigBytes, err := os.ReadFile("/etc/mdadm/mdadm.conf")
  26. if err != nil {
  27. return fmt.Errorf("unable to open mdadm.conf: " + err.Error())
  28. }
  29. currentConf := string(currentConfigBytes)
  30. //Check if the current config already contains the setting
  31. newConfigLines := []string{}
  32. uuidsInNewConfig := []string{}
  33. arrayConfigs := strings.TrimSpace(string(output))
  34. lines := strings.Split(arrayConfigs, "ARRAY")
  35. for _, line := range lines {
  36. //For each line, you should have something like this
  37. //ARRAY /dev/md0 metadata=1.2 name=debian:0 UUID=cbc11a2b:fbd42653:99c1340b:9c4962fb
  38. // devices=/dev/sdb,/dev/sdc
  39. //Building structure for RAID Config Record
  40. line = strings.ReplaceAll(line, "\n", " ")
  41. fields := strings.Fields(line)
  42. if len(fields) < 5 {
  43. continue
  44. }
  45. poolUUID := strings.TrimPrefix(fields[3], "UUID=")
  46. uuidsInNewConfig = append(uuidsInNewConfig, poolUUID)
  47. //Check if this uuid already in the config file
  48. if strings.Contains(currentConf, poolUUID) {
  49. continue
  50. }
  51. //This config not exists in the settings. Add it to append lines
  52. log.Println("[RAID] Adding " + fields[0] + " (UUID=" + poolUUID + ") into mdadm config")
  53. settingLine := "ARRAY " + strings.Join(fields, " ")
  54. newConfigLines = append(newConfigLines, settingLine)
  55. }
  56. originalConfigLines := strings.Split(strings.TrimSpace(currentConf), "\n")
  57. poolUUIDToBeRemoved := []string{}
  58. for _, line := range originalConfigLines {
  59. lineFields := strings.Fields(line)
  60. for _, thisField := range lineFields {
  61. if strings.HasPrefix(thisField, "UUID=") {
  62. //This is the UUID of this array. Check if it still exists in new storage config
  63. thisPoolUUID := strings.TrimPrefix(thisField, "UUID=")
  64. existsInNewConfig := utils.StringInArray(uuidsInNewConfig, thisPoolUUID)
  65. if !existsInNewConfig {
  66. //Label this UUID to be removed
  67. poolUUIDToBeRemoved = append(poolUUIDToBeRemoved, thisPoolUUID)
  68. }
  69. //Skip scanning the remaining fields of this RAID pool
  70. break
  71. }
  72. }
  73. }
  74. if len(poolUUIDToBeRemoved) > 0 {
  75. //Remove the old UUIDs from config
  76. for _, volumeUUID := range poolUUIDToBeRemoved {
  77. err = m.RemoveVolumeFromMDADMConfig(volumeUUID)
  78. if err != nil {
  79. log.Println("[RAID] Error when trying to remove old RAID volume from config: " + err.Error())
  80. return err
  81. } else {
  82. log.Println("[RAID] RAID volume " + volumeUUID + " removed from config file")
  83. }
  84. }
  85. }
  86. if len(newConfigLines) == 0 {
  87. //Nothing to write
  88. log.Println("[RAID] Nothing to write. Skipping mdadm config update.")
  89. return nil
  90. }
  91. // Construct the bash command to append the line to mdadm.conf using echo and tee
  92. for _, configLine := range newConfigLines {
  93. cmd := exec.Command("bash", "-c", fmt.Sprintf(`echo "%s" | sudo tee -a /etc/mdadm/mdadm.conf`, configLine))
  94. // Run the command
  95. err := cmd.Run()
  96. if err != nil {
  97. return fmt.Errorf("error injecting line into mdadm.conf: %v", err)
  98. }
  99. }
  100. return nil
  101. }
  102. // Removes a RAID volume from the mdadm configuration file given its volume UUID.
  103. // Note that this only remove a single line of config. If your line consists of multiple lines
  104. // you might need to remove it manually
  105. func (m *Manager) RemoveVolumeFromMDADMConfig(volumeUUID string) error {
  106. // Construct the sed command to remove the line containing the volume UUID from mdadm.conf
  107. sedCommand := fmt.Sprintf(`sudo sed -i '/UUID=%s/d' /etc/mdadm/mdadm.conf`, volumeUUID)
  108. // Execute the sed command
  109. cmd := exec.Command("bash", "-c", sedCommand)
  110. err := cmd.Run()
  111. if err != nil {
  112. return fmt.Errorf("error removing volume from mdadm.conf: %v", err)
  113. }
  114. return nil
  115. }