storage.pool.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760
  1. package main
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "log"
  6. "net/http"
  7. "os"
  8. "path/filepath"
  9. "strings"
  10. "time"
  11. "imuslab.com/arozos/mod/database"
  12. "imuslab.com/arozos/mod/permission"
  13. "imuslab.com/arozos/mod/storage/bridge"
  14. "imuslab.com/arozos/mod/utils"
  15. fs "imuslab.com/arozos/mod/filesystem"
  16. prout "imuslab.com/arozos/mod/prouter"
  17. storage "imuslab.com/arozos/mod/storage"
  18. )
  19. /*
  20. Storage Pool Handler
  21. author: tobychui
  22. This script handle the storage pool editing of different permission groups
  23. */
  24. func StoragePoolEditorInit() {
  25. adminRouter := prout.NewModuleRouter(prout.RouterOption{
  26. ModuleName: "System Settings",
  27. AdminOnly: true,
  28. UserHandler: userHandler,
  29. DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
  30. utils.SendErrorResponse(w, "Permission Denied")
  31. },
  32. })
  33. //Create the required folder structure
  34. err := os.MkdirAll("./system/storage", 0775)
  35. if err != nil {
  36. log.Println("Create storage pool setting folder failed: ")
  37. log.Fatal(err)
  38. }
  39. adminRouter.HandleFunc("/system/storage/pool/list", HandleListStoragePools)
  40. adminRouter.HandleFunc("/system/storage/pool/listraw", HandleListStoragePoolsConfig)
  41. //adminRouter.HandleFunc("/system/storage/pool/newHandler", HandleStorageNewFsHandler)
  42. adminRouter.HandleFunc("/system/storage/pool/removeHandler", HandleStoragePoolRemove)
  43. adminRouter.HandleFunc("/system/storage/pool/reload", HandleStoragePoolReload)
  44. adminRouter.HandleFunc("/system/storage/pool/toggle", HandleFSHToggle)
  45. adminRouter.HandleFunc("/system/storage/pool/edit", HandleFSHEdit)
  46. adminRouter.HandleFunc("/system/storage/pool/bridge", HandleFSHBridging)
  47. adminRouter.HandleFunc("/system/storage/pool/checkBridge", HandleFSHBridgeCheck)
  48. }
  49. // Handle editing of a given File System Handler
  50. func HandleFSHEdit(w http.ResponseWriter, r *http.Request) {
  51. opr, _ := utils.PostPara(r, "opr")
  52. group, err := utils.PostPara(r, "group")
  53. if err != nil {
  54. utils.SendErrorResponse(w, "Invalid group given")
  55. return
  56. }
  57. if opr == "get" {
  58. uuid, err := utils.PostPara(r, "uuid")
  59. if err != nil {
  60. utils.SendErrorResponse(w, "Invalid UUID")
  61. return
  62. }
  63. //Load
  64. fshOption, err := getFSHConfigFromGroupAndUUID(group, uuid)
  65. if err != nil {
  66. utils.SendErrorResponse(w, err.Error())
  67. return
  68. }
  69. //Hide the password info
  70. fshOption.Username = ""
  71. fshOption.Password = ""
  72. //Return as JSON
  73. js, _ := json.Marshal(fshOption)
  74. utils.SendJSONResponse(w, string(js))
  75. return
  76. } else if opr == "set" {
  77. config, err := utils.PostPara(r, "config")
  78. if err != nil {
  79. utils.SendErrorResponse(w, "Invalid UUID")
  80. return
  81. }
  82. newFsOption, err := buildOptionFromRequestForm(config)
  83. if err != nil {
  84. utils.SendErrorResponse(w, err.Error())
  85. return
  86. }
  87. //systemWideLogger.PrintAndLog("Storage", newFsOption, nil)
  88. uuid := newFsOption.Uuid
  89. //Read and remove the original settings from the config file
  90. err = setFSHConfigByGroupAndId(group, uuid, newFsOption)
  91. if err != nil {
  92. utils.SendErrorResponse(w, err.Error())
  93. } else {
  94. utils.SendOK(w)
  95. }
  96. } else if opr == "new" {
  97. //New handler
  98. config, err := utils.PostPara(r, "config")
  99. if err != nil {
  100. utils.SendErrorResponse(w, "Invalid config")
  101. return
  102. }
  103. newFsOption, err := buildOptionFromRequestForm(config)
  104. if err != nil {
  105. utils.SendErrorResponse(w, err.Error())
  106. return
  107. }
  108. //Check if group exists
  109. if !permissionHandler.GroupExists(group) && group != "system" {
  110. utils.SendErrorResponse(w, "Group not exists: "+group)
  111. return
  112. }
  113. //Validate the config is correct
  114. err = fs.ValidateOption(&newFsOption)
  115. if err != nil {
  116. utils.SendErrorResponse(w, err.Error())
  117. return
  118. }
  119. configFile := "./system/storage.json"
  120. if group != "system" {
  121. configFile = "./system/storage/" + group + ".json"
  122. }
  123. //Merge the old config file if exists
  124. oldConfigs := []fs.FileSystemOption{}
  125. if fs.FileExists(configFile) {
  126. originalConfigFile, _ := os.ReadFile(configFile)
  127. err := json.Unmarshal(originalConfigFile, &oldConfigs)
  128. if err != nil {
  129. systemWideLogger.PrintAndLog("Storage", err.Error(), err)
  130. }
  131. }
  132. oldConfigs = append(oldConfigs, newFsOption)
  133. js, _ := json.MarshalIndent(oldConfigs, "", " ")
  134. err = os.WriteFile(configFile, js, 0775)
  135. if err != nil {
  136. utils.SendErrorResponse(w, err.Error())
  137. return
  138. }
  139. utils.SendOK(w)
  140. } else {
  141. //Unknown
  142. utils.SendErrorResponse(w, "Unknown opr given")
  143. return
  144. }
  145. }
  146. // Get the FSH configuration for the given group and uuid
  147. func getFSHConfigFromGroupAndUUID(group string, uuid string) (*fs.FileSystemOption, error) {
  148. //Spot the desired config file
  149. targerFile := ""
  150. if group == "system" {
  151. targerFile = "./system/storage.json"
  152. } else {
  153. targerFile = "./system/storage/" + group + ".json"
  154. }
  155. //Check if file exists.
  156. if !fs.FileExists(targerFile) {
  157. systemWideLogger.PrintAndLog("Storage", "Config file not found: "+targerFile, nil)
  158. return nil, errors.New("Configuration file not found")
  159. }
  160. if !fs.FileExists(filepath.Dir(targerFile)) {
  161. os.MkdirAll(filepath.Dir(targerFile), 0775)
  162. }
  163. //Load and parse the file
  164. configContent, err := os.ReadFile(targerFile)
  165. if err != nil {
  166. return nil, err
  167. }
  168. loadedConfig := []fs.FileSystemOption{}
  169. err = json.Unmarshal(configContent, &loadedConfig)
  170. if err != nil {
  171. systemWideLogger.PrintAndLog("Storage", "Request to parse config error: "+err.Error()+targerFile, err)
  172. return nil, err
  173. }
  174. //Look for the target fsh uuid
  175. for _, thisFshConfig := range loadedConfig {
  176. if thisFshConfig.Uuid == uuid {
  177. return &thisFshConfig, nil
  178. }
  179. }
  180. return nil, errors.New("No FSH config found with the uuid")
  181. }
  182. func setFSHConfigByGroupAndId(group string, uuid string, options fs.FileSystemOption) error {
  183. //Spot the desired config file
  184. targerFile := ""
  185. if group == "system" {
  186. targerFile = "./system/storage.json"
  187. } else {
  188. targerFile = "./system/storage/" + group + ".json"
  189. }
  190. //Check if file exists.
  191. if !fs.FileExists(targerFile) {
  192. systemWideLogger.PrintAndLog("Storage", "Config file not found: "+targerFile, nil)
  193. return errors.New("Configuration file not found")
  194. }
  195. if !fs.FileExists(filepath.Dir(targerFile)) {
  196. os.MkdirAll(filepath.Dir(targerFile), 0775)
  197. }
  198. //Load and parse the file
  199. configContent, err := os.ReadFile(targerFile)
  200. if err != nil {
  201. return err
  202. }
  203. loadedConfig := []fs.FileSystemOption{}
  204. err = json.Unmarshal(configContent, &loadedConfig)
  205. if err != nil {
  206. systemWideLogger.PrintAndLog("Storage", "Request to parse config error: "+err.Error()+targerFile, err)
  207. return err
  208. }
  209. //Filter the old fs handler option with given uuid
  210. newConfig := []fs.FileSystemOption{}
  211. var overwritingConfig fs.FileSystemOption
  212. for _, fso := range loadedConfig {
  213. if fso.Uuid != uuid {
  214. newConfig = append(newConfig, fso)
  215. } else {
  216. overwritingConfig = fso
  217. }
  218. }
  219. //Continue using the old username and password if it is left empty
  220. if options.Username == "" {
  221. options.Username = overwritingConfig.Username
  222. }
  223. if options.Password == "" {
  224. options.Password = overwritingConfig.Password
  225. }
  226. //Append the new fso to config
  227. newConfig = append(newConfig, options)
  228. //Write config back to file
  229. js, _ := json.MarshalIndent(newConfig, "", " ")
  230. return os.WriteFile(targerFile, js, 0775)
  231. }
  232. // Handle Storage Pool toggle on-off
  233. func HandleFSHToggle(w http.ResponseWriter, r *http.Request) {
  234. fsh, _ := utils.PostPara(r, "fsh")
  235. if fsh == "" {
  236. utils.SendErrorResponse(w, "Invalid File System Handler ID")
  237. return
  238. }
  239. group, _ := utils.PostPara(r, "group")
  240. if group == "" {
  241. utils.SendErrorResponse(w, "Invalid group ID")
  242. return
  243. }
  244. //Check if group exists
  245. if group != "system" && !permissionHandler.GroupExists(group) {
  246. utils.SendErrorResponse(w, "Group not exists")
  247. return
  248. }
  249. //Not allow to modify system reserved fsh
  250. if fsh == "user" || fsh == "tmp" {
  251. utils.SendErrorResponse(w, "Cannot toggle system reserved File System Handler")
  252. return
  253. }
  254. //Check if fsh exists
  255. var targetpg *permission.PermissionGroup
  256. var storagePool *storage.StoragePool
  257. if group == "system" {
  258. //System storage pool.
  259. storagePool = baseStoragePool
  260. } else {
  261. targetpg = permissionHandler.GetPermissionGroupByName(group)
  262. storagePool = targetpg.StoragePool
  263. }
  264. var targetFSH *fs.FileSystemHandler
  265. for _, thisFsh := range storagePool.Storages {
  266. if thisFsh.UUID == fsh {
  267. targetFSH = thisFsh
  268. }
  269. }
  270. //Target File System Handler not found
  271. if targetFSH == nil {
  272. utils.SendErrorResponse(w, "Target File System Handler not found, given: "+fsh)
  273. return
  274. }
  275. if targetFSH.Closed {
  276. //Reopen the fsh database and set this to false
  277. aofsPath := filepath.ToSlash(filepath.Clean(targetFSH.Path)) + "/aofs.db"
  278. conn, err := database.NewDatabase(aofsPath, false)
  279. if err == nil {
  280. targetFSH.FilesystemDatabase = conn
  281. }
  282. targetFSH.Closed = false
  283. } else {
  284. //Close the fsh database and set this to true
  285. if targetFSH.FilesystemDatabase != nil {
  286. targetFSH.FilesystemDatabase.Close()
  287. }
  288. targetFSH.Closed = true
  289. }
  290. //Give it some time to finish unloading
  291. time.Sleep(1 * time.Second)
  292. //Return ok
  293. utils.SendOK(w)
  294. }
  295. // Handle reload of storage pool
  296. func HandleStoragePoolReload(w http.ResponseWriter, r *http.Request) {
  297. pool, _ := utils.PostPara(r, "pool")
  298. //Basepool super long string just to prevent any typo
  299. if pool == "1eb201a3-d0f6-6630-5e6d-2f40480115c5" {
  300. //Reload ALL storage pools
  301. //Reload basepool
  302. baseStoragePool.Close()
  303. emptyPool := storage.StoragePool{}
  304. baseStoragePool = &emptyPool
  305. //Start BasePool again
  306. err := LoadBaseStoragePool()
  307. if err != nil {
  308. systemWideLogger.PrintAndLog("Storage", err.Error(), err)
  309. } else {
  310. //Update userHandler's basePool
  311. userHandler.UpdateStoragePool(baseStoragePool)
  312. }
  313. //Reload all permission group's pool
  314. for _, pg := range permissionHandler.PermissionGroups {
  315. systemWideLogger.PrintAndLog("Storage", "Reloading Storage Pool for: "+pg.Name, err)
  316. //Pool should be exists. Close it
  317. pg.StoragePool.Close()
  318. //Create an empty pool for this permission group
  319. newEmptyPool := storage.StoragePool{}
  320. pg.StoragePool = &newEmptyPool
  321. //Recreate a new pool for this permission group
  322. //If there is no handler in config, the empty one will be kept
  323. LoadStoragePoolForGroup(pg)
  324. }
  325. BridgeStoragePoolInit()
  326. } else {
  327. if pool == "system" {
  328. //Reload basepool
  329. baseStoragePool.Close()
  330. emptyPool := storage.StoragePool{}
  331. baseStoragePool = &emptyPool
  332. //Start BasePool again
  333. err := LoadBaseStoragePool()
  334. if err != nil {
  335. systemWideLogger.PrintAndLog("Storage", err.Error(), err)
  336. } else {
  337. //Update userHandler's basePool
  338. userHandler.UpdateStoragePool(baseStoragePool)
  339. }
  340. BridgeStoragePoolForGroup("system")
  341. } else {
  342. //Reload the given storage pool
  343. if !permissionHandler.GroupExists(pool) {
  344. utils.SendErrorResponse(w, "Permission Pool owner not exists")
  345. return
  346. }
  347. systemWideLogger.PrintAndLog("Storage", "Reloading Storage Pool for: "+pool, nil)
  348. //Pool should be exists. Close it
  349. pg := permissionHandler.GetPermissionGroupByName(pool)
  350. //Record a list of uuids that reloaded, use for later checking for bridge remount
  351. reloadedFshUUIDs := []string{}
  352. for _, fsh := range pg.StoragePool.Storages {
  353. //Close the fsh if it is not a bridged one
  354. isBridged, _ := bridgeManager.IsBridgedFSH(fsh.UUID, pg.Name)
  355. if !isBridged && !fsh.Closed {
  356. fsh.Close()
  357. reloadedFshUUIDs = append(reloadedFshUUIDs, fsh.UUID)
  358. }
  359. }
  360. //Create an empty pool for this permission group
  361. newEmptyPool := storage.StoragePool{}
  362. pg.StoragePool = &newEmptyPool
  363. //Recreate a new pool for this permission group
  364. //If there is no handler in config, the empty one will be kept
  365. LoadStoragePoolForGroup(pg)
  366. BridgeStoragePoolForGroup(pg.Name)
  367. //Get all the groups that have bridged the reloaded fshs
  368. rebridgePendingMap := map[string]bool{}
  369. for _, fshuuid := range reloadedFshUUIDs {
  370. pgs := bridgeManager.GetBridgedGroups(fshuuid)
  371. for _, pg := range pgs {
  372. rebridgePendingMap[pg] = true
  373. }
  374. }
  375. //Debridge and rebridge all the related storage pools
  376. for pg, _ := range rebridgePendingMap {
  377. DebridgeAllFSHandlerFromGroup(pg)
  378. time.Sleep(100 * time.Millisecond)
  379. BridgeStoragePoolForGroup(pg)
  380. }
  381. }
  382. }
  383. utils.SendOK(w)
  384. }
  385. func HandleStoragePoolRemove(w http.ResponseWriter, r *http.Request) {
  386. groupname, err := utils.PostPara(r, "group")
  387. if err != nil {
  388. utils.SendErrorResponse(w, "group not defined")
  389. return
  390. }
  391. uuid, err := utils.PostPara(r, "uuid")
  392. if err != nil {
  393. utils.SendErrorResponse(w, "File system handler UUID not defined")
  394. return
  395. }
  396. targetConfigFile := "./system/storage.json"
  397. if groupname == "system" {
  398. if uuid == "user" || uuid == "tmp" {
  399. utils.SendErrorResponse(w, "Cannot remove system reserved file system handlers")
  400. return
  401. }
  402. //Ok to continue
  403. } else {
  404. //Check group exists
  405. if !permissionHandler.GroupExists(groupname) {
  406. utils.SendErrorResponse(w, "Group not exists")
  407. return
  408. }
  409. targetConfigFile = "./system/storage/" + groupname + ".json"
  410. if !fs.FileExists(targetConfigFile) {
  411. //No config. Create an empty one
  412. initConfig := []fs.FileSystemOption{}
  413. js, _ := json.MarshalIndent(initConfig, "", " ")
  414. os.WriteFile(targetConfigFile, js, 0775)
  415. }
  416. }
  417. //Check if this handler is bridged handler
  418. bridged, _ := bridgeManager.IsBridgedFSH(uuid, groupname)
  419. if bridged {
  420. //Bridged FSH. Remove it from bridge config
  421. basePool, err := GetStoragePoolByOwner(groupname)
  422. if err != nil {
  423. utils.SendErrorResponse(w, err.Error())
  424. return
  425. }
  426. err = DebridgeFSHandlerFromGroup(uuid, basePool)
  427. if err != nil {
  428. utils.SendErrorResponse(w, err.Error())
  429. return
  430. }
  431. //Remove it from the config
  432. bridgeManager.RemoveFromConfig(uuid, groupname)
  433. utils.SendOK(w)
  434. return
  435. } else {
  436. //Remove it from the json file
  437. //Read and parse from old config
  438. oldConfigs := []fs.FileSystemOption{}
  439. originalConfigFile, _ := os.ReadFile(targetConfigFile)
  440. err = json.Unmarshal(originalConfigFile, &oldConfigs)
  441. if err != nil {
  442. utils.SendErrorResponse(w, "Failed to parse original config file")
  443. return
  444. }
  445. //Generate new confic by filtering
  446. newConfigs := []fs.FileSystemOption{}
  447. for _, config := range oldConfigs {
  448. if config.Uuid != uuid {
  449. newConfigs = append(newConfigs, config)
  450. }
  451. }
  452. //Parse and put it into file
  453. if len(newConfigs) > 0 {
  454. js, _ := json.MarshalIndent(newConfigs, "", " ")
  455. os.WriteFile(targetConfigFile, js, 0777)
  456. } else {
  457. os.Remove(targetConfigFile)
  458. }
  459. }
  460. utils.SendOK(w)
  461. }
  462. // Constract a fsoption from form
  463. func buildOptionFromRequestForm(payload string) (fs.FileSystemOption, error) {
  464. newFsOption := fs.FileSystemOption{}
  465. err := json.Unmarshal([]byte(payload), &newFsOption)
  466. if err != nil {
  467. return fs.FileSystemOption{}, err
  468. }
  469. return newFsOption, nil
  470. }
  471. /*
  472. func HandleStorageNewFsHandler(w http.ResponseWriter, r *http.Request) {
  473. newFsOption, _ := buildOptionFromRequestForm(r)
  474. type errorObject struct {
  475. Message string
  476. Source string
  477. }
  478. //Get group from form data
  479. groupName := r.FormValue("group")
  480. //Check if group exists
  481. if !permissionHandler.GroupExists(groupName) && groupName != "system" {
  482. js, _ := json.Marshal(errorObject{
  483. Message: "Group not exists: " + groupName,
  484. Source: "",
  485. })
  486. http.Redirect(w, r, "../../../SystemAO/storage/error.html#"+string(js), 307)
  487. }
  488. //Validate the config
  489. err := fs.ValidateOption(&newFsOption)
  490. if err != nil {
  491. //Serve an error page
  492. js, _ := json.Marshal(errorObject{
  493. Message: err.Error(),
  494. Source: groupName,
  495. })
  496. http.Redirect(w, r, "../../../SystemAO/storage/error.html#"+string(js), 307)
  497. return
  498. }
  499. //Ok. Append to the record
  500. configFile := "./system/storage.json"
  501. if groupName != "system" {
  502. configFile = "./system/storage/" + groupName + ".json"
  503. }
  504. //If file exists, merge it to
  505. oldConfigs := []fs.FileSystemOption{}
  506. if fs.FileExists(configFile) {
  507. originalConfigFile, _ := os.ReadFile(configFile)
  508. err := json.Unmarshal(originalConfigFile, &oldConfigs)
  509. if err != nil {
  510. systemWideLogger.PrintAndLog(err,nil)
  511. }
  512. }
  513. oldConfigs = append(oldConfigs, newFsOption)
  514. //Prepare the content to be written
  515. js, _ := json.Marshal(oldConfigs)
  516. resultingJson := pretty.Pretty(js)
  517. err = os.WriteFile(configFile, resultingJson, 0775)
  518. if err != nil {
  519. //Write Error. This could sometime happens on Windows host for unknown reason
  520. js, _ := json.Marshal(errorObject{
  521. Message: err.Error(),
  522. Source: groupName,
  523. })
  524. http.Redirect(w, r, "../../../SystemAO/storage/error.html#"+string(js), 307)
  525. return
  526. }
  527. w.Header().Set("Cache-Control", "no-store, no-cache, must-revalidate, post-check=0, pre-check=0")
  528. http.Redirect(w, r, "../../../SystemAO/storage/poolEditor.html#"+groupName, 307)
  529. }
  530. */
  531. func HandleListStoragePoolsConfig(w http.ResponseWriter, r *http.Request) {
  532. target, _ := utils.GetPara(r, "target")
  533. if target == "" {
  534. target = "system"
  535. }
  536. target = strings.ReplaceAll(filepath.ToSlash(target), "/", "")
  537. //List the target storage pool config
  538. targetFile := "./system/storage.json"
  539. if target != "system" {
  540. targetFile = "./system/storage/" + target + ".json"
  541. }
  542. if !fs.FileExists(targetFile) {
  543. //Assume no storage.
  544. nofsh := []*fs.FileSystemOption{}
  545. js, _ := json.Marshal(nofsh)
  546. utils.SendJSONResponse(w, string(js))
  547. return
  548. }
  549. //Read and serve it
  550. configContent, err := os.ReadFile(targetFile)
  551. if err != nil {
  552. utils.SendErrorResponse(w, err.Error())
  553. return
  554. } else {
  555. utils.SendJSONResponse(w, string(configContent))
  556. }
  557. }
  558. // Return all storage pool mounted to the system, aka base pool + pg pools
  559. func HandleListStoragePools(w http.ResponseWriter, r *http.Request) {
  560. filter, _ := utils.GetPara(r, "filter")
  561. storagePools := []*storage.StoragePool{}
  562. if filter != "" {
  563. if filter == "system" {
  564. storagePools = append(storagePools, baseStoragePool)
  565. } else {
  566. for _, pg := range userHandler.GetPermissionHandler().PermissionGroups {
  567. if pg.Name == filter {
  568. storagePools = append(storagePools, pg.StoragePool)
  569. }
  570. }
  571. }
  572. } else {
  573. //Add the base pool into the list
  574. storagePools = append(storagePools, baseStoragePool)
  575. for _, pg := range userHandler.GetPermissionHandler().PermissionGroups {
  576. storagePools = append(storagePools, pg.StoragePool)
  577. }
  578. }
  579. js, _ := json.Marshal(storagePools)
  580. utils.SendJSONResponse(w, string(js))
  581. }
  582. // Handler for bridging two FSH, require admin permission
  583. func HandleFSHBridging(w http.ResponseWriter, r *http.Request) {
  584. //Get the target pool and fsh to bridge
  585. basePool, err := utils.PostPara(r, "base")
  586. if err != nil {
  587. utils.SendErrorResponse(w, "Invalid base pool")
  588. return
  589. }
  590. //Add the target FSH into the base pool
  591. basePoolObject, err := GetStoragePoolByOwner(basePool)
  592. if err != nil {
  593. systemWideLogger.PrintAndLog("Storage", "Bridge FSH failed: "+err.Error(), err)
  594. utils.SendErrorResponse(w, "Storage pool not found")
  595. return
  596. }
  597. targetFSH, err := utils.PostPara(r, "fsh")
  598. if err != nil {
  599. utils.SendErrorResponse(w, "Invalid File System Handler given")
  600. return
  601. }
  602. fsh, err := GetFsHandlerByUUID(targetFSH)
  603. if err != nil {
  604. utils.SendErrorResponse(w, "Given File System Handler UUID does not exists")
  605. return
  606. }
  607. err = BridgeFSHandlerToGroup(fsh, basePoolObject)
  608. if err != nil {
  609. utils.SendErrorResponse(w, err.Error())
  610. return
  611. }
  612. bridgeConfig := bridge.BridgeConfig{
  613. FSHUUID: fsh.UUID,
  614. SPOwner: basePoolObject.Owner,
  615. }
  616. //Write changes to file
  617. err = bridgeManager.AppendToConfig(&bridgeConfig)
  618. if err != nil {
  619. utils.SendErrorResponse(w, err.Error())
  620. return
  621. }
  622. utils.SendOK(w)
  623. }
  624. func HandleFSHBridgeCheck(w http.ResponseWriter, r *http.Request) {
  625. basePool, err := utils.PostPara(r, "base")
  626. if err != nil {
  627. utils.SendErrorResponse(w, "Invalid base pool")
  628. return
  629. }
  630. fsh, err := utils.PostPara(r, "fsh")
  631. if err != nil {
  632. utils.SendErrorResponse(w, "Invalid fsh UUID")
  633. return
  634. }
  635. isBridged, err := bridgeManager.IsBridgedFSH(fsh, basePool)
  636. if err != nil {
  637. utils.SendErrorResponse(w, err.Error())
  638. return
  639. }
  640. js, _ := json.Marshal(isBridged)
  641. utils.SendJSONResponse(w, string(js))
  642. }