From b02e6494056e0e835458784ae53854f81cc4f7f9 Mon Sep 17 00:00:00 2001 From: Alex <33497058+bexsoft@users.noreply.github.com> Date: Tue, 31 May 2022 10:03:58 -0500 Subject: [PATCH] Fixed dashboards capacity Widgets (#2055) - Added new calculation for prometheus capacity - Added indicator colors to capacity widgets - Adjusted capacity in drives for common dashboard Signed-off-by: Benjamin Perez --- portal-ui/src/common/types.ts | 5 + portal-ui/src/common/utils.ts | 15 ++- .../BasicDashboard/DriveInfoItem.tsx | 12 +- .../Prometheus/Widgets/CapacityItem.tsx | 117 +++++++++++++----- .../Console/Dashboard/Prometheus/utils.tsx | 75 ++++++++--- restapi/admin_info.go | 44 ++++++- 6 files changed, 208 insertions(+), 60 deletions(-) diff --git a/portal-ui/src/common/types.ts b/portal-ui/src/common/types.ts index 7371c09ab..de9636b0c 100644 --- a/portal-ui/src/common/types.ts +++ b/portal-ui/src/common/types.ts @@ -456,3 +456,8 @@ export interface IRetentionConfig { unit: string; validity: number; } + +export interface IBytesCalc { + total: number; + unit: string; +} diff --git a/portal-ui/src/common/utils.ts b/portal-ui/src/common/utils.ts index 124e6120a..650a9b8a7 100644 --- a/portal-ui/src/common/utils.ts +++ b/portal-ui/src/common/utils.ts @@ -16,6 +16,7 @@ import storage from "local-storage-fallback"; import { + IBytesCalc, ICapacity, IErasureCodeCalc, IStorageDistribution, @@ -576,7 +577,7 @@ export const calculateBytes = ( showDecimals = false, roundFloor = true, k8sUnit = false -) => { +): IBytesCalc => { let bytes; if (typeof x === "string") { @@ -696,3 +697,15 @@ export const getCookieValue = (cookieName: string) => { ?.pop() || "" ); }; + +export const capacityColors = (usedSpace: number, maxSpace: number) => { + const percCalculate = (usedSpace * 100) / maxSpace; + + if (percCalculate >= 90) { + return "#C83B51"; + } else if (percCalculate >= 70) { + return "#FFAB0F"; + } + + return "#07193E"; +}; diff --git a/portal-ui/src/screens/Console/Dashboard/BasicDashboard/DriveInfoItem.tsx b/portal-ui/src/screens/Console/Dashboard/BasicDashboard/DriveInfoItem.tsx index f0c8994d5..dccd118e1 100644 --- a/portal-ui/src/screens/Console/Dashboard/BasicDashboard/DriveInfoItem.tsx +++ b/portal-ui/src/screens/Console/Dashboard/BasicDashboard/DriveInfoItem.tsx @@ -19,7 +19,11 @@ import { Theme } from "@mui/material/styles"; import createStyles from "@mui/styles/createStyles"; import withStyles from "@mui/styles/withStyles"; import { IDriveInfo } from "../types"; -import { niceBytes, niceBytesInt } from "../../../../common/utils"; +import { + capacityColors, + niceBytes, + niceBytesInt, +} from "../../../../common/utils"; import { Box } from "@mui/material"; import { Cell, Pie, PieChart } from "recharts"; import { CircleIcon } from "../../../../icons"; @@ -48,11 +52,13 @@ const driveStatusColor = (health_status: string) => { }; const DriveInfoItem = ({ drive }: ICardProps) => { + const freeSpace = drive.totalSpace - drive.usedSpace; + const plotValues = [ - { value: drive.totalSpace, color: "#D6D6D6", label: "Free Space" }, + { value: freeSpace, color: "#D6D6D6", label: "Free Space" }, { value: drive.usedSpace, - color: "#073052", + color: capacityColors(drive.usedSpace, drive.totalSpace), label: "Used Space", }, ]; diff --git a/portal-ui/src/screens/Console/Dashboard/Prometheus/Widgets/CapacityItem.tsx b/portal-ui/src/screens/Console/Dashboard/Prometheus/Widgets/CapacityItem.tsx index 1eb087ee2..d7ecdfb5b 100644 --- a/portal-ui/src/screens/Console/Dashboard/Prometheus/Widgets/CapacityItem.tsx +++ b/portal-ui/src/screens/Console/Dashboard/Prometheus/Widgets/CapacityItem.tsx @@ -22,7 +22,11 @@ import { widgetDetailsToPanel } from "../utils"; import { ErrorResponseHandler } from "../../../../../common/types"; import { useDispatch } from "react-redux"; -import { niceBytes } from "../../../../../common/utils"; +import { + calculateBytes, + capacityColors, + niceBytesInt, +} from "../../../../../common/utils"; import { Cell, Pie, PieChart } from "recharts"; import { ReportedUsageIcon } from "../../../../../icons"; import Loader from "../../../Common/Loader/Loader"; @@ -43,8 +47,10 @@ const CapacityItem = ({ }) => { const dispatch = useDispatch(); const [loading, setLoading] = useState(true); - const [dataInner, setDataInner] = useState>([]); - const [result, setResult] = useState(null); + + const [totalUsableFree, setTotalUsableFree] = useState(0); + const [totalUsed, setTotalUsed] = useState(0); + const [totalUsable, setTotalUsable] = useState(0); useEffect(() => { if (propLoading) { @@ -73,8 +79,30 @@ const CapacityItem = ({ ) .then((res: any) => { const widgetsWithValue = widgetDetailsToPanel(res, value); - setDataInner(widgetsWithValue.data); - setResult(widgetsWithValue); + + let tUsable = 0; + let tUsed = 0; + let tFree = 0; + + widgetsWithValue.data.forEach((eachArray: any[]) => { + eachArray.forEach((itemSum) => { + switch (itemSum.legend) { + case "Total Usable": + tUsable += itemSum.value; + break; + case "Used Space": + tUsed += itemSum.value; + break; + case "Usable Free": + tFree += itemSum.value; + break; + } + }); + }); + + setTotalUsableFree(tFree); + setTotalUsed(tUsed); + setTotalUsable(tUsable); setLoading(false); }) @@ -85,21 +113,18 @@ const CapacityItem = ({ } }, [loading, value, timeEnd, timeStart, dispatch, apiPrefix]); - const [middleLabel, unitValue] = (result?.innerLabel || "").split(" "); - - const usableValueObj = dataInner[0]; - const { value: usableValue = 0 } = usableValueObj || { value: 0 }; + const usedConvert = calculateBytes(totalUsed, true, false); const plotValues = [ { - value: parseInt(usableValue), + value: totalUsableFree, color: "#D6D6D6", - label: "Usable Space", + label: "Usable Available Space", }, { - value: parseInt(usableValue), - color: "#073052", - label: "Usable Space", + value: totalUsed, + color: capacityColors(totalUsed, totalUsable), + label: "Used Space", }, ]; return ( @@ -150,7 +175,7 @@ const CapacityItem = ({ fontSize: 12, }} > - {niceBytes(usableValue)} + {niceBytesInt(totalUsableFree)}
- + -
{middleLabel}
{" "} -
{unitValue}
+ fontWeight: "bold", + fontSize: "14px", + }} + > + Used: +
+ +
{usedConvert.total}
+
{usedConvert.unit}
+
+ +
Of: {niceBytesInt(totalUsable)}
+
0 ? chartSeries[0].values : []; + let chartSeries = get(payloadData, "targets", []).filter( + (seriesItem: any) => seriesItem !== null + ); - const totalValues = calculateMainValue(valuesArray, metricCalc); + const values = chartSeries.map((chartTarget: any) => { + const resultMap = + chartTarget.result && Array.isArray(chartTarget.result) + ? chartTarget.result + : []; - const values = chartSeries.map((elementValue: any) => { - const values = get(elementValue, "values", []); - const metricKeyItem = Object.keys(elementValue.metric); - const sortResult = values.sort( - (value1: any[], value2: any[]) => - parseInt(value1[0][1]) - parseInt(value2[0][1]) - ); + const values = resultMap.map((elementValue: any) => { + const values = get(elementValue, "values", []); + const metricKeyItem = Object.keys(elementValue.metric); + const sortResult = values.sort( + (value1: any[], value2: any[]) => + parseInt(value1[0][1]) - parseInt(value2[0][1]) + ); - const metricName = elementValue.metric[metricKeyItem[0]]; - const value = sortResult[sortResult.length - 1]; - return { name: metricName, value: parseInt(value[1]) }; + const metricName = elementValue.metric[metricKeyItem[0]]; + const value = sortResult[sortResult.length - 1]; + return { + name: metricName, + value: parseInt(value[1]), + legend: chartTarget.legendFormat, + }; + }); + + return values; }); + const firstTarget = + chartSeries[0].result && chartSeries[0].result.length > 0 + ? chartSeries[0].result[0].values + : []; + + const totalValues = calculateMainValue(firstTarget, metricCalc); + const innerLabel = panelItem.labelDisplayFunction ? panelItem.labelDisplayFunction(totalValues[1]) : totalValues[1]; diff --git a/restapi/admin_info.go b/restapi/admin_info.go index 185003564..63b3affe4 100644 --- a/restapi/admin_info.go +++ b/restapi/admin_info.go @@ -27,14 +27,12 @@ import ( "strings" "time" - "github.com/minio/madmin-go" - - "github.com/go-openapi/swag" - "github.com/go-openapi/runtime/middleware" + "github.com/go-openapi/swag" "github.com/minio/console/models" "github.com/minio/console/restapi/operations" systemApi "github.com/minio/console/restapi/operations/system" + "github.com/minio/madmin-go" ) func registerAdminInfoHandlers(api *operations.ConsoleAPI) { @@ -222,7 +220,7 @@ var widgets = []Metric{ }, { ID: 50, - Title: "Current Usable Capacity", + Title: "Current Usable Free Capacity", Type: "gauge", MaxDataPoints: 100, GridPos: GridPos{ @@ -239,8 +237,44 @@ var widgets = []Metric{ }, }, Targets: []Target{ + { + Expr: `topk(1, sum(minio_cluster_capacity_usable_total_bytes{$__query}) by (instance))`, + LegendFormat: "Total Usable", + Step: 300, + }, { Expr: `topk(1, sum(minio_cluster_capacity_usable_free_bytes{$__query}) by (instance))`, + LegendFormat: "Usable Free", + Step: 300, + }, + { + Expr: `topk(1, sum(minio_cluster_capacity_usable_total_bytes{$__query}) by (instance)) - topk(1, sum(minio_cluster_capacity_usable_free_bytes{$__query}) by (instance))`, + LegendFormat: "Used Space", + Step: 300, + }, + }, + }, + { + ID: 51, + Title: "Current Usable Total Bytes", + Type: "gauge", + MaxDataPoints: 100, + GridPos: GridPos{ + H: 6, + W: 3, + X: 6, + Y: 0, + }, + Options: MetricOptions{ + ReduceOptions: ReduceOptions{ + Calcs: []string{ + "lastNotNull", + }, + }, + }, + Targets: []Target{ + { + Expr: `topk(1, sum(minio_cluster_capacity_usable_total_bytes{$__query}) by (instance))`, LegendFormat: "", Step: 300, },