aboutsummaryrefslogtreecommitdiff
path: root/weed/admin/handlers/handlers.go
diff options
context:
space:
mode:
Diffstat (limited to 'weed/admin/handlers/handlers.go')
-rw-r--r--weed/admin/handlers/handlers.go320
1 files changed, 320 insertions, 0 deletions
diff --git a/weed/admin/handlers/handlers.go b/weed/admin/handlers/handlers.go
new file mode 100644
index 000000000..2a7dc65a5
--- /dev/null
+++ b/weed/admin/handlers/handlers.go
@@ -0,0 +1,320 @@
+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
+}
+
+// NewAdminHandlers creates a new instance of AdminHandlers
+func NewAdminHandlers(adminServer *dash.AdminServer) *AdminHandlers {
+ authHandlers := NewAuthHandlers(adminServer)
+ clusterHandlers := NewClusterHandlers(adminServer)
+ fileBrowserHandlers := NewFileBrowserHandlers(adminServer)
+ return &AdminHandlers{
+ adminServer: adminServer,
+ authHandlers: authHandlers,
+ clusterHandlers: clusterHandlers,
+ fileBrowserHandlers: fileBrowserHandlers,
+ }
+}
+
+// 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.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)
+ }
+
+ // 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)
+ }
+ }
+ } 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.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)
+ }
+
+ // 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)
+ }
+ }
+ }
+}
+
+// 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 S3 buckets management page
+func (h *AdminHandlers) ShowS3Buckets(c *gin.Context) {
+ // Get S3 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)
+}
+
+// ShowObjectStoreUsers renders the object store users management page
+func (h *AdminHandlers) ShowObjectStoreUsers(c *gin.Context) {
+ // Get object store users data from the server
+ usersData := h.getObjectStoreUsersData(c)
+
+ // Render HTML template
+ c.Header("Content-Type", "text/html")
+ usersComponent := app.ObjectStoreUsers(usersData)
+ layoutComponent := layout.Layout(c, usersComponent)
+ 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
+ }
+}
+
+// getS3BucketsData retrieves S3 buckets data from the server
+func (h *AdminHandlers) getS3BucketsData(c *gin.Context) dash.S3BucketsData {
+ username := c.GetString("username")
+ if username == "" {
+ username = "admin"
+ }
+
+ // Get S3 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(),
+ }
+}
+
+// getObjectStoreUsersData retrieves object store users data from the server
+func (h *AdminHandlers) getObjectStoreUsersData(c *gin.Context) dash.ObjectStoreUsersData {
+ username := c.GetString("username")
+ if username == "" {
+ username = "admin"
+ }
+
+ // Get object store users
+ users, err := h.adminServer.GetObjectStoreUsers()
+ if err != nil {
+ // Return empty data on error
+ return dash.ObjectStoreUsersData{
+ Username: username,
+ Users: []dash.ObjectStoreUser{},
+ TotalUsers: 0,
+ LastUpdated: time.Now(),
+ }
+ }
+
+ return dash.ObjectStoreUsersData{
+ Username: username,
+ Users: users,
+ TotalUsers: len(users),
+ 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"
+}