storage.go 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. package main
  2. import (
  3. "errors"
  4. "io/ioutil"
  5. "log"
  6. "os"
  7. "path/filepath"
  8. "runtime"
  9. "strings"
  10. "imuslab.com/arozos/mod/permission"
  11. "imuslab.com/arozos/mod/storage/bridge"
  12. fs "imuslab.com/arozos/mod/filesystem"
  13. storage "imuslab.com/arozos/mod/storage"
  14. )
  15. var (
  16. baseStoragePool *storage.StoragePool //base storage pool, all user can access these virtual roots
  17. fsHandlers []*fs.FileSystemHandler //All File system handlers. All opened handles must be registered in here
  18. //storagePools []*storage.StoragePool //All Storage pool opened
  19. bridgeManager *bridge.Record //Manager to handle bridged FSH
  20. )
  21. func StorageInit() {
  22. //Load the default handler for the user storage root
  23. if !fileExists(filepath.Clean(*root_directory) + "/") {
  24. os.MkdirAll(filepath.Clean(*root_directory)+"/", 0755)
  25. }
  26. //Start loading the base storage pool
  27. err := LoadBaseStoragePool()
  28. if err != nil {
  29. panic(err)
  30. }
  31. //Create a brdige record manager
  32. bm := bridge.NewBridgeRecord("system/bridge.json")
  33. bridgeManager = bm
  34. }
  35. func LoadBaseStoragePool() error {
  36. //Use for Debian buster local file system
  37. localFileSystem := "ext4"
  38. if runtime.GOOS == "windows" {
  39. localFileSystem = "ntfs"
  40. }
  41. baseHandler, err := fs.NewFileSystemHandler(fs.FileSystemOption{
  42. Name: "User",
  43. Uuid: "user",
  44. Path: filepath.ToSlash(filepath.Clean(*root_directory)) + "/",
  45. Hierarchy: "user",
  46. Automount: false,
  47. Filesystem: localFileSystem,
  48. })
  49. if err != nil {
  50. log.Println("Failed to initiate user root storage directory: " + *root_directory)
  51. return err
  52. }
  53. fsHandlers = append(fsHandlers, baseHandler)
  54. //Load the tmp folder as storage unit
  55. tmpHandler, err := fs.NewFileSystemHandler(fs.FileSystemOption{
  56. Name: "tmp",
  57. Uuid: "tmp",
  58. Path: filepath.ToSlash(filepath.Clean(*tmp_directory)) + "/",
  59. Hierarchy: "user",
  60. Automount: false,
  61. Filesystem: localFileSystem,
  62. })
  63. if err != nil {
  64. log.Println("Failed to initiate tmp storage directory: " + *tmp_directory)
  65. return err
  66. }
  67. fsHandlers = append(fsHandlers, tmpHandler)
  68. //Load all the storage config from file
  69. rawConfig, err := ioutil.ReadFile(*storage_config_file)
  70. if err != nil {
  71. //File not found. Use internal storage only
  72. log.Println("Storage configuration file not found. Using internal storage only.")
  73. } else {
  74. //Configuration loaded. Initializing handler
  75. externalHandlers, err := fs.NewFileSystemHandlersFromJSON(rawConfig)
  76. if err != nil {
  77. log.Println("Failed to load storage configuration: " + err.Error() + " -- Skipping")
  78. } else {
  79. for _, thisHandler := range externalHandlers {
  80. fsHandlers = append(fsHandlers, thisHandler)
  81. log.Println(thisHandler.Name + " Mounted as " + thisHandler.UUID + ":/")
  82. }
  83. }
  84. }
  85. //Create a base storage pool for all users
  86. sp, err := storage.NewStoragePool(fsHandlers, "system")
  87. if err != nil {
  88. log.Println("Failed to create base Storaeg Pool")
  89. return err
  90. }
  91. //Update the storage pool permission to readwrite
  92. sp.OtherPermission = "readwrite"
  93. baseStoragePool = sp
  94. return nil
  95. }
  96. //Initialize group storage pool
  97. func GroupStoragePoolInit() {
  98. //Mount permission groups
  99. for _, pg := range permissionHandler.PermissionGroups {
  100. //For each group, check does this group has a config file
  101. err := LoadStoragePoolForGroup(pg)
  102. if err != nil {
  103. continue
  104. }
  105. //Do something else, WIP
  106. }
  107. //Start editing interface for Storage Pool Editor
  108. StoragePoolEditorInit()
  109. }
  110. //Initiate bridged storage pool configs
  111. func BridgeStoragePoolInit() {
  112. bridgeRecords, err := bridgeManager.ReadConfig()
  113. if err != nil {
  114. log.Println("[ERROR] Fail to read File System Handler bridge config")
  115. return
  116. }
  117. for _, bridgeConf := range bridgeRecords {
  118. fsh, err := GetFsHandlerByUUID(bridgeConf.FSHUUID)
  119. if err != nil {
  120. //This fsh is not found. Skip this
  121. continue
  122. }
  123. basePool, err := GetStoragePoolByOwner(bridgeConf.SPOwner)
  124. if err != nil {
  125. //This fsh is not found. Skip this
  126. continue
  127. }
  128. err = BridgeFSHandlerToGroup(fsh, basePool)
  129. if err != nil {
  130. log.Println("Failed to bridge "+fsh.UUID+":/ to "+basePool.Owner, err.Error())
  131. }
  132. log.Println(fsh.UUID + ":/ bridged to " + basePool.Owner + " Storage Pool")
  133. }
  134. }
  135. func BridgeStoragePoolForGroup(group string) {
  136. bridgeRecords, err := bridgeManager.ReadConfig()
  137. if err != nil {
  138. log.Println("Failed to bridge FSH for group " + group)
  139. return
  140. }
  141. for _, bridgeConf := range bridgeRecords {
  142. if bridgeConf.SPOwner == group {
  143. fsh, err := GetFsHandlerByUUID(bridgeConf.FSHUUID)
  144. if err != nil {
  145. //This fsh is not found. Skip this
  146. continue
  147. }
  148. basePool, err := GetStoragePoolByOwner(bridgeConf.SPOwner)
  149. if err != nil {
  150. //This fsh is not found. Skip this
  151. continue
  152. }
  153. err = BridgeFSHandlerToGroup(fsh, basePool)
  154. if err != nil {
  155. log.Println("Failed to bridge "+fsh.UUID+":/ to "+basePool.Owner, err.Error())
  156. }
  157. log.Println(fsh.UUID + ":/ bridged to " + basePool.Owner + " Storage Pool")
  158. }
  159. }
  160. }
  161. //Bridge a FSH to a given Storage Pool
  162. func BridgeFSHandlerToGroup(fsh *fs.FileSystemHandler, sp *storage.StoragePool) error {
  163. //Check if the fsh already exists in the basepool
  164. for _, thisFSH := range sp.Storages {
  165. if thisFSH.UUID == fsh.UUID {
  166. return errors.New("Target File System Handler already bridged to this pool")
  167. }
  168. }
  169. sp.Storages = append(sp.Storages, fsh)
  170. return nil
  171. }
  172. func DebridgeFSHandlerFromGroup(fshUUID string, sp *storage.StoragePool) error {
  173. newStorageList := []*fs.FileSystemHandler{}
  174. fshExists := false
  175. for _, fsh := range sp.Storages {
  176. if fsh.UUID != fshUUID {
  177. fshExists = true
  178. newStorageList = append(newStorageList, fsh)
  179. }
  180. }
  181. if fshExists {
  182. sp.Storages = newStorageList
  183. return nil
  184. } else {
  185. return errors.New("Target File System Handler not found")
  186. }
  187. }
  188. func LoadStoragePoolForGroup(pg *permission.PermissionGroup) error {
  189. expectedConfigPath := "./system/storage/" + pg.Name + ".json"
  190. if fileExists(expectedConfigPath) {
  191. //Read the config file
  192. pgStorageConfig, err := ioutil.ReadFile(expectedConfigPath)
  193. if err != nil {
  194. log.Println("Failed to read config for " + pg.Name + ": " + err.Error())
  195. return errors.New("Failed to read config for " + pg.Name + ": " + err.Error())
  196. }
  197. //Generate fsHandler form json
  198. thisGroupFsHandlers, err := fs.NewFileSystemHandlersFromJSON(pgStorageConfig)
  199. if err != nil {
  200. log.Println("Failed to load storage configuration: " + err.Error())
  201. return errors.New("Failed to load storage configuration: " + err.Error())
  202. }
  203. //Add these to mounted handlers
  204. for _, thisHandler := range thisGroupFsHandlers {
  205. fsHandlers = append(fsHandlers, thisHandler)
  206. log.Println(thisHandler.Name + " Mounted as " + thisHandler.UUID + ":/ for group " + pg.Name)
  207. }
  208. //Create a storage pool from these handlers
  209. sp, err := storage.NewStoragePool(thisGroupFsHandlers, pg.Name)
  210. if err != nil {
  211. log.Println("Failed to create storage pool for " + pg.Name)
  212. return errors.New("Failed to create storage pool for " + pg.Name)
  213. }
  214. //Set other permission to denied by default
  215. sp.OtherPermission = "denied"
  216. //Assign storage pool to group
  217. pg.StoragePool = sp
  218. } else {
  219. //Storage configuration not exists. Fill in the basic information and move to next storage pool
  220. //Create a new empty storage pool for this group
  221. sp, err := storage.NewStoragePool([]*fs.FileSystemHandler{}, pg.Name)
  222. if err != nil {
  223. log.Println("Failed to create empty storage pool for group: ", pg.Name)
  224. }
  225. pg.StoragePool = sp
  226. pg.StoragePool.OtherPermission = "denied"
  227. }
  228. return nil
  229. }
  230. //Check if a storage pool exists by its group owner name
  231. func StoragePoolExists(poolOwner string) bool {
  232. _, err := GetStoragePoolByOwner(poolOwner)
  233. return err == nil
  234. }
  235. func GetAllStoragePools() []*storage.StoragePool {
  236. //Append the base pool
  237. results := []*storage.StoragePool{baseStoragePool}
  238. //Add each permissionGroup's pool
  239. for _, pg := range permissionHandler.PermissionGroups {
  240. results = append(results, pg.StoragePool)
  241. }
  242. return results
  243. }
  244. func GetStoragePoolByOwner(owner string) (*storage.StoragePool, error) {
  245. sps := GetAllStoragePools()
  246. for _, pool := range sps {
  247. if pool.Owner == owner {
  248. return pool, nil
  249. }
  250. }
  251. return nil, errors.New("Storage pool owned by " + owner + " not found")
  252. }
  253. func GetFsHandlerByUUID(uuid string) (*fs.FileSystemHandler, error) {
  254. //Filter out the :/ fropm uuid if exists
  255. if strings.Contains(uuid, ":") {
  256. uuid = strings.Split(uuid, ":")[0]
  257. }
  258. for _, fsh := range fsHandlers {
  259. if fsh.UUID == uuid {
  260. return fsh, nil
  261. }
  262. }
  263. return nil, errors.New("Filesystem handler with given UUID not found")
  264. }
  265. func RegisterStorageSettings() {
  266. //Storage Pool Configuration
  267. registerSetting(settingModule{
  268. Name: "Storage Pools",
  269. Desc: "Storage Pool Mounting Configuration",
  270. IconPath: "SystemAO/disk/smart/img/small_icon.png",
  271. Group: "Disk",
  272. StartDir: "SystemAO/storage/poolList.html",
  273. RequireAdmin: true,
  274. })
  275. }
  276. //CloseAllStorages Close all storage database
  277. func CloseAllStorages() {
  278. for _, fsh := range fsHandlers {
  279. fsh.FilesystemDatabase.Close()
  280. }
  281. }
  282. func closeAllStoragePools() {
  283. for _, sp := range GetAllStoragePools() {
  284. sp.Close()
  285. }
  286. }