storage.pool.go 18 KB

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