backup.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. package main
  2. import (
  3. "encoding/json"
  4. "net/http"
  5. "path/filepath"
  6. "imuslab.com/arozos/mod/disk/hybridBackup"
  7. prout "imuslab.com/arozos/mod/prouter"
  8. )
  9. func backup_init() {
  10. //Register HybridBackup storage restore endpoints
  11. router := prout.NewModuleRouter(prout.RouterOption{
  12. AdminOnly: false,
  13. UserHandler: userHandler,
  14. DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
  15. sendErrorResponse(w, "Permission Denied")
  16. },
  17. })
  18. //Register API endpoints
  19. router.HandleFunc("/system/backup/listRestorable", backup_listRestorable)
  20. router.HandleFunc("/system/backup/restoreFile", backup_restoreSelected)
  21. router.HandleFunc("/system/backup/snapshotSummary", backup_renderSnapshotSummary)
  22. router.HandleFunc("/system/backup/listAll", backup_listAllBackupDisk)
  23. }
  24. //List all backup disk info
  25. func backup_listAllBackupDisk(w http.ResponseWriter, r *http.Request) {
  26. //Get all fsh from the system
  27. runningBackupTasks := []*hybridBackup.BackupTask{}
  28. //Render base storage pool
  29. for _, fsh := range baseStoragePool.Storages {
  30. if fsh.Hierarchy == "backup" {
  31. task, err := baseStoragePool.HyperBackupManager.GetTaskByBackupDiskID(fsh.UUID)
  32. if err != nil {
  33. continue
  34. }
  35. runningBackupTasks = append(runningBackupTasks, task)
  36. }
  37. }
  38. //Render group storage pool
  39. for _, pg := range permissionHandler.PermissionGroups {
  40. for _, fsh := range pg.StoragePool.Storages {
  41. task, err := pg.StoragePool.HyperBackupManager.GetTaskByBackupDiskID(fsh.UUID)
  42. if err != nil {
  43. continue
  44. }
  45. runningBackupTasks = append(runningBackupTasks, task)
  46. }
  47. }
  48. type backupDrive struct {
  49. DiskUID string //The backup disk UUID
  50. DiskName string // The Backup disk name
  51. ParentUID string //Parent disk UID
  52. ParentName string //Parent disk name
  53. BackupMode string //The backup mode of the drive
  54. LastBackupCycleTime int64 //Last backup timestamp
  55. BackupCycleCount int64 //How many backup cycle has proceeded since the system startup
  56. }
  57. backupDrives := []*backupDrive{}
  58. for _, task := range runningBackupTasks {
  59. diskFsh, diskErr := GetFsHandlerByUUID(task.DiskUID)
  60. parentFsh, parentErr := GetFsHandlerByUUID(task.ParentUID)
  61. //Check for error in getting FS Handler
  62. if diskErr != nil || parentErr != nil {
  63. sendErrorResponse(w, "Unable to get backup task info from backup disk: "+task.DiskUID)
  64. return
  65. }
  66. backupDrives = append(backupDrives, &backupDrive{
  67. DiskUID: diskFsh.UUID,
  68. DiskName: diskFsh.Name,
  69. ParentUID: parentFsh.UUID,
  70. ParentName: parentFsh.Name,
  71. BackupMode: task.Mode,
  72. LastBackupCycleTime: task.LastCycleTime,
  73. BackupCycleCount: task.CycleCounter,
  74. })
  75. }
  76. js, _ := json.Marshal(backupDrives)
  77. sendJSONResponse(w, string(js))
  78. }
  79. //Generate a snapshot summary for vroot
  80. func backup_renderSnapshotSummary(w http.ResponseWriter, r *http.Request) {
  81. //Get user accessiable storage pools
  82. userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
  83. if err != nil {
  84. sendErrorResponse(w, "User not logged in")
  85. return
  86. }
  87. //Get Backup disk ID from request
  88. bdid, err := mv(r, "bdid", true)
  89. if err != nil {
  90. sendErrorResponse(w, "Invalid backup disk ID given")
  91. return
  92. }
  93. //Get target snapshot name from request
  94. snapshot, err := mv(r, "snapshot", true)
  95. if err != nil {
  96. sendErrorResponse(w, "Invalid snapshot name given")
  97. return
  98. }
  99. //Get fsh from the id
  100. fsh, err := GetFsHandlerByUUID(bdid)
  101. if err != nil {
  102. sendErrorResponse(w, err.Error())
  103. return
  104. }
  105. //Get parent disk hierarcy
  106. parentDiskID, err := userinfo.HomeDirectories.HyperBackupManager.GetParentDiskIDByRestoreDiskID(fsh.UUID)
  107. if err != nil {
  108. sendErrorResponse(w, err.Error())
  109. return
  110. }
  111. parentFsh, err := GetFsHandlerByUUID(parentDiskID)
  112. if err != nil {
  113. sendErrorResponse(w, err.Error())
  114. return
  115. }
  116. //Get task by the backup disk id
  117. task, err := userinfo.HomeDirectories.HyperBackupManager.GetTaskByBackupDiskID(fsh.UUID)
  118. if err != nil {
  119. sendErrorResponse(w, err.Error())
  120. return
  121. }
  122. if task.Mode == "version" {
  123. //Generate snapshot summary
  124. var summary *hybridBackup.SnapshotSummary
  125. if parentFsh.Hierarchy == "user" {
  126. s, err := task.GenerateSnapshotSummary(snapshot, &userinfo.Username)
  127. if err != nil {
  128. sendErrorResponse(w, err.Error())
  129. return
  130. }
  131. summary = s
  132. } else {
  133. s, err := task.GenerateSnapshotSummary(snapshot, nil)
  134. if err != nil {
  135. sendErrorResponse(w, err.Error())
  136. return
  137. }
  138. summary = s
  139. }
  140. js, _ := json.Marshal(summary)
  141. sendJSONResponse(w, string(js))
  142. } else {
  143. sendErrorResponse(w, "Unable to genreate snapshot summary: Backup mode is not snapshot")
  144. return
  145. }
  146. }
  147. //Restore a given file
  148. func backup_restoreSelected(w http.ResponseWriter, r *http.Request) {
  149. //Get user accessiable storage pools
  150. userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
  151. if err != nil {
  152. sendErrorResponse(w, "User not logged in")
  153. return
  154. }
  155. //Get Backup disk ID from request
  156. bdid, err := mv(r, "bdid", true)
  157. if err != nil {
  158. sendErrorResponse(w, "Invalid backup disk ID given")
  159. return
  160. }
  161. //Get fsh from the id
  162. fsh, err := GetFsHandlerByUUID(bdid)
  163. if err != nil {
  164. sendErrorResponse(w, err.Error())
  165. return
  166. }
  167. //Get the relative path for the restorable file
  168. relpath, err := mv(r, "relpath", true)
  169. if err != nil {
  170. sendErrorResponse(w, "Invalid relative path given")
  171. return
  172. }
  173. //Handle restore of the file
  174. err = userinfo.HomeDirectories.HyperBackupManager.HandleRestore(fsh.UUID, relpath, &userinfo.Username)
  175. if err != nil {
  176. sendErrorResponse(w, err.Error())
  177. return
  178. }
  179. type RestoreResult struct {
  180. RestoreDiskID string
  181. TargetDiskID string
  182. RestoredVirtualPath string
  183. }
  184. result := RestoreResult{
  185. RestoreDiskID: fsh.UUID,
  186. }
  187. //Get access path for this file
  188. parentDiskId, err := userinfo.HomeDirectories.HyperBackupManager.GetParentDiskIDByRestoreDiskID(fsh.UUID)
  189. if err != nil {
  190. //Unable to get parent disk ID???
  191. } else {
  192. //Get the path of the parent disk
  193. parentDiskHandler, err := GetFsHandlerByUUID(parentDiskId)
  194. if err == nil {
  195. //Join the result to create a virtual path
  196. assumedRestoreRealPath := filepath.ToSlash(filepath.Join(parentDiskHandler.Path, relpath))
  197. restoreVpath, err := userinfo.RealPathToVirtualPath(assumedRestoreRealPath)
  198. if err == nil {
  199. result.RestoredVirtualPath = restoreVpath
  200. }
  201. result.TargetDiskID = parentDiskId
  202. }
  203. }
  204. js, _ := json.Marshal(result)
  205. sendJSONResponse(w, string(js))
  206. }
  207. //Generate and return a restorable report
  208. func backup_listRestorable(w http.ResponseWriter, r *http.Request) {
  209. //Get user accessiable storage pools
  210. userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
  211. if err != nil {
  212. sendErrorResponse(w, "User not logged in")
  213. return
  214. }
  215. //Get Vroot ID from request
  216. vroot, err := mv(r, "vroot", true)
  217. if err != nil {
  218. sendErrorResponse(w, "Invalid vroot given")
  219. return
  220. }
  221. //Get fsh from the id
  222. fsh, err := GetFsHandlerByUUID(vroot)
  223. if err != nil {
  224. sendErrorResponse(w, err.Error())
  225. return
  226. }
  227. userBackupManager := userinfo.HomeDirectories.HyperBackupManager
  228. //Get the user's storage pool and list restorable by the user's storage pool access
  229. restorableReport, err := userBackupManager.ListRestorable(fsh.UUID)
  230. if err != nil {
  231. sendErrorResponse(w, err.Error())
  232. return
  233. }
  234. //Get and check if the parent disk has a user Hierarcy
  235. paretnfsh, err := GetFsHandlerByUUID(restorableReport.ParentUID)
  236. if err != nil {
  237. sendErrorResponse(w, err.Error())
  238. return
  239. }
  240. result := hybridBackup.RestorableReport{
  241. ParentUID: restorableReport.ParentUID,
  242. RestorableFiles: []*hybridBackup.RestorableFile{},
  243. }
  244. if paretnfsh.Hierarchy == "user" {
  245. //The file system is user based. Filter out those file that is not belong to this user
  246. for _, restorableFile := range restorableReport.RestorableFiles {
  247. if restorableFile.IsSnapshot {
  248. //Is snapshot. Always allow access
  249. result.RestorableFiles = append(result.RestorableFiles, restorableFile)
  250. } else {
  251. //Is file
  252. fileAbsPath := filepath.Join(fsh.Path, restorableFile.RelpathOnDisk)
  253. _, err := userinfo.RealPathToVirtualPath(fileAbsPath)
  254. if err != nil {
  255. //Cannot translate this file. That means the file is not owned by this user
  256. } else {
  257. //Can translate the path.
  258. result.RestorableFiles = append(result.RestorableFiles, restorableFile)
  259. }
  260. }
  261. }
  262. } else {
  263. result = restorableReport
  264. }
  265. js, _ := json.Marshal(result)
  266. sendJSONResponse(w, string(js))
  267. }