admin_handlers.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. package handlers
  2. import (
  3. "net/http"
  4. "time"
  5. "github.com/gin-gonic/gin"
  6. "github.com/seaweedfs/seaweedfs/weed/admin/dash"
  7. "github.com/seaweedfs/seaweedfs/weed/admin/view/app"
  8. "github.com/seaweedfs/seaweedfs/weed/admin/view/layout"
  9. )
  10. // AdminHandlers contains all the HTTP handlers for the admin interface
  11. type AdminHandlers struct {
  12. adminServer *dash.AdminServer
  13. authHandlers *AuthHandlers
  14. clusterHandlers *ClusterHandlers
  15. fileBrowserHandlers *FileBrowserHandlers
  16. userHandlers *UserHandlers
  17. policyHandlers *PolicyHandlers
  18. maintenanceHandlers *MaintenanceHandlers
  19. mqHandlers *MessageQueueHandlers
  20. }
  21. // NewAdminHandlers creates a new instance of AdminHandlers
  22. func NewAdminHandlers(adminServer *dash.AdminServer) *AdminHandlers {
  23. authHandlers := NewAuthHandlers(adminServer)
  24. clusterHandlers := NewClusterHandlers(adminServer)
  25. fileBrowserHandlers := NewFileBrowserHandlers(adminServer)
  26. userHandlers := NewUserHandlers(adminServer)
  27. policyHandlers := NewPolicyHandlers(adminServer)
  28. maintenanceHandlers := NewMaintenanceHandlers(adminServer)
  29. mqHandlers := NewMessageQueueHandlers(adminServer)
  30. return &AdminHandlers{
  31. adminServer: adminServer,
  32. authHandlers: authHandlers,
  33. clusterHandlers: clusterHandlers,
  34. fileBrowserHandlers: fileBrowserHandlers,
  35. userHandlers: userHandlers,
  36. policyHandlers: policyHandlers,
  37. maintenanceHandlers: maintenanceHandlers,
  38. mqHandlers: mqHandlers,
  39. }
  40. }
  41. // SetupRoutes configures all the routes for the admin interface
  42. func (h *AdminHandlers) SetupRoutes(r *gin.Engine, authRequired bool, username, password string) {
  43. // Health check (no auth required)
  44. r.GET("/health", h.HealthCheck)
  45. if authRequired {
  46. // Authentication routes (no auth required)
  47. r.GET("/login", h.authHandlers.ShowLogin)
  48. r.POST("/login", h.authHandlers.HandleLogin(username, password))
  49. r.GET("/logout", h.authHandlers.HandleLogout)
  50. // Protected routes group
  51. protected := r.Group("/")
  52. protected.Use(dash.RequireAuth())
  53. // Main admin interface routes
  54. protected.GET("/", h.ShowDashboard)
  55. protected.GET("/admin", h.ShowDashboard)
  56. // Object Store management routes
  57. protected.GET("/object-store/buckets", h.ShowS3Buckets)
  58. protected.GET("/object-store/buckets/:bucket", h.ShowBucketDetails)
  59. protected.GET("/object-store/users", h.userHandlers.ShowObjectStoreUsers)
  60. protected.GET("/object-store/policies", h.policyHandlers.ShowPolicies)
  61. // File browser routes
  62. protected.GET("/files", h.fileBrowserHandlers.ShowFileBrowser)
  63. // Cluster management routes
  64. protected.GET("/cluster/masters", h.clusterHandlers.ShowClusterMasters)
  65. protected.GET("/cluster/filers", h.clusterHandlers.ShowClusterFilers)
  66. protected.GET("/cluster/volume-servers", h.clusterHandlers.ShowClusterVolumeServers)
  67. protected.GET("/cluster/volumes", h.clusterHandlers.ShowClusterVolumes)
  68. protected.GET("/cluster/volumes/:id/:server", h.clusterHandlers.ShowVolumeDetails)
  69. protected.GET("/cluster/collections", h.clusterHandlers.ShowClusterCollections)
  70. protected.GET("/cluster/collections/:name", h.clusterHandlers.ShowCollectionDetails)
  71. protected.GET("/cluster/ec-shards", h.clusterHandlers.ShowClusterEcShards)
  72. protected.GET("/cluster/ec-volumes/:id", h.clusterHandlers.ShowEcVolumeDetails)
  73. // Message Queue management routes
  74. protected.GET("/mq/brokers", h.mqHandlers.ShowBrokers)
  75. protected.GET("/mq/topics", h.mqHandlers.ShowTopics)
  76. protected.GET("/mq/topics/:namespace/:topic", h.mqHandlers.ShowTopicDetails)
  77. // Maintenance system routes
  78. protected.GET("/maintenance", h.maintenanceHandlers.ShowMaintenanceQueue)
  79. protected.GET("/maintenance/workers", h.maintenanceHandlers.ShowMaintenanceWorkers)
  80. protected.GET("/maintenance/config", h.maintenanceHandlers.ShowMaintenanceConfig)
  81. protected.POST("/maintenance/config", h.maintenanceHandlers.UpdateMaintenanceConfig)
  82. protected.GET("/maintenance/config/:taskType", h.maintenanceHandlers.ShowTaskConfig)
  83. protected.POST("/maintenance/config/:taskType", h.maintenanceHandlers.UpdateTaskConfig)
  84. protected.GET("/maintenance/tasks/:id", h.maintenanceHandlers.ShowTaskDetail)
  85. // API routes for AJAX calls
  86. api := r.Group("/api")
  87. api.Use(dash.RequireAuthAPI()) // Use API-specific auth middleware
  88. {
  89. api.GET("/cluster/topology", h.clusterHandlers.GetClusterTopology)
  90. api.GET("/cluster/masters", h.clusterHandlers.GetMasters)
  91. api.GET("/cluster/volumes", h.clusterHandlers.GetVolumeServers)
  92. api.GET("/admin", h.adminServer.ShowAdmin) // JSON API for admin data
  93. api.GET("/config", h.adminServer.GetConfigInfo) // Configuration information
  94. // S3 API routes
  95. s3Api := api.Group("/s3")
  96. {
  97. s3Api.GET("/buckets", h.adminServer.ListBucketsAPI)
  98. s3Api.POST("/buckets", h.adminServer.CreateBucket)
  99. s3Api.DELETE("/buckets/:bucket", h.adminServer.DeleteBucket)
  100. s3Api.GET("/buckets/:bucket", h.adminServer.ShowBucketDetails)
  101. s3Api.PUT("/buckets/:bucket/quota", h.adminServer.UpdateBucketQuota)
  102. }
  103. // User management API routes
  104. usersApi := api.Group("/users")
  105. {
  106. usersApi.GET("", h.userHandlers.GetUsers)
  107. usersApi.POST("", h.userHandlers.CreateUser)
  108. usersApi.GET("/:username", h.userHandlers.GetUserDetails)
  109. usersApi.PUT("/:username", h.userHandlers.UpdateUser)
  110. usersApi.DELETE("/:username", h.userHandlers.DeleteUser)
  111. usersApi.POST("/:username/access-keys", h.userHandlers.CreateAccessKey)
  112. usersApi.DELETE("/:username/access-keys/:accessKeyId", h.userHandlers.DeleteAccessKey)
  113. usersApi.GET("/:username/policies", h.userHandlers.GetUserPolicies)
  114. usersApi.PUT("/:username/policies", h.userHandlers.UpdateUserPolicies)
  115. }
  116. // Object Store Policy management API routes
  117. objectStorePoliciesApi := api.Group("/object-store/policies")
  118. {
  119. objectStorePoliciesApi.GET("", h.policyHandlers.GetPolicies)
  120. objectStorePoliciesApi.POST("", h.policyHandlers.CreatePolicy)
  121. objectStorePoliciesApi.GET("/:name", h.policyHandlers.GetPolicy)
  122. objectStorePoliciesApi.PUT("/:name", h.policyHandlers.UpdatePolicy)
  123. objectStorePoliciesApi.DELETE("/:name", h.policyHandlers.DeletePolicy)
  124. objectStorePoliciesApi.POST("/validate", h.policyHandlers.ValidatePolicy)
  125. }
  126. // File management API routes
  127. filesApi := api.Group("/files")
  128. {
  129. filesApi.DELETE("/delete", h.fileBrowserHandlers.DeleteFile)
  130. filesApi.DELETE("/delete-multiple", h.fileBrowserHandlers.DeleteMultipleFiles)
  131. filesApi.POST("/create-folder", h.fileBrowserHandlers.CreateFolder)
  132. filesApi.POST("/upload", h.fileBrowserHandlers.UploadFile)
  133. filesApi.GET("/download", h.fileBrowserHandlers.DownloadFile)
  134. filesApi.GET("/view", h.fileBrowserHandlers.ViewFile)
  135. filesApi.GET("/properties", h.fileBrowserHandlers.GetFileProperties)
  136. }
  137. // Volume management API routes
  138. volumeApi := api.Group("/volumes")
  139. {
  140. volumeApi.POST("/:id/:server/vacuum", h.clusterHandlers.VacuumVolume)
  141. }
  142. // Maintenance API routes
  143. maintenanceApi := api.Group("/maintenance")
  144. {
  145. maintenanceApi.POST("/scan", h.adminServer.TriggerMaintenanceScan)
  146. maintenanceApi.GET("/tasks", h.adminServer.GetMaintenanceTasks)
  147. maintenanceApi.GET("/tasks/:id", h.adminServer.GetMaintenanceTask)
  148. maintenanceApi.GET("/tasks/:id/detail", h.adminServer.GetMaintenanceTaskDetailAPI)
  149. maintenanceApi.POST("/tasks/:id/cancel", h.adminServer.CancelMaintenanceTask)
  150. maintenanceApi.GET("/workers", h.adminServer.GetMaintenanceWorkersAPI)
  151. maintenanceApi.GET("/workers/:id", h.adminServer.GetMaintenanceWorker)
  152. maintenanceApi.GET("/workers/:id/logs", h.adminServer.GetWorkerLogs)
  153. maintenanceApi.GET("/stats", h.adminServer.GetMaintenanceStats)
  154. maintenanceApi.GET("/config", h.adminServer.GetMaintenanceConfigAPI)
  155. maintenanceApi.PUT("/config", h.adminServer.UpdateMaintenanceConfigAPI)
  156. }
  157. // Message Queue API routes
  158. mqApi := api.Group("/mq")
  159. {
  160. mqApi.GET("/topics/:namespace/:topic", h.mqHandlers.GetTopicDetailsAPI)
  161. mqApi.POST("/topics/create", h.mqHandlers.CreateTopicAPI)
  162. mqApi.POST("/topics/retention/update", h.mqHandlers.UpdateTopicRetentionAPI)
  163. mqApi.POST("/retention/purge", h.adminServer.TriggerTopicRetentionPurgeAPI)
  164. }
  165. }
  166. } else {
  167. // No authentication required - all routes are public
  168. r.GET("/", h.ShowDashboard)
  169. r.GET("/admin", h.ShowDashboard)
  170. // Object Store management routes
  171. r.GET("/object-store/buckets", h.ShowS3Buckets)
  172. r.GET("/object-store/buckets/:bucket", h.ShowBucketDetails)
  173. r.GET("/object-store/users", h.userHandlers.ShowObjectStoreUsers)
  174. r.GET("/object-store/policies", h.policyHandlers.ShowPolicies)
  175. // File browser routes
  176. r.GET("/files", h.fileBrowserHandlers.ShowFileBrowser)
  177. // Cluster management routes
  178. r.GET("/cluster/masters", h.clusterHandlers.ShowClusterMasters)
  179. r.GET("/cluster/filers", h.clusterHandlers.ShowClusterFilers)
  180. r.GET("/cluster/volume-servers", h.clusterHandlers.ShowClusterVolumeServers)
  181. r.GET("/cluster/volumes", h.clusterHandlers.ShowClusterVolumes)
  182. r.GET("/cluster/volumes/:id/:server", h.clusterHandlers.ShowVolumeDetails)
  183. r.GET("/cluster/collections", h.clusterHandlers.ShowClusterCollections)
  184. r.GET("/cluster/collections/:name", h.clusterHandlers.ShowCollectionDetails)
  185. r.GET("/cluster/ec-shards", h.clusterHandlers.ShowClusterEcShards)
  186. r.GET("/cluster/ec-volumes/:id", h.clusterHandlers.ShowEcVolumeDetails)
  187. // Message Queue management routes
  188. r.GET("/mq/brokers", h.mqHandlers.ShowBrokers)
  189. r.GET("/mq/topics", h.mqHandlers.ShowTopics)
  190. r.GET("/mq/topics/:namespace/:topic", h.mqHandlers.ShowTopicDetails)
  191. // Maintenance system routes
  192. r.GET("/maintenance", h.maintenanceHandlers.ShowMaintenanceQueue)
  193. r.GET("/maintenance/workers", h.maintenanceHandlers.ShowMaintenanceWorkers)
  194. r.GET("/maintenance/config", h.maintenanceHandlers.ShowMaintenanceConfig)
  195. r.POST("/maintenance/config", h.maintenanceHandlers.UpdateMaintenanceConfig)
  196. r.GET("/maintenance/config/:taskType", h.maintenanceHandlers.ShowTaskConfig)
  197. r.POST("/maintenance/config/:taskType", h.maintenanceHandlers.UpdateTaskConfig)
  198. r.GET("/maintenance/tasks/:id", h.maintenanceHandlers.ShowTaskDetail)
  199. // API routes for AJAX calls
  200. api := r.Group("/api")
  201. {
  202. api.GET("/cluster/topology", h.clusterHandlers.GetClusterTopology)
  203. api.GET("/cluster/masters", h.clusterHandlers.GetMasters)
  204. api.GET("/cluster/volumes", h.clusterHandlers.GetVolumeServers)
  205. api.GET("/admin", h.adminServer.ShowAdmin) // JSON API for admin data
  206. api.GET("/config", h.adminServer.GetConfigInfo) // Configuration information
  207. // S3 API routes
  208. s3Api := api.Group("/s3")
  209. {
  210. s3Api.GET("/buckets", h.adminServer.ListBucketsAPI)
  211. s3Api.POST("/buckets", h.adminServer.CreateBucket)
  212. s3Api.DELETE("/buckets/:bucket", h.adminServer.DeleteBucket)
  213. s3Api.GET("/buckets/:bucket", h.adminServer.ShowBucketDetails)
  214. s3Api.PUT("/buckets/:bucket/quota", h.adminServer.UpdateBucketQuota)
  215. }
  216. // User management API routes
  217. usersApi := api.Group("/users")
  218. {
  219. usersApi.GET("", h.userHandlers.GetUsers)
  220. usersApi.POST("", h.userHandlers.CreateUser)
  221. usersApi.GET("/:username", h.userHandlers.GetUserDetails)
  222. usersApi.PUT("/:username", h.userHandlers.UpdateUser)
  223. usersApi.DELETE("/:username", h.userHandlers.DeleteUser)
  224. usersApi.POST("/:username/access-keys", h.userHandlers.CreateAccessKey)
  225. usersApi.DELETE("/:username/access-keys/:accessKeyId", h.userHandlers.DeleteAccessKey)
  226. usersApi.GET("/:username/policies", h.userHandlers.GetUserPolicies)
  227. usersApi.PUT("/:username/policies", h.userHandlers.UpdateUserPolicies)
  228. }
  229. // Object Store Policy management API routes
  230. objectStorePoliciesApi := api.Group("/object-store/policies")
  231. {
  232. objectStorePoliciesApi.GET("", h.policyHandlers.GetPolicies)
  233. objectStorePoliciesApi.POST("", h.policyHandlers.CreatePolicy)
  234. objectStorePoliciesApi.GET("/:name", h.policyHandlers.GetPolicy)
  235. objectStorePoliciesApi.PUT("/:name", h.policyHandlers.UpdatePolicy)
  236. objectStorePoliciesApi.DELETE("/:name", h.policyHandlers.DeletePolicy)
  237. objectStorePoliciesApi.POST("/validate", h.policyHandlers.ValidatePolicy)
  238. }
  239. // File management API routes
  240. filesApi := api.Group("/files")
  241. {
  242. filesApi.DELETE("/delete", h.fileBrowserHandlers.DeleteFile)
  243. filesApi.DELETE("/delete-multiple", h.fileBrowserHandlers.DeleteMultipleFiles)
  244. filesApi.POST("/create-folder", h.fileBrowserHandlers.CreateFolder)
  245. filesApi.POST("/upload", h.fileBrowserHandlers.UploadFile)
  246. filesApi.GET("/download", h.fileBrowserHandlers.DownloadFile)
  247. filesApi.GET("/view", h.fileBrowserHandlers.ViewFile)
  248. filesApi.GET("/properties", h.fileBrowserHandlers.GetFileProperties)
  249. }
  250. // Volume management API routes
  251. volumeApi := api.Group("/volumes")
  252. {
  253. volumeApi.POST("/:id/:server/vacuum", h.clusterHandlers.VacuumVolume)
  254. }
  255. // Maintenance API routes
  256. maintenanceApi := api.Group("/maintenance")
  257. {
  258. maintenanceApi.POST("/scan", h.adminServer.TriggerMaintenanceScan)
  259. maintenanceApi.GET("/tasks", h.adminServer.GetMaintenanceTasks)
  260. maintenanceApi.GET("/tasks/:id", h.adminServer.GetMaintenanceTask)
  261. maintenanceApi.GET("/tasks/:id/detail", h.adminServer.GetMaintenanceTaskDetailAPI)
  262. maintenanceApi.POST("/tasks/:id/cancel", h.adminServer.CancelMaintenanceTask)
  263. maintenanceApi.GET("/workers", h.adminServer.GetMaintenanceWorkersAPI)
  264. maintenanceApi.GET("/workers/:id", h.adminServer.GetMaintenanceWorker)
  265. maintenanceApi.GET("/workers/:id/logs", h.adminServer.GetWorkerLogs)
  266. maintenanceApi.GET("/stats", h.adminServer.GetMaintenanceStats)
  267. maintenanceApi.GET("/config", h.adminServer.GetMaintenanceConfigAPI)
  268. maintenanceApi.PUT("/config", h.adminServer.UpdateMaintenanceConfigAPI)
  269. }
  270. // Message Queue API routes
  271. mqApi := api.Group("/mq")
  272. {
  273. mqApi.GET("/topics/:namespace/:topic", h.mqHandlers.GetTopicDetailsAPI)
  274. mqApi.POST("/topics/create", h.mqHandlers.CreateTopicAPI)
  275. mqApi.POST("/topics/retention/update", h.mqHandlers.UpdateTopicRetentionAPI)
  276. mqApi.POST("/retention/purge", h.adminServer.TriggerTopicRetentionPurgeAPI)
  277. }
  278. }
  279. }
  280. }
  281. // HealthCheck returns the health status of the admin interface
  282. func (h *AdminHandlers) HealthCheck(c *gin.Context) {
  283. c.JSON(200, gin.H{"health": "ok"})
  284. }
  285. // ShowDashboard renders the main admin dashboard
  286. func (h *AdminHandlers) ShowDashboard(c *gin.Context) {
  287. // Get admin data from the server
  288. adminData := h.getAdminData(c)
  289. // Render HTML template
  290. c.Header("Content-Type", "text/html")
  291. adminComponent := app.Admin(adminData)
  292. layoutComponent := layout.Layout(c, adminComponent)
  293. err := layoutComponent.Render(c.Request.Context(), c.Writer)
  294. if err != nil {
  295. c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to render template: " + err.Error()})
  296. return
  297. }
  298. }
  299. // ShowS3Buckets renders the Object Store buckets management page
  300. func (h *AdminHandlers) ShowS3Buckets(c *gin.Context) {
  301. // Get Object Store buckets data from the server
  302. s3Data := h.getS3BucketsData(c)
  303. // Render HTML template
  304. c.Header("Content-Type", "text/html")
  305. s3Component := app.S3Buckets(s3Data)
  306. layoutComponent := layout.Layout(c, s3Component)
  307. err := layoutComponent.Render(c.Request.Context(), c.Writer)
  308. if err != nil {
  309. c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to render template: " + err.Error()})
  310. return
  311. }
  312. }
  313. // ShowBucketDetails returns detailed information about a specific bucket
  314. func (h *AdminHandlers) ShowBucketDetails(c *gin.Context) {
  315. bucketName := c.Param("bucket")
  316. details, err := h.adminServer.GetBucketDetails(bucketName)
  317. if err != nil {
  318. c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get bucket details: " + err.Error()})
  319. return
  320. }
  321. c.JSON(http.StatusOK, details)
  322. }
  323. // getS3BucketsData retrieves Object Store buckets data from the server
  324. func (h *AdminHandlers) getS3BucketsData(c *gin.Context) dash.S3BucketsData {
  325. username := c.GetString("username")
  326. if username == "" {
  327. username = "admin"
  328. }
  329. // Get Object Store buckets
  330. buckets, err := h.adminServer.GetS3Buckets()
  331. if err != nil {
  332. // Return empty data on error
  333. return dash.S3BucketsData{
  334. Username: username,
  335. Buckets: []dash.S3Bucket{},
  336. TotalBuckets: 0,
  337. TotalSize: 0,
  338. LastUpdated: time.Now(),
  339. }
  340. }
  341. // Calculate totals
  342. var totalSize int64
  343. for _, bucket := range buckets {
  344. totalSize += bucket.Size
  345. }
  346. return dash.S3BucketsData{
  347. Username: username,
  348. Buckets: buckets,
  349. TotalBuckets: len(buckets),
  350. TotalSize: totalSize,
  351. LastUpdated: time.Now(),
  352. }
  353. }
  354. // getAdminData retrieves admin data from the server (now uses consolidated method)
  355. func (h *AdminHandlers) getAdminData(c *gin.Context) dash.AdminData {
  356. username := c.GetString("username")
  357. // Use the consolidated GetAdminData method from AdminServer
  358. adminData, err := h.adminServer.GetAdminData(username)
  359. if err != nil {
  360. // Return default data when services are not available
  361. if username == "" {
  362. username = "admin"
  363. }
  364. masterNodes := []dash.MasterNode{
  365. {
  366. Address: "localhost:9333",
  367. IsLeader: true,
  368. },
  369. }
  370. return dash.AdminData{
  371. Username: username,
  372. TotalVolumes: 0,
  373. TotalFiles: 0,
  374. TotalSize: 0,
  375. MasterNodes: masterNodes,
  376. VolumeServers: []dash.VolumeServer{},
  377. FilerNodes: []dash.FilerNode{},
  378. DataCenters: []dash.DataCenter{},
  379. LastUpdated: time.Now(),
  380. }
  381. }
  382. return adminData
  383. }
  384. // Helper functions