| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434 |
- package handlers
- import (
- "net/http"
- "time"
- "github.com/gin-gonic/gin"
- "github.com/seaweedfs/seaweedfs/weed/admin/dash"
- "github.com/seaweedfs/seaweedfs/weed/admin/view/app"
- "github.com/seaweedfs/seaweedfs/weed/admin/view/layout"
- )
- // AdminHandlers contains all the HTTP handlers for the admin interface
- type AdminHandlers struct {
- adminServer *dash.AdminServer
- authHandlers *AuthHandlers
- clusterHandlers *ClusterHandlers
- fileBrowserHandlers *FileBrowserHandlers
- userHandlers *UserHandlers
- policyHandlers *PolicyHandlers
- maintenanceHandlers *MaintenanceHandlers
- mqHandlers *MessageQueueHandlers
- }
- // NewAdminHandlers creates a new instance of AdminHandlers
- func NewAdminHandlers(adminServer *dash.AdminServer) *AdminHandlers {
- authHandlers := NewAuthHandlers(adminServer)
- clusterHandlers := NewClusterHandlers(adminServer)
- fileBrowserHandlers := NewFileBrowserHandlers(adminServer)
- userHandlers := NewUserHandlers(adminServer)
- policyHandlers := NewPolicyHandlers(adminServer)
- maintenanceHandlers := NewMaintenanceHandlers(adminServer)
- mqHandlers := NewMessageQueueHandlers(adminServer)
- return &AdminHandlers{
- adminServer: adminServer,
- authHandlers: authHandlers,
- clusterHandlers: clusterHandlers,
- fileBrowserHandlers: fileBrowserHandlers,
- userHandlers: userHandlers,
- policyHandlers: policyHandlers,
- maintenanceHandlers: maintenanceHandlers,
- mqHandlers: mqHandlers,
- }
- }
- // SetupRoutes configures all the routes for the admin interface
- func (h *AdminHandlers) SetupRoutes(r *gin.Engine, authRequired bool, username, password string) {
- // Health check (no auth required)
- r.GET("/health", h.HealthCheck)
- if authRequired {
- // Authentication routes (no auth required)
- r.GET("/login", h.authHandlers.ShowLogin)
- r.POST("/login", h.authHandlers.HandleLogin(username, password))
- r.GET("/logout", h.authHandlers.HandleLogout)
- // Protected routes group
- protected := r.Group("/")
- protected.Use(dash.RequireAuth())
- // Main admin interface routes
- protected.GET("/", h.ShowDashboard)
- protected.GET("/admin", h.ShowDashboard)
- // Object Store management routes
- protected.GET("/object-store/buckets", h.ShowS3Buckets)
- protected.GET("/object-store/buckets/:bucket", h.ShowBucketDetails)
- protected.GET("/object-store/users", h.userHandlers.ShowObjectStoreUsers)
- protected.GET("/object-store/policies", h.policyHandlers.ShowPolicies)
- // File browser routes
- protected.GET("/files", h.fileBrowserHandlers.ShowFileBrowser)
- // Cluster management routes
- protected.GET("/cluster/masters", h.clusterHandlers.ShowClusterMasters)
- protected.GET("/cluster/filers", h.clusterHandlers.ShowClusterFilers)
- protected.GET("/cluster/volume-servers", h.clusterHandlers.ShowClusterVolumeServers)
- protected.GET("/cluster/volumes", h.clusterHandlers.ShowClusterVolumes)
- protected.GET("/cluster/volumes/:id/:server", h.clusterHandlers.ShowVolumeDetails)
- protected.GET("/cluster/collections", h.clusterHandlers.ShowClusterCollections)
- protected.GET("/cluster/collections/:name", h.clusterHandlers.ShowCollectionDetails)
- protected.GET("/cluster/ec-shards", h.clusterHandlers.ShowClusterEcShards)
- protected.GET("/cluster/ec-volumes/:id", h.clusterHandlers.ShowEcVolumeDetails)
- // Message Queue management routes
- protected.GET("/mq/brokers", h.mqHandlers.ShowBrokers)
- protected.GET("/mq/topics", h.mqHandlers.ShowTopics)
- protected.GET("/mq/topics/:namespace/:topic", h.mqHandlers.ShowTopicDetails)
- // Maintenance system routes
- protected.GET("/maintenance", h.maintenanceHandlers.ShowMaintenanceQueue)
- protected.GET("/maintenance/workers", h.maintenanceHandlers.ShowMaintenanceWorkers)
- protected.GET("/maintenance/config", h.maintenanceHandlers.ShowMaintenanceConfig)
- protected.POST("/maintenance/config", h.maintenanceHandlers.UpdateMaintenanceConfig)
- protected.GET("/maintenance/config/:taskType", h.maintenanceHandlers.ShowTaskConfig)
- protected.POST("/maintenance/config/:taskType", h.maintenanceHandlers.UpdateTaskConfig)
- protected.GET("/maintenance/tasks/:id", h.maintenanceHandlers.ShowTaskDetail)
- // API routes for AJAX calls
- api := r.Group("/api")
- api.Use(dash.RequireAuthAPI()) // Use API-specific auth middleware
- {
- api.GET("/cluster/topology", h.clusterHandlers.GetClusterTopology)
- api.GET("/cluster/masters", h.clusterHandlers.GetMasters)
- api.GET("/cluster/volumes", h.clusterHandlers.GetVolumeServers)
- api.GET("/admin", h.adminServer.ShowAdmin) // JSON API for admin data
- api.GET("/config", h.adminServer.GetConfigInfo) // Configuration information
- // S3 API routes
- s3Api := api.Group("/s3")
- {
- s3Api.GET("/buckets", h.adminServer.ListBucketsAPI)
- s3Api.POST("/buckets", h.adminServer.CreateBucket)
- s3Api.DELETE("/buckets/:bucket", h.adminServer.DeleteBucket)
- s3Api.GET("/buckets/:bucket", h.adminServer.ShowBucketDetails)
- s3Api.PUT("/buckets/:bucket/quota", h.adminServer.UpdateBucketQuota)
- }
- // User management API routes
- usersApi := api.Group("/users")
- {
- usersApi.GET("", h.userHandlers.GetUsers)
- usersApi.POST("", h.userHandlers.CreateUser)
- usersApi.GET("/:username", h.userHandlers.GetUserDetails)
- usersApi.PUT("/:username", h.userHandlers.UpdateUser)
- usersApi.DELETE("/:username", h.userHandlers.DeleteUser)
- usersApi.POST("/:username/access-keys", h.userHandlers.CreateAccessKey)
- usersApi.DELETE("/:username/access-keys/:accessKeyId", h.userHandlers.DeleteAccessKey)
- usersApi.GET("/:username/policies", h.userHandlers.GetUserPolicies)
- usersApi.PUT("/:username/policies", h.userHandlers.UpdateUserPolicies)
- }
- // Object Store Policy management API routes
- objectStorePoliciesApi := api.Group("/object-store/policies")
- {
- objectStorePoliciesApi.GET("", h.policyHandlers.GetPolicies)
- objectStorePoliciesApi.POST("", h.policyHandlers.CreatePolicy)
- objectStorePoliciesApi.GET("/:name", h.policyHandlers.GetPolicy)
- objectStorePoliciesApi.PUT("/:name", h.policyHandlers.UpdatePolicy)
- objectStorePoliciesApi.DELETE("/:name", h.policyHandlers.DeletePolicy)
- objectStorePoliciesApi.POST("/validate", h.policyHandlers.ValidatePolicy)
- }
- // File management API routes
- filesApi := api.Group("/files")
- {
- filesApi.DELETE("/delete", h.fileBrowserHandlers.DeleteFile)
- filesApi.DELETE("/delete-multiple", h.fileBrowserHandlers.DeleteMultipleFiles)
- filesApi.POST("/create-folder", h.fileBrowserHandlers.CreateFolder)
- filesApi.POST("/upload", h.fileBrowserHandlers.UploadFile)
- filesApi.GET("/download", h.fileBrowserHandlers.DownloadFile)
- filesApi.GET("/view", h.fileBrowserHandlers.ViewFile)
- filesApi.GET("/properties", h.fileBrowserHandlers.GetFileProperties)
- }
- // Volume management API routes
- volumeApi := api.Group("/volumes")
- {
- volumeApi.POST("/:id/:server/vacuum", h.clusterHandlers.VacuumVolume)
- }
- // Maintenance API routes
- maintenanceApi := api.Group("/maintenance")
- {
- maintenanceApi.POST("/scan", h.adminServer.TriggerMaintenanceScan)
- maintenanceApi.GET("/tasks", h.adminServer.GetMaintenanceTasks)
- maintenanceApi.GET("/tasks/:id", h.adminServer.GetMaintenanceTask)
- maintenanceApi.GET("/tasks/:id/detail", h.adminServer.GetMaintenanceTaskDetailAPI)
- maintenanceApi.POST("/tasks/:id/cancel", h.adminServer.CancelMaintenanceTask)
- maintenanceApi.GET("/workers", h.adminServer.GetMaintenanceWorkersAPI)
- maintenanceApi.GET("/workers/:id", h.adminServer.GetMaintenanceWorker)
- maintenanceApi.GET("/workers/:id/logs", h.adminServer.GetWorkerLogs)
- maintenanceApi.GET("/stats", h.adminServer.GetMaintenanceStats)
- maintenanceApi.GET("/config", h.adminServer.GetMaintenanceConfigAPI)
- maintenanceApi.PUT("/config", h.adminServer.UpdateMaintenanceConfigAPI)
- }
- // Message Queue API routes
- mqApi := api.Group("/mq")
- {
- mqApi.GET("/topics/:namespace/:topic", h.mqHandlers.GetTopicDetailsAPI)
- mqApi.POST("/topics/create", h.mqHandlers.CreateTopicAPI)
- mqApi.POST("/topics/retention/update", h.mqHandlers.UpdateTopicRetentionAPI)
- mqApi.POST("/retention/purge", h.adminServer.TriggerTopicRetentionPurgeAPI)
- }
- }
- } else {
- // No authentication required - all routes are public
- r.GET("/", h.ShowDashboard)
- r.GET("/admin", h.ShowDashboard)
- // Object Store management routes
- r.GET("/object-store/buckets", h.ShowS3Buckets)
- r.GET("/object-store/buckets/:bucket", h.ShowBucketDetails)
- r.GET("/object-store/users", h.userHandlers.ShowObjectStoreUsers)
- r.GET("/object-store/policies", h.policyHandlers.ShowPolicies)
- // File browser routes
- r.GET("/files", h.fileBrowserHandlers.ShowFileBrowser)
- // Cluster management routes
- r.GET("/cluster/masters", h.clusterHandlers.ShowClusterMasters)
- r.GET("/cluster/filers", h.clusterHandlers.ShowClusterFilers)
- r.GET("/cluster/volume-servers", h.clusterHandlers.ShowClusterVolumeServers)
- r.GET("/cluster/volumes", h.clusterHandlers.ShowClusterVolumes)
- r.GET("/cluster/volumes/:id/:server", h.clusterHandlers.ShowVolumeDetails)
- r.GET("/cluster/collections", h.clusterHandlers.ShowClusterCollections)
- r.GET("/cluster/collections/:name", h.clusterHandlers.ShowCollectionDetails)
- r.GET("/cluster/ec-shards", h.clusterHandlers.ShowClusterEcShards)
- r.GET("/cluster/ec-volumes/:id", h.clusterHandlers.ShowEcVolumeDetails)
- // Message Queue management routes
- r.GET("/mq/brokers", h.mqHandlers.ShowBrokers)
- r.GET("/mq/topics", h.mqHandlers.ShowTopics)
- r.GET("/mq/topics/:namespace/:topic", h.mqHandlers.ShowTopicDetails)
- // Maintenance system routes
- r.GET("/maintenance", h.maintenanceHandlers.ShowMaintenanceQueue)
- r.GET("/maintenance/workers", h.maintenanceHandlers.ShowMaintenanceWorkers)
- r.GET("/maintenance/config", h.maintenanceHandlers.ShowMaintenanceConfig)
- r.POST("/maintenance/config", h.maintenanceHandlers.UpdateMaintenanceConfig)
- r.GET("/maintenance/config/:taskType", h.maintenanceHandlers.ShowTaskConfig)
- r.POST("/maintenance/config/:taskType", h.maintenanceHandlers.UpdateTaskConfig)
- r.GET("/maintenance/tasks/:id", h.maintenanceHandlers.ShowTaskDetail)
- // API routes for AJAX calls
- api := r.Group("/api")
- {
- api.GET("/cluster/topology", h.clusterHandlers.GetClusterTopology)
- api.GET("/cluster/masters", h.clusterHandlers.GetMasters)
- api.GET("/cluster/volumes", h.clusterHandlers.GetVolumeServers)
- api.GET("/admin", h.adminServer.ShowAdmin) // JSON API for admin data
- api.GET("/config", h.adminServer.GetConfigInfo) // Configuration information
- // S3 API routes
- s3Api := api.Group("/s3")
- {
- s3Api.GET("/buckets", h.adminServer.ListBucketsAPI)
- s3Api.POST("/buckets", h.adminServer.CreateBucket)
- s3Api.DELETE("/buckets/:bucket", h.adminServer.DeleteBucket)
- s3Api.GET("/buckets/:bucket", h.adminServer.ShowBucketDetails)
- s3Api.PUT("/buckets/:bucket/quota", h.adminServer.UpdateBucketQuota)
- }
- // User management API routes
- usersApi := api.Group("/users")
- {
- usersApi.GET("", h.userHandlers.GetUsers)
- usersApi.POST("", h.userHandlers.CreateUser)
- usersApi.GET("/:username", h.userHandlers.GetUserDetails)
- usersApi.PUT("/:username", h.userHandlers.UpdateUser)
- usersApi.DELETE("/:username", h.userHandlers.DeleteUser)
- usersApi.POST("/:username/access-keys", h.userHandlers.CreateAccessKey)
- usersApi.DELETE("/:username/access-keys/:accessKeyId", h.userHandlers.DeleteAccessKey)
- usersApi.GET("/:username/policies", h.userHandlers.GetUserPolicies)
- usersApi.PUT("/:username/policies", h.userHandlers.UpdateUserPolicies)
- }
- // Object Store Policy management API routes
- objectStorePoliciesApi := api.Group("/object-store/policies")
- {
- objectStorePoliciesApi.GET("", h.policyHandlers.GetPolicies)
- objectStorePoliciesApi.POST("", h.policyHandlers.CreatePolicy)
- objectStorePoliciesApi.GET("/:name", h.policyHandlers.GetPolicy)
- objectStorePoliciesApi.PUT("/:name", h.policyHandlers.UpdatePolicy)
- objectStorePoliciesApi.DELETE("/:name", h.policyHandlers.DeletePolicy)
- objectStorePoliciesApi.POST("/validate", h.policyHandlers.ValidatePolicy)
- }
- // File management API routes
- filesApi := api.Group("/files")
- {
- filesApi.DELETE("/delete", h.fileBrowserHandlers.DeleteFile)
- filesApi.DELETE("/delete-multiple", h.fileBrowserHandlers.DeleteMultipleFiles)
- filesApi.POST("/create-folder", h.fileBrowserHandlers.CreateFolder)
- filesApi.POST("/upload", h.fileBrowserHandlers.UploadFile)
- filesApi.GET("/download", h.fileBrowserHandlers.DownloadFile)
- filesApi.GET("/view", h.fileBrowserHandlers.ViewFile)
- filesApi.GET("/properties", h.fileBrowserHandlers.GetFileProperties)
- }
- // Volume management API routes
- volumeApi := api.Group("/volumes")
- {
- volumeApi.POST("/:id/:server/vacuum", h.clusterHandlers.VacuumVolume)
- }
- // Maintenance API routes
- maintenanceApi := api.Group("/maintenance")
- {
- maintenanceApi.POST("/scan", h.adminServer.TriggerMaintenanceScan)
- maintenanceApi.GET("/tasks", h.adminServer.GetMaintenanceTasks)
- maintenanceApi.GET("/tasks/:id", h.adminServer.GetMaintenanceTask)
- maintenanceApi.GET("/tasks/:id/detail", h.adminServer.GetMaintenanceTaskDetailAPI)
- maintenanceApi.POST("/tasks/:id/cancel", h.adminServer.CancelMaintenanceTask)
- maintenanceApi.GET("/workers", h.adminServer.GetMaintenanceWorkersAPI)
- maintenanceApi.GET("/workers/:id", h.adminServer.GetMaintenanceWorker)
- maintenanceApi.GET("/workers/:id/logs", h.adminServer.GetWorkerLogs)
- maintenanceApi.GET("/stats", h.adminServer.GetMaintenanceStats)
- maintenanceApi.GET("/config", h.adminServer.GetMaintenanceConfigAPI)
- maintenanceApi.PUT("/config", h.adminServer.UpdateMaintenanceConfigAPI)
- }
- // Message Queue API routes
- mqApi := api.Group("/mq")
- {
- mqApi.GET("/topics/:namespace/:topic", h.mqHandlers.GetTopicDetailsAPI)
- mqApi.POST("/topics/create", h.mqHandlers.CreateTopicAPI)
- mqApi.POST("/topics/retention/update", h.mqHandlers.UpdateTopicRetentionAPI)
- mqApi.POST("/retention/purge", h.adminServer.TriggerTopicRetentionPurgeAPI)
- }
- }
- }
- }
- // HealthCheck returns the health status of the admin interface
- func (h *AdminHandlers) HealthCheck(c *gin.Context) {
- c.JSON(200, gin.H{"health": "ok"})
- }
- // ShowDashboard renders the main admin dashboard
- func (h *AdminHandlers) ShowDashboard(c *gin.Context) {
- // Get admin data from the server
- adminData := h.getAdminData(c)
- // Render HTML template
- c.Header("Content-Type", "text/html")
- adminComponent := app.Admin(adminData)
- layoutComponent := layout.Layout(c, adminComponent)
- err := layoutComponent.Render(c.Request.Context(), c.Writer)
- if err != nil {
- c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to render template: " + err.Error()})
- return
- }
- }
- // ShowS3Buckets renders the Object Store buckets management page
- func (h *AdminHandlers) ShowS3Buckets(c *gin.Context) {
- // Get Object Store buckets data from the server
- s3Data := h.getS3BucketsData(c)
- // Render HTML template
- c.Header("Content-Type", "text/html")
- s3Component := app.S3Buckets(s3Data)
- layoutComponent := layout.Layout(c, s3Component)
- err := layoutComponent.Render(c.Request.Context(), c.Writer)
- if err != nil {
- c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to render template: " + err.Error()})
- return
- }
- }
- // ShowBucketDetails returns detailed information about a specific bucket
- func (h *AdminHandlers) ShowBucketDetails(c *gin.Context) {
- bucketName := c.Param("bucket")
- details, err := h.adminServer.GetBucketDetails(bucketName)
- if err != nil {
- c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get bucket details: " + err.Error()})
- return
- }
- c.JSON(http.StatusOK, details)
- }
- // getS3BucketsData retrieves Object Store buckets data from the server
- func (h *AdminHandlers) getS3BucketsData(c *gin.Context) dash.S3BucketsData {
- username := c.GetString("username")
- if username == "" {
- username = "admin"
- }
- // Get Object Store buckets
- buckets, err := h.adminServer.GetS3Buckets()
- if err != nil {
- // Return empty data on error
- return dash.S3BucketsData{
- Username: username,
- Buckets: []dash.S3Bucket{},
- TotalBuckets: 0,
- TotalSize: 0,
- LastUpdated: time.Now(),
- }
- }
- // Calculate totals
- var totalSize int64
- for _, bucket := range buckets {
- totalSize += bucket.Size
- }
- return dash.S3BucketsData{
- Username: username,
- Buckets: buckets,
- TotalBuckets: len(buckets),
- TotalSize: totalSize,
- LastUpdated: time.Now(),
- }
- }
- // getAdminData retrieves admin data from the server (now uses consolidated method)
- func (h *AdminHandlers) getAdminData(c *gin.Context) dash.AdminData {
- username := c.GetString("username")
- // Use the consolidated GetAdminData method from AdminServer
- adminData, err := h.adminServer.GetAdminData(username)
- if err != nil {
- // Return default data when services are not available
- if username == "" {
- username = "admin"
- }
- masterNodes := []dash.MasterNode{
- {
- Address: "localhost:9333",
- IsLeader: true,
- },
- }
- return dash.AdminData{
- Username: username,
- TotalVolumes: 0,
- TotalFiles: 0,
- TotalSize: 0,
- MasterNodes: masterNodes,
- VolumeServers: []dash.VolumeServer{},
- FilerNodes: []dash.FilerNode{},
- DataCenters: []dash.DataCenter{},
- LastUpdated: time.Now(),
- }
- }
- return adminData
- }
- // Helper functions
|