api.go 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "log"
  6. "net/http"
  7. "strings"
  8. "imuslab.com/bokofs/bokofsd/mod/diskinfo"
  9. "imuslab.com/bokofs/bokofsd/mod/diskinfo/lsblk"
  10. "imuslab.com/bokofs/bokofsd/mod/diskinfo/smart"
  11. "imuslab.com/bokofs/bokofsd/mod/netstat"
  12. )
  13. /*
  14. API Router
  15. This module handle routing of the API calls
  16. */
  17. // Primary handler for the API router
  18. func HandlerAPIcalls() http.Handler {
  19. return http.StripPrefix("/api", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  20. // Get the disk ID from the URL path
  21. pathParts := strings.Split(r.URL.Path, "/")
  22. if len(pathParts) < 2 {
  23. http.Error(w, "Bad Request", http.StatusBadRequest)
  24. return
  25. }
  26. diskID := pathParts[1]
  27. if diskID == "" {
  28. http.Error(w, "Bad Request", http.StatusBadRequest)
  29. return
  30. }
  31. switch diskID {
  32. case "info":
  33. // Request to /api/info/*
  34. HandleInfoAPIcalls().ServeHTTP(w, r)
  35. return
  36. case "smart":
  37. // Request to /api/smart/*
  38. HandleSMARTCalls().ServeHTTP(w, r)
  39. return
  40. default:
  41. http.Error(w, "Not Found", http.StatusNotFound)
  42. return
  43. }
  44. }))
  45. }
  46. // Handler for SMART API calls
  47. func HandleSMARTCalls() http.Handler {
  48. return http.StripPrefix("/smart/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  49. pathParts := strings.Split(r.URL.Path, "/")
  50. if len(pathParts) < 2 {
  51. http.Error(w, "Bad Request - Missing disk name", http.StatusBadRequest)
  52. return
  53. }
  54. subPath := pathParts[0]
  55. diskName := pathParts[1]
  56. if diskName == "" {
  57. http.Error(w, "Bad Request - Missing disk name", http.StatusBadRequest)
  58. return
  59. }
  60. switch subPath {
  61. case "health":
  62. if diskName == "all" {
  63. // Get the SMART information for all disks
  64. allDisks, err := diskinfo.GetAllDisks()
  65. if err != nil {
  66. log.Println("Error getting all disks:", err)
  67. http.Error(w, "Internal Server Error", http.StatusInternalServerError)
  68. return
  69. }
  70. // Create a map to hold the SMART information for each disk
  71. diskInfoMap := []*smart.DriveHealthInfo{}
  72. for _, disk := range allDisks {
  73. diskName := disk.Name
  74. health, err := smart.GetDiskSMARTHealthSummary(diskName)
  75. if err != nil {
  76. log.Println("Error getting disk health:", err)
  77. continue
  78. }
  79. diskInfoMap = append(diskInfoMap, health)
  80. }
  81. // Convert the disk information to JSON and write it to the response
  82. js, _ := json.Marshal(diskInfoMap)
  83. w.Header().Set("Content-Type", "application/json")
  84. w.WriteHeader(http.StatusOK)
  85. w.Write(js)
  86. return
  87. }
  88. // Get the health status of the disk
  89. health, err := smart.GetDiskSMARTHealthSummary(diskName)
  90. if err != nil {
  91. log.Println("Error getting disk health:", err)
  92. http.Error(w, "Internal Server Error", http.StatusInternalServerError)
  93. return
  94. }
  95. // Convert the health status to JSON and write it to the response
  96. js, _ := json.Marshal(health)
  97. w.Header().Set("Content-Type", "application/json")
  98. w.WriteHeader(http.StatusOK)
  99. w.Write(js)
  100. return
  101. case "info":
  102. // Handle SMART API calls
  103. dt, err := smart.GetDiskType(diskName)
  104. if err != nil {
  105. log.Println("Error getting disk type:", err)
  106. http.Error(w, "Internal Server Error", http.StatusInternalServerError)
  107. return
  108. }
  109. if dt == smart.DiskType_SATA {
  110. // Get SATA disk information
  111. sataInfo, err := smart.GetSATAInfo(diskName)
  112. if err != nil {
  113. log.Println("Error getting SATA disk info:", err)
  114. http.Error(w, "Internal Server Error", http.StatusInternalServerError)
  115. return
  116. }
  117. // Convert the SATA info to JSON and write it to the response
  118. js, _ := json.Marshal(sataInfo)
  119. w.Header().Set("Content-Type", "application/json")
  120. w.WriteHeader(http.StatusOK)
  121. w.Write(js)
  122. } else if dt == smart.DiskType_NVMe {
  123. // Get NVMe disk information
  124. nvmeInfo, err := smart.GetNVMEInfo(diskName)
  125. if err != nil {
  126. log.Println("Error getting NVMe disk info:", err)
  127. http.Error(w, "Internal Server Error", http.StatusInternalServerError)
  128. return
  129. }
  130. // Convert the NVMe info to JSON and write it to the response
  131. js, _ := json.Marshal(nvmeInfo)
  132. w.Header().Set("Content-Type", "application/json")
  133. w.WriteHeader(http.StatusOK)
  134. w.Write(js)
  135. } else {
  136. log.Println("Unknown disk type:", dt)
  137. http.Error(w, "Bad Request - Unknown disk type", http.StatusBadRequest)
  138. return
  139. }
  140. return
  141. default:
  142. http.Error(w, "Not Found", http.StatusNotFound)
  143. return
  144. }
  145. }))
  146. }
  147. // Handler for info API calls
  148. func HandleInfoAPIcalls() http.Handler {
  149. return http.StripPrefix("/info/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  150. //Check the next part of the URL
  151. pathParts := strings.Split(r.URL.Path, "/")
  152. subPath := pathParts[0]
  153. switch subPath {
  154. case "netstat":
  155. // Get the current network statistics
  156. netstatBuffer.HandleGetBufferedNetworkInterfaceStats(w, r)
  157. return
  158. case "iface":
  159. // Get the list of network interfaces
  160. netstat.HandleListNetworkInterfaces(w, r)
  161. return
  162. case "list":
  163. // List all block devices and their partitions
  164. blockDevices, err := lsblk.GetLSBLKOutput()
  165. if err != nil {
  166. log.Println("Error getting block devices:", err)
  167. http.Error(w, "Internal Server Error", http.StatusInternalServerError)
  168. return
  169. }
  170. disks := make([]*diskinfo.Disk, 0)
  171. for _, device := range blockDevices {
  172. if device.Type == "disk" {
  173. disk, err := diskinfo.GetDiskInfo(device.Name)
  174. if err != nil {
  175. log.Println("Error getting disk info:", err)
  176. http.Error(w, "Internal Server Error", http.StatusInternalServerError)
  177. return
  178. }
  179. disks = append(disks, disk)
  180. }
  181. }
  182. // Convert the block devices to JSON and write it to the response
  183. js, _ := json.Marshal(disks)
  184. w.Header().Set("Content-Type", "application/json")
  185. w.WriteHeader(http.StatusOK)
  186. w.Write(js)
  187. case "disk":
  188. // Get the disk info for a particular disk, e.g. sda
  189. if len(pathParts) < 2 {
  190. http.Error(w, "Bad Request - Invalid disk name", http.StatusBadRequest)
  191. return
  192. }
  193. diskID := pathParts[1]
  194. if diskID == "" {
  195. http.Error(w, "Bad Request - Invalid disk name", http.StatusBadRequest)
  196. return
  197. }
  198. if !diskinfo.DevicePathIsValidDisk(diskID) {
  199. log.Println("Invalid disk ID:", diskID)
  200. http.Error(w, "Bad Request", http.StatusBadRequest)
  201. return
  202. }
  203. // Handle diskinfo API calls
  204. targetDiskInfo, err := diskinfo.GetDiskInfo(diskID)
  205. if err != nil {
  206. http.Error(w, "Internal Server Error", http.StatusInternalServerError)
  207. return
  208. }
  209. // Convert the disk info to JSON and write it to the response
  210. js, _ := json.Marshal(targetDiskInfo)
  211. w.Header().Set("Content-Type", "application/json")
  212. w.WriteHeader(http.StatusOK)
  213. w.Write(js)
  214. return
  215. case "part":
  216. // Get the partition info for a particular partition, e.g. sda1
  217. if len(pathParts) < 2 {
  218. http.Error(w, "Bad Request - Missing parition name", http.StatusBadRequest)
  219. return
  220. }
  221. partID := pathParts[1]
  222. if partID == "" {
  223. http.Error(w, "Bad Request - Missing parition name", http.StatusBadRequest)
  224. return
  225. }
  226. if !diskinfo.DevicePathIsValidPartition(partID) {
  227. log.Println("Invalid partition name:", partID)
  228. http.Error(w, "Bad Request - Invalid parition name", http.StatusBadRequest)
  229. return
  230. }
  231. // Handle partinfo API calls
  232. targetPartInfo, err := diskinfo.GetPartitionInfo(partID)
  233. if err != nil {
  234. http.Error(w, "Internal Server Error", http.StatusInternalServerError)
  235. return
  236. }
  237. // Convert the partition info to JSON and write it to the response
  238. js, _ := json.Marshal(targetPartInfo)
  239. w.Header().Set("Content-Type", "application/json")
  240. w.WriteHeader(http.StatusOK)
  241. w.Write(js)
  242. return
  243. default:
  244. fmt.Println("Unknown API call:", subPath)
  245. http.Error(w, "Not Found", http.StatusNotFound)
  246. }
  247. }))
  248. }