diff --git a/models/admin_info_response.go b/models/admin_info_response.go index 87481b60c..c221669e5 100644 --- a/models/admin_info_response.go +++ b/models/admin_info_response.go @@ -42,6 +42,9 @@ type AdminInfoResponse struct { // objects Objects int64 `json:"objects,omitempty"` + // servers + Servers []*ServerProperties `json:"servers"` + // usage Usage int64 `json:"usage,omitempty"` @@ -53,6 +56,10 @@ type AdminInfoResponse struct { func (m *AdminInfoResponse) Validate(formats strfmt.Registry) error { var res []error + if err := m.validateServers(formats); err != nil { + res = append(res, err) + } + if err := m.validateWidgets(formats); err != nil { res = append(res, err) } @@ -63,6 +70,30 @@ func (m *AdminInfoResponse) Validate(formats strfmt.Registry) error { return nil } +func (m *AdminInfoResponse) validateServers(formats strfmt.Registry) error { + if swag.IsZero(m.Servers) { // not required + return nil + } + + for i := 0; i < len(m.Servers); i++ { + if swag.IsZero(m.Servers[i]) { // not required + continue + } + + if m.Servers[i] != nil { + if err := m.Servers[i].Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("servers" + "." + strconv.Itoa(i)) + } + return err + } + } + + } + + return nil +} + func (m *AdminInfoResponse) validateWidgets(formats strfmt.Registry) error { if swag.IsZero(m.Widgets) { // not required return nil @@ -91,6 +122,10 @@ func (m *AdminInfoResponse) validateWidgets(formats strfmt.Registry) error { func (m *AdminInfoResponse) ContextValidate(ctx context.Context, formats strfmt.Registry) error { var res []error + if err := m.contextValidateServers(ctx, formats); err != nil { + res = append(res, err) + } + if err := m.contextValidateWidgets(ctx, formats); err != nil { res = append(res, err) } @@ -101,6 +136,24 @@ func (m *AdminInfoResponse) ContextValidate(ctx context.Context, formats strfmt. return nil } +func (m *AdminInfoResponse) contextValidateServers(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Servers); i++ { + + if m.Servers[i] != nil { + if err := m.Servers[i].ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("servers" + "." + strconv.Itoa(i)) + } + return err + } + } + + } + + return nil +} + func (m *AdminInfoResponse) contextValidateWidgets(ctx context.Context, formats strfmt.Registry) error { for i := 0; i < len(m.Widgets); i++ { diff --git a/models/server_properties.go b/models/server_properties.go new file mode 100644 index 000000000..d119b9b24 --- /dev/null +++ b/models/server_properties.go @@ -0,0 +1,82 @@ +// Code generated by go-swagger; DO NOT EDIT. + +// This file is part of MinIO Console Server +// Copyright (c) 2021 MinIO, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// + +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// ServerProperties server properties +// +// swagger:model serverProperties +type ServerProperties struct { + + // commit ID + CommitID string `json:"commitID,omitempty"` + + // endpoint + Endpoint string `json:"endpoint,omitempty"` + + // pool number + PoolNumber int64 `json:"poolNumber,omitempty"` + + // state + State string `json:"state,omitempty"` + + // uptime + Uptime string `json:"uptime,omitempty"` + + // version + Version string `json:"version,omitempty"` +} + +// Validate validates this server properties +func (m *ServerProperties) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this server properties based on context it is used +func (m *ServerProperties) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *ServerProperties) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *ServerProperties) UnmarshalBinary(b []byte) error { + var res ServerProperties + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/portal-ui/src/screens/Console/Dashboard/BasicDashboard/BasicDashboard.tsx b/portal-ui/src/screens/Console/Dashboard/BasicDashboard/BasicDashboard.tsx index ced1ba662..e975a39e4 100644 --- a/portal-ui/src/screens/Console/Dashboard/BasicDashboard/BasicDashboard.tsx +++ b/portal-ui/src/screens/Console/Dashboard/BasicDashboard/BasicDashboard.tsx @@ -14,17 +14,20 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -import React, { Fragment } from "react"; +import React, { Fragment, useState } from "react"; import { createStyles, Theme, withStyles } from "@material-ui/core/styles"; import clsx from "clsx"; import Grid from "@material-ui/core/Grid"; import Paper from "@material-ui/core/Paper"; import Typography from "@material-ui/core/Typography"; -import { Usage } from "../types"; -import { niceBytes } from "../../../../common/utils"; +import { Usage, ServerInfo } from "../types"; +import { niceBytes, niceDays } from "../../../../common/utils"; import AllBucketsIcon from "../../../../icons/AllBucketsIcon"; import UsageIcon from "../../../../icons/UsageIcon"; +import DnsIcon from "@material-ui/icons/Dns"; import EgressIcon from "../../../../icons/EgressIcon"; +import TableWrapper from "../../Common/TableWrapper/TableWrapper"; +import { TableContainer } from "@material-ui/core"; const styles = (theme: Theme) => createStyles({ @@ -57,6 +60,7 @@ const styles = (theme: Theme) => }, notationContainer: { display: "flex", + flexWrap: "wrap", }, dashboardBG: { width: 390, @@ -120,6 +124,45 @@ const BasicDashboard = ({ classes, usage }: IDashboardProps) => { return usage.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); }; + const serverColumns = [ + { + label: "Endpoint", + elementKey: "endpoint", + }, + { + label: "Status", + elementKey: "state", + }, + { + label: "Uptime", + elementKey: "uptime", + }, + { + label: "Version", + elementKey: "version", + }, + ]; + + const makeServerArray = (usage: Usage | null) => { + if (usage != null) { + usage.servers.forEach(s => s.uptime = niceDays(s.uptime)) + return usage.servers.sort(function (a, b) { + var nameA = a.endpoint.toUpperCase(); + var nameB = b.endpoint.toUpperCase(); + if (nameA < nameB) { + return -1; + } + if (nameA > nameB) { + return 1; + } + return 0; + }); + } + else return []; + }; + + const serverArray = makeServerArray(usage); + return (
@@ -172,6 +215,24 @@ const BasicDashboard = ({ classes, usage }: IDashboardProps) => { {usage ? prettyNumber(usage.objects) : 0} + + + + + + + {" "} + Servers + + + + diff --git a/portal-ui/src/screens/Console/Dashboard/types.tsx b/portal-ui/src/screens/Console/Dashboard/types.tsx index d76075e62..69c314e6a 100644 --- a/portal-ui/src/screens/Console/Dashboard/types.tsx +++ b/portal-ui/src/screens/Console/Dashboard/types.tsx @@ -19,4 +19,14 @@ export interface Usage { buckets: number; objects: number; widgets?: any; + servers: ServerInfo[]; +} + +export interface ServerInfo { + state: string; + endpoint: string; + uptime: string; + version: string; + commitID: string; + poolNumber: number; } diff --git a/restapi/admin_info.go b/restapi/admin_info.go index e7aebd4ed..7aa781f77 100644 --- a/restapi/admin_info.go +++ b/restapi/admin_info.go @@ -24,6 +24,7 @@ import ( "net/http" "net/url" "regexp" + "strconv" "strings" "time" @@ -62,6 +63,7 @@ type UsageInfo struct { Objects int64 Usage int64 DisksUsage int64 + Servers []*models.ServerProperties } // GetAdminInfo invokes admin info and returns a parsed `UsageInfo` structure @@ -80,11 +82,27 @@ func GetAdminInfo(ctx context.Context, client MinioAdmin) (*UsageInfo, error) { } } + //serverArray contains the serverProperties which describe the servers in the network + var serverArray []*models.ServerProperties + for _, serv := range serverInfo.Servers { + var newServer = &models.ServerProperties{ + State: serv.State, + Endpoint: serv.Endpoint, + Uptime: strconv.Itoa(int(serv.Uptime)), + Version: serv.Version, + CommitID: serv.CommitID, + PoolNumber: int64(serv.PoolNumber), + } + + serverArray = append(serverArray, newServer) + } + return &UsageInfo{ Buckets: int64(serverInfo.Buckets.Count), Objects: int64(serverInfo.Objects.Count), Usage: int64(serverInfo.Usage.Size), DisksUsage: usedSpace, + Servers: serverArray, }, nil } @@ -820,6 +838,7 @@ func getUsageWidgetsForDeployment(prometheusURL string, mAdmin *madmin.AdminClie Buckets: usage.Buckets, Objects: usage.Objects, Usage: usage.Usage, + Servers: usage.Servers, } return sessionResp, nil } diff --git a/restapi/embedded_spec.go b/restapi/embedded_spec.go index 4e3ceb9cf..b920accd2 100644 --- a/restapi/embedded_spec.go +++ b/restapi/embedded_spec.go @@ -3517,6 +3517,12 @@ func init() { "objects": { "type": "integer" }, + "servers": { + "type": "array", + "items": { + "$ref": "#/definitions/serverProperties" + } + }, "usage": { "type": "integer" }, @@ -4855,6 +4861,29 @@ func init() { } } }, + "serverProperties": { + "type": "object", + "properties": { + "commitID": { + "type": "string" + }, + "endpoint": { + "type": "string" + }, + "poolNumber": { + "type": "integer" + }, + "state": { + "type": "string" + }, + "uptime": { + "type": "string" + }, + "version": { + "type": "string" + } + } + }, "serviceAccountCreds": { "type": "object", "properties": { @@ -8935,6 +8964,12 @@ func init() { "objects": { "type": "integer" }, + "servers": { + "type": "array", + "items": { + "$ref": "#/definitions/serverProperties" + } + }, "usage": { "type": "integer" }, @@ -10273,6 +10308,29 @@ func init() { } } }, + "serverProperties": { + "type": "object", + "properties": { + "commitID": { + "type": "string" + }, + "endpoint": { + "type": "string" + }, + "poolNumber": { + "type": "integer" + }, + "state": { + "type": "string" + }, + "uptime": { + "type": "string" + }, + "version": { + "type": "string" + } + } + }, "serviceAccountCreds": { "type": "object", "properties": { diff --git a/swagger-console.yml b/swagger-console.yml index a4b415e9d..2763e0dd4 100644 --- a/swagger-console.yml +++ b/swagger-console.yml @@ -389,7 +389,7 @@ paths: schema: type: array items: - $ref: "#/definitions/deleteFile" + $ref: "#/definitions/deleteFile" responses: 200: description: A successful response. @@ -1046,7 +1046,7 @@ paths: $ref: "#/definitions/error" tags: - UserAPI - + /buckets/{bucket_name}/rewind/{date}: get: summary: Get objects in a bucket for a rewind date @@ -1074,7 +1074,7 @@ paths: schema: $ref: "#/definitions/error" tags: - - UserAPI + - UserAPI /service-accounts: get: @@ -1935,7 +1935,6 @@ paths: tags: - AdminAPI - /admin/info: get: summary: Returns information about the deployment @@ -3085,6 +3084,25 @@ definitions: type: array items: $ref: "#/definitions/widget" + servers: + type: array + items: + $ref: "#/definitions/serverProperties" + serverProperties: + type: object + properties: + state: + type: string + endpoint: + type: string + uptime: + type: string + version: + type: string + commitID: + type: string + poolNumber: + type: integer arnsResponse: type: object properties: @@ -3300,7 +3318,6 @@ definitions: object_locking_enabled: type: boolean - logSearchResponse: type: object properties: @@ -3308,8 +3325,6 @@ definitions: type: object title: list of log search responses - - objectLegalHoldStatus: type: string enum: @@ -3559,7 +3574,6 @@ definitions: items: $ref: "#/definitions/permissionAction" - tier_s3: type: object properties: @@ -3679,7 +3693,7 @@ definitions: type: string name: type: string - + rewindResponse: type: object properties: