admin_data.go 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. package dash
  2. import (
  3. "context"
  4. "net/http"
  5. "time"
  6. "github.com/gin-gonic/gin"
  7. "github.com/seaweedfs/seaweedfs/weed/cluster"
  8. "github.com/seaweedfs/seaweedfs/weed/glog"
  9. "github.com/seaweedfs/seaweedfs/weed/pb/master_pb"
  10. )
  11. type AdminData struct {
  12. Username string `json:"username"`
  13. TotalVolumes int `json:"total_volumes"`
  14. TotalFiles int64 `json:"total_files"`
  15. TotalSize int64 `json:"total_size"`
  16. VolumeSizeLimitMB uint64 `json:"volume_size_limit_mb"`
  17. MasterNodes []MasterNode `json:"master_nodes"`
  18. VolumeServers []VolumeServer `json:"volume_servers"`
  19. FilerNodes []FilerNode `json:"filer_nodes"`
  20. MessageBrokers []MessageBrokerNode `json:"message_brokers"`
  21. DataCenters []DataCenter `json:"datacenters"`
  22. LastUpdated time.Time `json:"last_updated"`
  23. // EC shard totals for dashboard
  24. TotalEcVolumes int `json:"total_ec_volumes"` // Total number of EC volumes across all servers
  25. TotalEcShards int `json:"total_ec_shards"` // Total number of EC shards across all servers
  26. }
  27. // Object Store Users management structures
  28. type ObjectStoreUser struct {
  29. Username string `json:"username"`
  30. Email string `json:"email"`
  31. AccessKey string `json:"access_key"`
  32. SecretKey string `json:"secret_key"`
  33. Permissions []string `json:"permissions"`
  34. }
  35. type ObjectStoreUsersData struct {
  36. Username string `json:"username"`
  37. Users []ObjectStoreUser `json:"users"`
  38. TotalUsers int `json:"total_users"`
  39. LastUpdated time.Time `json:"last_updated"`
  40. }
  41. // User management request structures
  42. type CreateUserRequest struct {
  43. Username string `json:"username" binding:"required"`
  44. Email string `json:"email"`
  45. Actions []string `json:"actions"`
  46. GenerateKey bool `json:"generate_key"`
  47. }
  48. type UpdateUserRequest struct {
  49. Email string `json:"email"`
  50. Actions []string `json:"actions"`
  51. }
  52. type UpdateUserPoliciesRequest struct {
  53. Actions []string `json:"actions" binding:"required"`
  54. }
  55. type AccessKeyInfo struct {
  56. AccessKey string `json:"access_key"`
  57. SecretKey string `json:"secret_key"`
  58. CreatedAt time.Time `json:"created_at"`
  59. }
  60. type UserDetails struct {
  61. Username string `json:"username"`
  62. Email string `json:"email"`
  63. Actions []string `json:"actions"`
  64. AccessKeys []AccessKeyInfo `json:"access_keys"`
  65. }
  66. type FilerNode struct {
  67. Address string `json:"address"`
  68. DataCenter string `json:"datacenter"`
  69. Rack string `json:"rack"`
  70. LastUpdated time.Time `json:"last_updated"`
  71. }
  72. type MessageBrokerNode struct {
  73. Address string `json:"address"`
  74. DataCenter string `json:"datacenter"`
  75. Rack string `json:"rack"`
  76. LastUpdated time.Time `json:"last_updated"`
  77. }
  78. // GetAdminData retrieves admin data as a struct (for reuse by both JSON and HTML handlers)
  79. func (s *AdminServer) GetAdminData(username string) (AdminData, error) {
  80. if username == "" {
  81. username = "admin"
  82. }
  83. // Get cluster topology
  84. topology, err := s.GetClusterTopology()
  85. if err != nil {
  86. glog.Errorf("Failed to get cluster topology: %v", err)
  87. return AdminData{}, err
  88. }
  89. // Get volume servers data with EC shard information
  90. volumeServersData, err := s.GetClusterVolumeServers()
  91. if err != nil {
  92. glog.Errorf("Failed to get cluster volume servers: %v", err)
  93. return AdminData{}, err
  94. }
  95. // Get master nodes status
  96. masterNodes := s.getMasterNodesStatus()
  97. // Get filer nodes status
  98. filerNodes := s.getFilerNodesStatus()
  99. // Get message broker nodes status
  100. messageBrokers := s.getMessageBrokerNodesStatus()
  101. // Get volume size limit from master configuration
  102. var volumeSizeLimitMB uint64 = 30000 // Default to 30GB
  103. err = s.WithMasterClient(func(client master_pb.SeaweedClient) error {
  104. resp, err := client.GetMasterConfiguration(context.Background(), &master_pb.GetMasterConfigurationRequest{})
  105. if err != nil {
  106. return err
  107. }
  108. volumeSizeLimitMB = uint64(resp.VolumeSizeLimitMB)
  109. return nil
  110. })
  111. if err != nil {
  112. glog.Warningf("Failed to get volume size limit from master: %v", err)
  113. // Keep default value on error
  114. }
  115. // Calculate EC shard totals
  116. var totalEcVolumes, totalEcShards int
  117. ecVolumeSet := make(map[uint32]bool) // To avoid counting the same EC volume multiple times
  118. for _, vs := range volumeServersData.VolumeServers {
  119. totalEcShards += vs.EcShards
  120. // Count unique EC volumes across all servers
  121. for _, ecInfo := range vs.EcShardDetails {
  122. ecVolumeSet[ecInfo.VolumeID] = true
  123. }
  124. }
  125. totalEcVolumes = len(ecVolumeSet)
  126. // Prepare admin data
  127. adminData := AdminData{
  128. Username: username,
  129. TotalVolumes: topology.TotalVolumes,
  130. TotalFiles: topology.TotalFiles,
  131. TotalSize: topology.TotalSize,
  132. VolumeSizeLimitMB: volumeSizeLimitMB,
  133. MasterNodes: masterNodes,
  134. VolumeServers: volumeServersData.VolumeServers,
  135. FilerNodes: filerNodes,
  136. MessageBrokers: messageBrokers,
  137. DataCenters: topology.DataCenters,
  138. LastUpdated: topology.UpdatedAt,
  139. TotalEcVolumes: totalEcVolumes,
  140. TotalEcShards: totalEcShards,
  141. }
  142. return adminData, nil
  143. }
  144. // ShowAdmin displays the main admin page (now uses GetAdminData)
  145. func (s *AdminServer) ShowAdmin(c *gin.Context) {
  146. username := c.GetString("username")
  147. adminData, err := s.GetAdminData(username)
  148. if err != nil {
  149. c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get admin data: " + err.Error()})
  150. return
  151. }
  152. // Return JSON for API calls
  153. c.JSON(http.StatusOK, adminData)
  154. }
  155. // ShowOverview displays cluster overview
  156. func (s *AdminServer) ShowOverview(c *gin.Context) {
  157. topology, err := s.GetClusterTopology()
  158. if err != nil {
  159. c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
  160. return
  161. }
  162. c.JSON(http.StatusOK, topology)
  163. }
  164. // getMasterNodesStatus checks status of all master nodes
  165. func (s *AdminServer) getMasterNodesStatus() []MasterNode {
  166. var masterNodes []MasterNode
  167. // Since we have a single master address, create one entry
  168. var isLeader bool = true // Assume leader since it's the only master we know about
  169. // Try to get leader info from this master
  170. err := s.WithMasterClient(func(client master_pb.SeaweedClient) error {
  171. _, err := client.GetMasterConfiguration(context.Background(), &master_pb.GetMasterConfigurationRequest{})
  172. if err != nil {
  173. return err
  174. }
  175. // For now, assume this master is the leader since we can connect to it
  176. isLeader = true
  177. return nil
  178. })
  179. if err != nil {
  180. isLeader = false
  181. }
  182. currentMaster := s.masterClient.GetMaster(context.Background())
  183. if currentMaster != "" {
  184. masterNodes = append(masterNodes, MasterNode{
  185. Address: string(currentMaster),
  186. IsLeader: isLeader,
  187. })
  188. }
  189. return masterNodes
  190. }
  191. // getFilerNodesStatus checks status of all filer nodes using master's ListClusterNodes
  192. func (s *AdminServer) getFilerNodesStatus() []FilerNode {
  193. var filerNodes []FilerNode
  194. // Get filer nodes from master using ListClusterNodes
  195. err := s.WithMasterClient(func(client master_pb.SeaweedClient) error {
  196. resp, err := client.ListClusterNodes(context.Background(), &master_pb.ListClusterNodesRequest{
  197. ClientType: cluster.FilerType,
  198. })
  199. if err != nil {
  200. return err
  201. }
  202. // Process each filer node
  203. for _, node := range resp.ClusterNodes {
  204. filerNodes = append(filerNodes, FilerNode{
  205. Address: node.Address,
  206. DataCenter: node.DataCenter,
  207. Rack: node.Rack,
  208. LastUpdated: time.Now(),
  209. })
  210. }
  211. return nil
  212. })
  213. if err != nil {
  214. currentMaster := s.masterClient.GetMaster(context.Background())
  215. glog.Errorf("Failed to get filer nodes from master %s: %v", currentMaster, err)
  216. // Return empty list if we can't get filer info from master
  217. return []FilerNode{}
  218. }
  219. return filerNodes
  220. }
  221. // getMessageBrokerNodesStatus checks status of all message broker nodes using master's ListClusterNodes
  222. func (s *AdminServer) getMessageBrokerNodesStatus() []MessageBrokerNode {
  223. var messageBrokers []MessageBrokerNode
  224. // Get message broker nodes from master using ListClusterNodes
  225. err := s.WithMasterClient(func(client master_pb.SeaweedClient) error {
  226. resp, err := client.ListClusterNodes(context.Background(), &master_pb.ListClusterNodesRequest{
  227. ClientType: cluster.BrokerType,
  228. })
  229. if err != nil {
  230. return err
  231. }
  232. // Process each message broker node
  233. for _, node := range resp.ClusterNodes {
  234. messageBrokers = append(messageBrokers, MessageBrokerNode{
  235. Address: node.Address,
  236. DataCenter: node.DataCenter,
  237. Rack: node.Rack,
  238. LastUpdated: time.Now(),
  239. })
  240. }
  241. return nil
  242. })
  243. if err != nil {
  244. currentMaster := s.masterClient.GetMaster(context.Background())
  245. glog.Errorf("Failed to get message broker nodes from master %s: %v", currentMaster, err)
  246. // Return empty list if we can't get broker info from master
  247. return []MessageBrokerNode{}
  248. }
  249. return messageBrokers
  250. }