diff options
| author | chrislu <chris.lu@gmail.com> | 2025-07-02 00:04:46 -0700 |
|---|---|---|
| committer | chrislu <chris.lu@gmail.com> | 2025-07-02 00:04:46 -0700 |
| commit | 6b706f9ccdf46046133c867c4240c4e8594da5b3 (patch) | |
| tree | cc57ff507de3f355ea6fab2175fb920a0120ae98 /weed/admin/handlers/admin_handlers.go | |
| parent | f47c4aef5a104a8c6ccd011ce441c453c4bebe62 (diff) | |
| download | seaweedfs-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.go | 316 |
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" +} |
