aboutsummaryrefslogtreecommitdiff
path: root/weed/admin/handlers/admin_handlers.go
diff options
context:
space:
mode:
authorchrislu <chris.lu@gmail.com>2025-07-02 00:04:46 -0700
committerchrislu <chris.lu@gmail.com>2025-07-02 00:04:46 -0700
commit6b706f9ccdf46046133c867c4240c4e8594da5b3 (patch)
treecc57ff507de3f355ea6fab2175fb920a0120ae98 /weed/admin/handlers/admin_handlers.go
parentf47c4aef5a104a8c6ccd011ce441c453c4bebe62 (diff)
downloadseaweedfs-6b706f9ccdf46046133c867c4240c4e8594da5b3.tar.xz
seaweedfs-6b706f9ccdf46046133c867c4240c4e8594da5b3.zip
rename files
*_server.go - main server files *_management.go - business logic *_data.go - data structures and types *_middleware.go - middleware logic
Diffstat (limited to 'weed/admin/handlers/admin_handlers.go')
-rw-r--r--weed/admin/handlers/admin_handlers.go316
1 files changed, 316 insertions, 0 deletions
diff --git a/weed/admin/handlers/admin_handlers.go b/weed/admin/handlers/admin_handlers.go
new file mode 100644
index 000000000..a0140a25d
--- /dev/null
+++ b/weed/admin/handlers/admin_handlers.go
@@ -0,0 +1,316 @@
+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
+}
+
+// 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)
+ return &AdminHandlers{
+ adminServer: adminServer,
+ authHandlers: authHandlers,
+ clusterHandlers: clusterHandlers,
+ fileBrowserHandlers: fileBrowserHandlers,
+ userHandlers: userHandlers,
+ }
+}
+
+// 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)
+
+ // 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/collections", h.clusterHandlers.ShowClusterCollections)
+
+ // API routes for AJAX calls
+ api := protected.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
+
+ // 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)
+ }
+
+ // 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)
+ }
+ }
+ } 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)
+
+ // 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/collections", h.clusterHandlers.ShowClusterCollections)
+
+ // 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
+
+ // 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)
+ }
+
+ // 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)
+ }
+ }
+ }
+}
+
+// HealthCheck returns the health status of the admin interface
+func (h *AdminHandlers) HealthCheck(c *gin.Context) {
+ c.JSON(200, gin.H{"status": "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,
+ Status: "unreachable",
+ },
+ }
+
+ return dash.AdminData{
+ Username: username,
+ ClusterStatus: "warning",
+ TotalVolumes: 0,
+ TotalFiles: 0,
+ TotalSize: 0,
+ MasterNodes: masterNodes,
+ VolumeServers: []dash.VolumeServer{},
+ FilerNodes: []dash.FilerNode{},
+ DataCenters: []dash.DataCenter{},
+ LastUpdated: time.Now(),
+ SystemHealth: "poor",
+ }
+ }
+
+ return adminData
+}
+
+// Helper functions
+func (h *AdminHandlers) determineClusterStatus(topology *dash.ClusterTopology, masters []dash.MasterNode) string {
+ if len(topology.VolumeServers) == 0 {
+ return "warning"
+ }
+ return "healthy"
+}
+
+func (h *AdminHandlers) determineSystemHealth(topology *dash.ClusterTopology, masters []dash.MasterNode) string {
+ if len(topology.VolumeServers) > 0 && len(masters) > 0 {
+ return "good"
+ }
+ return "fair"
+}