disk.go 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. package service
  2. import (
  3. json2 "encoding/json"
  4. "fmt"
  5. "reflect"
  6. "strconv"
  7. "strings"
  8. "time"
  9. "github.com/IceWhaleTech/CasaOS/model"
  10. "github.com/IceWhaleTech/CasaOS/pkg/config"
  11. command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command"
  12. "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
  13. model2 "github.com/IceWhaleTech/CasaOS/service/model"
  14. "github.com/shirou/gopsutil/v3/disk"
  15. "github.com/tidwall/gjson"
  16. "go.uber.org/zap"
  17. "gorm.io/gorm"
  18. )
  19. type DiskService interface {
  20. GetPlugInDisk() []string
  21. LSBLK(isUseCache bool) []model.LSBLKModel
  22. SmartCTL(path string) model.SmartctlA
  23. FormatDisk(path, format string) []string
  24. UmountPointAndRemoveDir(path string) []string
  25. GetDiskInfo(path string) model.LSBLKModel
  26. DelPartition(path, num string) string
  27. AddPartition(path string) string
  28. GetDiskInfoByPath(path string) *disk.UsageStat
  29. MountDisk(path, volume string)
  30. GetSerialAll() []model2.SerialDisk
  31. SaveMountPoint(m model2.SerialDisk)
  32. DeleteMountPoint(path, mountPoint string)
  33. DeleteMount(id string)
  34. UpdateMountPoint(m model2.SerialDisk)
  35. RemoveLSBLKCache()
  36. UmountUSB(path string)
  37. }
  38. type diskService struct {
  39. db *gorm.DB
  40. }
  41. func (d *diskService) RemoveLSBLKCache() {
  42. key := "system_lsblk"
  43. Cache.Delete(key)
  44. }
  45. func (d *diskService) UmountUSB(path string) {
  46. r := command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;UDEVILUmount " + path)
  47. fmt.Println(r)
  48. }
  49. func (d *diskService) SmartCTL(path string) model.SmartctlA {
  50. key := "system_smart_" + path
  51. if result, ok := Cache.Get(key); ok {
  52. res, ok := result.(model.SmartctlA)
  53. if ok {
  54. return res
  55. }
  56. }
  57. var m model.SmartctlA
  58. str := command2.ExecSmartCTLByPath(path)
  59. if str == nil {
  60. loger.Error("failed to exec shell ", zap.Any("err", "smartctl exec error"))
  61. Cache.Add(key, m, time.Minute*10)
  62. return m
  63. }
  64. err := json2.Unmarshal([]byte(str), &m)
  65. if err != nil {
  66. loger.Error("Failed to unmarshal json", zap.Any("err", err))
  67. }
  68. if !reflect.DeepEqual(m, model.SmartctlA{}) {
  69. Cache.Add(key, m, time.Hour*24)
  70. }
  71. return m
  72. }
  73. //通过脚本获取外挂磁盘
  74. func (d *diskService) GetPlugInDisk() []string {
  75. return command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/helper.sh ;GetPlugInDisk")
  76. }
  77. //格式化硬盘
  78. func (d *diskService) FormatDisk(path, format string) []string {
  79. r := command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/helper.sh ;FormatDisk " + path + " " + format)
  80. return r
  81. }
  82. //移除挂载点,删除目录
  83. func (d *diskService) UmountPointAndRemoveDir(path string) []string {
  84. r := command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/helper.sh ;UMountPorintAndRemoveDir " + path)
  85. return r
  86. }
  87. //删除分区
  88. func (d *diskService) DelPartition(path, num string) string {
  89. r := command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/helper.sh ;DelPartition " + path + " " + num)
  90. fmt.Println(r)
  91. return ""
  92. }
  93. //part
  94. func (d *diskService) AddPartition(path string) string {
  95. command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/helper.sh ;AddPartition " + path)
  96. return ""
  97. }
  98. func (d *diskService) AddAllPartition(path string) {
  99. }
  100. //获取硬盘详情
  101. func (d *diskService) GetDiskInfoByPath(path string) *disk.UsageStat {
  102. diskInfo, err := disk.Usage(path + "1")
  103. if err != nil {
  104. fmt.Println(err)
  105. }
  106. diskInfo.UsedPercent, _ = strconv.ParseFloat(fmt.Sprintf("%.1f", diskInfo.UsedPercent), 64)
  107. diskInfo.InodesUsedPercent, _ = strconv.ParseFloat(fmt.Sprintf("%.1f", diskInfo.InodesUsedPercent), 64)
  108. return diskInfo
  109. }
  110. //get disk details
  111. func (d *diskService) LSBLK(isUseCache bool) []model.LSBLKModel {
  112. key := "system_lsblk"
  113. var n []model.LSBLKModel
  114. if result, ok := Cache.Get(key); ok && isUseCache {
  115. res, ok := result.([]model.LSBLKModel)
  116. if ok {
  117. return res
  118. }
  119. }
  120. str := command2.ExecLSBLK()
  121. if str == nil {
  122. loger.Error("Failed to exec shell", zap.Any("err", "lsblk exec error"))
  123. return nil
  124. }
  125. var m []model.LSBLKModel
  126. err := json2.Unmarshal([]byte(gjson.Get(string(str), "blockdevices").String()), &m)
  127. if err != nil {
  128. loger.Error("Failed to unmarshal json", zap.Any("err", err))
  129. }
  130. var c []model.LSBLKModel
  131. var fsused uint64
  132. var health = true
  133. for _, i := range m {
  134. if i.Type != "loop" && !i.RO {
  135. fsused = 0
  136. for _, child := range i.Children {
  137. if child.RM {
  138. child.Health = strings.TrimSpace(command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;GetDiskHealthState " + child.Path))
  139. if strings.ToLower(strings.TrimSpace(child.State)) != "ok" {
  140. health = false
  141. }
  142. f, _ := strconv.ParseUint(child.FSUsed, 10, 64)
  143. fsused += f
  144. } else {
  145. health = false
  146. }
  147. c = append(c, child)
  148. }
  149. //i.Format = strings.TrimSpace(command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;GetDiskType " + i.Path))
  150. if health {
  151. i.Health = "OK"
  152. }
  153. i.FSUsed = strconv.FormatUint(fsused, 10)
  154. i.Children = c
  155. if fsused > 0 {
  156. i.UsedPercent, err = strconv.ParseFloat(fmt.Sprintf("%.4f", float64(fsused)/float64(i.Size)), 64)
  157. if err != nil {
  158. loger.Error("Failed to parse float", zap.Any("err", err))
  159. }
  160. }
  161. n = append(n, i)
  162. health = true
  163. c = []model.LSBLKModel{}
  164. fsused = 0
  165. }
  166. }
  167. if len(n) > 0 {
  168. Cache.Add(key, n, time.Second*100)
  169. }
  170. return n
  171. }
  172. func (d *diskService) GetDiskInfo(path string) model.LSBLKModel {
  173. str := command2.ExecLSBLKByPath(path)
  174. if str == nil {
  175. loger.Error("Failed to exec shell", zap.Any("err", "lsblk exec error"))
  176. return model.LSBLKModel{}
  177. }
  178. var ml []model.LSBLKModel
  179. err := json2.Unmarshal([]byte(gjson.Get(string(str), "blockdevices").String()), &ml)
  180. if err != nil {
  181. loger.Error("Failed to unmarshal json", zap.Any("err", err))
  182. return model.LSBLKModel{}
  183. }
  184. m := model.LSBLKModel{}
  185. if len(ml) > 0 {
  186. m = ml[0]
  187. }
  188. return m
  189. // 下面为计算是否可以继续分区的部分,暂时不需要
  190. chiArr := make(map[string]string)
  191. chiList := command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/helper.sh ;GetPartitionSectors " + m.Path)
  192. if len(chiList) == 0 {
  193. loger.Error("chiList length error", zap.Any("err", "chiList length error"))
  194. }
  195. for i := 0; i < len(chiList); i++ {
  196. tempArr := strings.Split(chiList[i], ",")
  197. chiArr[tempArr[0]] = chiList[i]
  198. }
  199. var maxSector uint64 = 0
  200. for i := 0; i < len(m.Children); i++ {
  201. tempArr := strings.Split(chiArr[m.Children[i].Path], ",")
  202. m.Children[i].StartSector, _ = strconv.ParseUint(tempArr[1], 10, 64)
  203. m.Children[i].EndSector, _ = strconv.ParseUint(tempArr[2], 10, 64)
  204. if m.Children[i].EndSector > maxSector {
  205. maxSector = m.Children[i].EndSector
  206. }
  207. }
  208. diskEndSector := command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/helper.sh ;GetDiskSizeAndSectors " + m.Path)
  209. if len(diskEndSector) < 2 {
  210. loger.Error("diskEndSector length error", zap.Any("err", "diskEndSector length error"))
  211. }
  212. diskEndSectorInt, _ := strconv.ParseUint(diskEndSector[len(diskEndSector)-1], 10, 64)
  213. if (diskEndSectorInt-maxSector)*m.MinIO/1024/1024 > 100 {
  214. //添加可以分区情况
  215. p := model.LSBLKModel{}
  216. p.Path = "可以添加"
  217. m.Children = append(m.Children, p)
  218. }
  219. return m
  220. }
  221. func (d *diskService) MountDisk(path, volume string) {
  222. //fmt.Println("source " + config.AppInfo.ShellPath + "/helper.sh ;do_mount " + path + " " + volume)
  223. r := command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;do_mount " + path + " " + volume)
  224. fmt.Println(r)
  225. }
  226. func (d *diskService) SaveMountPoint(m model2.SerialDisk) {
  227. d.db.Where("uuid = ?", m.UUID).Delete(&model2.SerialDisk{})
  228. d.db.Create(&m)
  229. }
  230. func (d *diskService) UpdateMountPoint(m model2.SerialDisk) {
  231. d.db.Model(&model2.SerialDisk{}).Where("uui = ?", m.UUID).Update("mount_point", m.MountPoint)
  232. }
  233. func (d *diskService) DeleteMount(id string) {
  234. d.db.Delete(&model2.SerialDisk{}).Where("id = ?", id)
  235. }
  236. func (d *diskService) DeleteMountPoint(path, mountPoint string) {
  237. d.db.Where("path = ? AND mount_point = ?", path, mountPoint).Delete(&model2.SerialDisk{})
  238. command2.OnlyExec("source " + config.AppInfo.ShellPath + "/helper.sh ;do_umount " + path)
  239. }
  240. func (d *diskService) GetSerialAll() []model2.SerialDisk {
  241. var m []model2.SerialDisk
  242. d.db.Find(&m)
  243. return m
  244. }
  245. func NewDiskService(db *gorm.DB) DiskService {
  246. return &diskService{db: db}
  247. }