storage.pool.go 20 KB

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