Added fallback to default dashboard in case Prometheus is not accesible (#1302)
This commit is contained in:
@@ -42,6 +42,9 @@ type AdminInfoResponse struct {
|
|||||||
// objects
|
// objects
|
||||||
Objects int64 `json:"objects,omitempty"`
|
Objects int64 `json:"objects,omitempty"`
|
||||||
|
|
||||||
|
// prometheus not ready
|
||||||
|
PrometheusNotReady bool `json:"prometheusNotReady,omitempty"`
|
||||||
|
|
||||||
// servers
|
// servers
|
||||||
Servers []*ServerProperties `json:"servers"`
|
Servers []*ServerProperties `json:"servers"`
|
||||||
|
|
||||||
|
|||||||
@@ -472,7 +472,12 @@ export const getTimeFromTimestamp = (
|
|||||||
timestamp: string,
|
timestamp: string,
|
||||||
fullDate: boolean = false
|
fullDate: boolean = false
|
||||||
) => {
|
) => {
|
||||||
const dateObject = new Date(parseInt(timestamp) * 1000);
|
const timestampToInt = parseInt(timestamp);
|
||||||
|
|
||||||
|
if (isNaN(timestampToInt)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
const dateObject = new Date(timestampToInt * 1000);
|
||||||
|
|
||||||
if (fullDate) {
|
if (fullDate) {
|
||||||
return `${dateObject.getFullYear()}-${String(
|
return `${dateObject.getFullYear()}-${String(
|
||||||
|
|||||||
@@ -133,6 +133,31 @@ const BasicDashboard = ({ classes, usage }: IDashboardProps) => {
|
|||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<div className={classes.dashboardBG} />
|
<div className={classes.dashboardBG} />
|
||||||
|
{usage?.prometheusNotReady && (
|
||||||
|
<Grid
|
||||||
|
container
|
||||||
|
justifyContent={"center"}
|
||||||
|
alignContent={"center"}
|
||||||
|
alignItems={"center"}
|
||||||
|
>
|
||||||
|
<Grid item xs={8}>
|
||||||
|
<HelpBox
|
||||||
|
iconComponent={<PrometheusIcon />}
|
||||||
|
title={"We can't retrieve advanced metrics at this time"}
|
||||||
|
help={
|
||||||
|
<Fragment>
|
||||||
|
MinIO Dashboard will display basic metrics as we couldn't
|
||||||
|
connect to Prometheus successfully.
|
||||||
|
<br /> <br />
|
||||||
|
Please try again in a few minutes. If the problem persists,
|
||||||
|
you can review your configuration and confirm that Prometheus
|
||||||
|
server is up and running.
|
||||||
|
</Fragment>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
)}
|
||||||
<Grid container spacing={2}>
|
<Grid container spacing={2}>
|
||||||
<Grid item xs={12} className={classes.generalStatusTitle}>
|
<Grid item xs={12} className={classes.generalStatusTitle}>
|
||||||
General Status
|
General Status
|
||||||
@@ -241,45 +266,47 @@ const BasicDashboard = ({ classes, usage }: IDashboardProps) => {
|
|||||||
</TabPanel>
|
</TabPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid
|
{!usage?.prometheusNotReady && (
|
||||||
container
|
<Grid
|
||||||
justifyContent={"center"}
|
container
|
||||||
alignContent={"center"}
|
justifyContent={"center"}
|
||||||
alignItems={"center"}
|
alignContent={"center"}
|
||||||
>
|
alignItems={"center"}
|
||||||
<Grid item xs={8}>
|
>
|
||||||
<HelpBox
|
<Grid item xs={8}>
|
||||||
iconComponent={<PrometheusIcon />}
|
<HelpBox
|
||||||
title={"Monitoring"}
|
iconComponent={<PrometheusIcon />}
|
||||||
help={
|
title={"Monitoring"}
|
||||||
<Fragment>
|
help={
|
||||||
The MinIO Dashboard is displaying basic metrics only due to
|
<Fragment>
|
||||||
missing the{" "}
|
The MinIO Dashboard is displaying basic metrics only due to
|
||||||
<a
|
missing the{" "}
|
||||||
href="https://docs.min.io/minio/baremetal/console/minio-console.html?ref=con#configuration"
|
<a
|
||||||
target="_blank"
|
href="https://docs.min.io/minio/baremetal/console/minio-console.html?ref=con#configuration"
|
||||||
rel="noreferrer"
|
target="_blank"
|
||||||
>
|
rel="noreferrer"
|
||||||
necessary settings
|
>
|
||||||
</a>{" "}
|
necessary settings
|
||||||
for displaying extended metrics.
|
</a>{" "}
|
||||||
<br />
|
for displaying extended metrics.
|
||||||
<br />
|
<br />
|
||||||
See{" "}
|
<br />
|
||||||
<a
|
See{" "}
|
||||||
href="https://docs.min.io/minio/baremetal/monitoring/metrics-alerts/collect-minio-metrics-using-prometheus.html?ref=con#minio-metrics-collect-using-prometheus"
|
<a
|
||||||
target="_blank"
|
href="https://docs.min.io/minio/baremetal/monitoring/metrics-alerts/collect-minio-metrics-using-prometheus.html?ref=con#minio-metrics-collect-using-prometheus"
|
||||||
rel="noreferrer"
|
target="_blank"
|
||||||
>
|
rel="noreferrer"
|
||||||
Collect MinIO Metrics Using Prometheus
|
>
|
||||||
</a>{" "}
|
Collect MinIO Metrics Using Prometheus
|
||||||
for a complete tutorial on scraping and visualizing MinIO
|
</a>{" "}
|
||||||
metrics with Prometheus.
|
for a complete tutorial on scraping and visualizing MinIO
|
||||||
</Fragment>
|
metrics with Prometheus.
|
||||||
}
|
</Fragment>
|
||||||
/>
|
}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
)}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -154,7 +154,12 @@ const LinearGraphWidget = ({
|
|||||||
if (key === "name") {
|
if (key === "name") {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const val = parseInt(dp[key]);
|
let val = parseInt(dp[key]);
|
||||||
|
|
||||||
|
if (isNaN(val)) {
|
||||||
|
val = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (maxVal < val) {
|
if (maxVal < val) {
|
||||||
maxVal = val;
|
maxVal = val;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,6 +111,18 @@ const SingleRepWidget = ({
|
|||||||
}, [loading, panelItem, timeEnd, timeStart, displayErrorMessage, apiPrefix]);
|
}, [loading, panelItem, timeEnd, timeStart, displayErrorMessage, apiPrefix]);
|
||||||
const gradientID = `colorGradient-${title.split(" ").join("-")}`;
|
const gradientID = `colorGradient-${title.split(" ").join("-")}`;
|
||||||
|
|
||||||
|
let repNumber = "";
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
const resultRep = parseInt(result.innerLabel || "0");
|
||||||
|
|
||||||
|
if (!isNaN(resultRep)) {
|
||||||
|
repNumber = representationNumber(resultRep);
|
||||||
|
} else {
|
||||||
|
repNumber = "0";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.singleValueContainer}>
|
<div className={classes.singleValueContainer}>
|
||||||
<div className={classes.titleContainer}>{title}</div>
|
<div className={classes.titleContainer}>{title}</div>
|
||||||
@@ -150,7 +162,7 @@ const SingleRepWidget = ({
|
|||||||
fill={"#07193E"}
|
fill={"#07193E"}
|
||||||
>
|
>
|
||||||
{result
|
{result
|
||||||
? representationNumber(parseInt(result.innerLabel || "0"))
|
? repNumber
|
||||||
: ""}
|
: ""}
|
||||||
</text>
|
</text>
|
||||||
</AreaChart>
|
</AreaChart>
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ export interface Usage {
|
|||||||
usage: number;
|
usage: number;
|
||||||
buckets: number;
|
buckets: number;
|
||||||
objects: number;
|
objects: number;
|
||||||
|
prometheusNotReady?: boolean;
|
||||||
widgets?: any;
|
widgets?: any;
|
||||||
servers: ServerInfo[];
|
servers: ServerInfo[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,22 +89,27 @@ const EditConfiguration = ({
|
|||||||
useState<boolean>(false);
|
useState<boolean>(false);
|
||||||
//Effects
|
//Effects
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const configId = get(selectedConfiguration, "configuration_id", false);
|
if (loadingConfig) {
|
||||||
|
const configId = get(selectedConfiguration, "configuration_id", false);
|
||||||
|
|
||||||
if (configId) {
|
if (configId) {
|
||||||
api
|
api
|
||||||
.invoke("GET", `/api/v1/configs/${configId}`)
|
.invoke("GET", `/api/v1/configs/${configId}`)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
const keyVals = get(res, "key_values", []);
|
const keyVals = get(res, "key_values", []);
|
||||||
setConfigValues(keyVals);
|
setConfigValues(keyVals);
|
||||||
})
|
setLoadingConfig(false);
|
||||||
.catch((err: ErrorResponseHandler) => {
|
})
|
||||||
setLoadingConfig(false);
|
.catch((err: ErrorResponseHandler) => {
|
||||||
setErrorSnackMessage(err);
|
setLoadingConfig(false);
|
||||||
});
|
setErrorSnackMessage(err);
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setLoadingConfig(false);
|
||||||
}
|
}
|
||||||
setLoadingConfig(false);
|
}, [loadingConfig, selectedConfiguration, setErrorSnackMessage]);
|
||||||
}, [selectedConfiguration, setErrorSnackMessage]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (saving) {
|
if (saving) {
|
||||||
@@ -153,6 +158,9 @@ const EditConfiguration = ({
|
|||||||
const continueReset = (restart: boolean) => {
|
const continueReset = (restart: boolean) => {
|
||||||
setResetConfigurationOpen(false);
|
setResetConfigurationOpen(false);
|
||||||
serverNeedsRestart(restart);
|
serverNeedsRestart(restart);
|
||||||
|
if (restart) {
|
||||||
|
setLoadingConfig(true);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -58,11 +58,12 @@ func registerAdminInfoHandlers(api *operations.ConsoleAPI) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type UsageInfo struct {
|
type UsageInfo struct {
|
||||||
Buckets int64
|
Buckets int64
|
||||||
Objects int64
|
Objects int64
|
||||||
Usage int64
|
Usage int64
|
||||||
DisksUsage int64
|
DisksUsage int64
|
||||||
Servers []*models.ServerProperties
|
Servers []*models.ServerProperties
|
||||||
|
EndpointNotReady bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAdminInfo invokes admin info and returns a parsed `UsageInfo` structure
|
// GetAdminInfo invokes admin info and returns a parsed `UsageInfo` structure
|
||||||
@@ -845,7 +846,12 @@ func getAdminInfoResponse(session *models.Principal, params admin_api.AdminInfoP
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getUsageWidgetsForDeployment(prometheusURL string, mAdmin *madmin.AdminClient) (*models.AdminInfoResponse, *models.Error) {
|
func getUsageWidgetsForDeployment(prometheusURL string, mAdmin *madmin.AdminClient) (*models.AdminInfoResponse, *models.Error) {
|
||||||
if prometheusURL == "" {
|
prometheusNotReady := false
|
||||||
|
|
||||||
|
if prometheusURL != "" && !testPrometheusURL(prometheusURL) {
|
||||||
|
prometheusNotReady = true
|
||||||
|
}
|
||||||
|
if prometheusURL == "" || prometheusNotReady {
|
||||||
// create a minioClient interface implementation
|
// create a minioClient interface implementation
|
||||||
// defining the client to be used
|
// defining the client to be used
|
||||||
adminClient := AdminClient{Client: mAdmin}
|
adminClient := AdminClient{Client: mAdmin}
|
||||||
@@ -858,10 +864,11 @@ func getUsageWidgetsForDeployment(prometheusURL string, mAdmin *madmin.AdminClie
|
|||||||
return nil, prepareError(err)
|
return nil, prepareError(err)
|
||||||
}
|
}
|
||||||
sessionResp := &models.AdminInfoResponse{
|
sessionResp := &models.AdminInfoResponse{
|
||||||
Buckets: usage.Buckets,
|
Buckets: usage.Buckets,
|
||||||
Objects: usage.Objects,
|
Objects: usage.Objects,
|
||||||
Usage: usage.Usage,
|
Usage: usage.Usage,
|
||||||
Servers: usage.Servers,
|
Servers: usage.Servers,
|
||||||
|
PrometheusNotReady: prometheusNotReady,
|
||||||
}
|
}
|
||||||
return sessionResp, nil
|
return sessionResp, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3655,6 +3655,9 @@ func init() {
|
|||||||
"objects": {
|
"objects": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
"prometheusNotReady": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"servers": {
|
"servers": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
@@ -9503,6 +9506,9 @@ func init() {
|
|||||||
"objects": {
|
"objects": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
"prometheusNotReady": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"servers": {
|
"servers": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
|
|||||||
@@ -3228,6 +3228,8 @@ definitions:
|
|||||||
type: integer
|
type: integer
|
||||||
usage:
|
usage:
|
||||||
type: integer
|
type: integer
|
||||||
|
prometheusNotReady:
|
||||||
|
type: boolean
|
||||||
widgets:
|
widgets:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
|
|||||||
Reference in New Issue
Block a user