Skip to content

Commit 4e29381

Browse files
Added Prometheus URL validation which alerts the user of bad address and prevents state change in the event the url is invalid
1 parent cef3610 commit 4e29381

File tree

4 files changed

+90
-37
lines changed

4 files changed

+90
-37
lines changed

ksqLight/server/server.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ const RealTimeType = new GraphQLObjectType({
3838
})
3939

4040
//---------------Root Query Types----------------
41+
// todo: change the Number(val) implementation
4142
const RootQueryType = new GraphQLObjectType({
4243
name: 'Query',
4344
description: 'Root Query',
@@ -53,7 +54,7 @@ const RootQueryType = new GraphQLObjectType({
5354
prometheusURL: { type: GraphQLNonNull(GraphQLString)}
5455
},
5556
resolve: (parent, {start, end, resolution, metric, prometheusURL}) => {
56-
if (prometheusURL[prometheusURL.length] === '/') prometheusURL = prometheusURL.slice(0, prometheusURL.length);
57+
if (prometheusURL[prometheusURL.length] === '/') prometheusURL = prometheusURL.slice(0, prometheusURL.length - 1);
5758

5859
return axios.get(`${prometheusURL}/api/v1/query_range?step=${resolution}s&end=${end}&start=${start}&query=${queryTypes[metric]}`)
5960
.then(res => {
@@ -125,6 +126,20 @@ const RootQueryType = new GraphQLObjectType({
125126
}
126127
}
127128
},
129+
isValidPrometheusURL: {
130+
type: GraphQLBoolean,
131+
description: 'Boolean value representing whether provided Prometheus URL points to valid Prometheus server',
132+
args: {
133+
prometheusURL: { type: GraphQLNonNull(GraphQLString)}
134+
},
135+
resolve: async (parent, { prometheusURL }) => {
136+
if (prometheusURL[prometheusURL.length] === '/') prometheusURL = prometheusURL.slice(0, prometheusURL.length - 1);
137+
138+
return axios.get(`${prometheusURL}/api/v1/status/buildinfo`)
139+
.then(res => res.status === 200)
140+
.catch(error => error);
141+
}
142+
}
128143
})
129144
});
130145

ksqLight/src/components/Homepage.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export const Homepage = ({ showQueries, showMessages, showErrors, metricsState }
3232
["errorRate", "Error Rate"],
3333
["errorQueries", "Number of Error Queries"],
3434
["pendingErrorQueries", "Number of Pending Error Queries"],
35+
3536
]
3637
const queryTypes = [
3738
["runningQueries", "Number of Running Queries"],
@@ -58,7 +59,7 @@ export const Homepage = ({ showQueries, showMessages, showErrors, metricsState }
5859
return (
5960
<Box>
6061
<CssBaseline />
61-
<Typography color="primary">Hi Welcome back</Typography>
62+
{/* <Typography color="primary">Hi Welcome back</Typography> */}
6263
<Grid container spacing={4} sx={{}}>
6364
{showQueries &&
6465
queriesCharts.map(([query, description], index) =>
@@ -69,11 +70,11 @@ export const Homepage = ({ showQueries, showMessages, showErrors, metricsState }
6970
<LineChart description={description} metric={query} metricsState={metricsState} key={index} />
7071
)
7172
}
72-
{/* {showErrors &&
73+
{showErrors &&
7374
errorCharts.map(([query, description], index) =>
74-
<LineChart description={description} metric={query} key={index} />
75+
<LineChart description={description} metric={query} metricsState={metricsState} key={index} />
7576
)
76-
} */}
77+
}
7778
{/* {queryTypes.map(([query, description], index) => <LineChart description={description} metric={query} key={index} />)} */}
7879
</Grid>
7980
</Box>

ksqLight/src/components/SettingsSidebar.js

Lines changed: 66 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,17 @@ import React, { useEffect } from "react";
22
import { useState } from "react";
33
import { TextField, Typography, MenuItem, Select, Drawer, IconButton, Grid, Button, Stack } from "@mui/material"
44
import ArrowForwardIosIcon from '@mui/icons-material/ArrowForwardIos';
5+
import {
6+
ApolloClient,
7+
InMemoryCache,
8+
ApolloProvider,
9+
gql,
10+
} from "@apollo/client";
11+
12+
const client = new ApolloClient({
13+
uri: "http://localhost:5001/graphql",
14+
cache: new InMemoryCache(),
15+
});
516

617
export const SettingsSidebar = ({ showSettings, setShowSettings, metricsState, setMetricsState }) => {
718
const [localMetricsState, setLocalMetricsState] = useState({
@@ -10,6 +21,8 @@ export const SettingsSidebar = ({ showSettings, setShowSettings, metricsState, s
1021
duration: metricsState.duration,
1122
refreshRate: metricsState.refreshRate
1223
});
24+
const [invalidPrometheusMessage, setInvalidPrometheusMessage] = useState(null);
25+
const [showSubmissionConfirmation, setShowSubmissionConfirmation] = useState(false);
1326

1427
const handleLocalMetrics = (event) => {
1528
switch(event.target.name) {
@@ -63,32 +76,38 @@ export const SettingsSidebar = ({ showSettings, setShowSettings, metricsState, s
6376
}
6477
}
6578

66-
const handleSubmit = (event) => {
79+
const handleSubmit = async (event) => {
6780
event.preventDefault();
6881

69-
// ToDo:
70-
// 1. verify prometheus URL
71-
// 2. verify ksqlDB url
72-
// 3. verify metrics exist for duration requested
73-
74-
// update state
75-
setMetricsState({
76-
prometheusURL: localMetricsState.prometheusURL,
77-
ksqlDBURL: localMetricsState.ksqlDBURL,
78-
duration: {
79-
days: localMetricsState.duration.days,
80-
hours: localMetricsState.duration.hours,
81-
minutes: localMetricsState.duration.minutes
82-
},
83-
refreshRate: localMetricsState.refreshRate
84-
});
82+
// Verify Prometheus URL
83+
client.query({
84+
query: gql`
85+
query validatePrometheusURL{
86+
isValidPrometheusURL(prometheusURL: "${event.target[1].value}")
87+
}
88+
`
89+
})
90+
.then(res => {
91+
// update state
92+
setMetricsState({
93+
prometheusURL: localMetricsState.prometheusURL,
94+
ksqlDBURL: localMetricsState.ksqlDBURL,
95+
duration: {
96+
days: localMetricsState.duration.days,
97+
hours: localMetricsState.duration.hours,
98+
minutes: localMetricsState.duration.minutes
99+
},
100+
refreshRate: localMetricsState.refreshRate
101+
});
102+
setInvalidPrometheusMessage(null);
103+
setShowSubmissionConfirmation(true);
104+
setTimeout(() => setShowSubmissionConfirmation(false), 3000);
105+
})
106+
.catch(error => {
107+
setInvalidPrometheusMessage(error.message);
108+
});
85109
}
86110

87-
// useEffect(() => {
88-
// console.log('this is the metrics state: ', metricsState);
89-
// }, [metricsState]);
90-
91-
92111
return(
93112
<Drawer variant="temporary" anchor="right" open={showSettings} PaperProps={{sx: {paddingTop: "3.5em", width: "35%"}}}>
94113
<div className="flex-1 w-full header-viewport p-4">
@@ -98,15 +117,30 @@ export const SettingsSidebar = ({ showSettings, setShowSettings, metricsState, s
98117
<ArrowForwardIosIcon sx={{color: "#333"}}/>
99118
</IconButton>
100119
<Typography variant="h6" sx={{color: "#333"}}>Prometheus Connection</Typography>
101-
<hr className="w-full mb-3 mt-1"></hr>
102-
<TextField
103-
fullWidth
104-
variant="outlined"
105-
label="URL"
106-
name="prometheus-url"
107-
onChange={handleLocalMetrics}
108-
value={localMetricsState.prometheusURL}
109-
/>
120+
<hr className="w-full mb-3 mt-1"></hr>
121+
{invalidPrometheusMessage ? (
122+
<>
123+
<TextField
124+
error
125+
fullWidth
126+
variant="outlined"
127+
label="URL"
128+
name="prometheus-url"
129+
onChange={handleLocalMetrics}
130+
value={localMetricsState.prometheusURL}
131+
/>
132+
<Typography variant="h8" sx={{color: "red"}}>{invalidPrometheusMessage}</Typography>
133+
</>
134+
) : (
135+
<TextField
136+
fullWidth
137+
variant="outlined"
138+
label="URL"
139+
name="prometheus-url"
140+
onChange={handleLocalMetrics}
141+
value={localMetricsState.prometheusURL}
142+
/>
143+
)}
110144
<hr className="w-full invisible mb-2 mt-2"></hr>
111145
<Typography variant="h6" sx={{color: "#333"}}>ksqlDB Connection</Typography>
112146
<hr className="w-full mb-3 mt-1"></hr>
@@ -172,6 +206,7 @@ export const SettingsSidebar = ({ showSettings, setShowSettings, metricsState, s
172206
<Button variant="contained" type="submit">Submit</Button>
173207
<Button color='secondary' variant="contained" onClick={() => setShowSettings(!showSettings)}>Cancel</Button>
174208
</Stack>
209+
{showSubmissionConfirmation && <Typography variant="h8" sx={{color: "forestgreen", mt: "1em"}}>Settings Saved!</Typography>}
175210
</Grid>
176211
</form>
177212
</div>

ksqLight/src/utils/utilityFunctions.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
const axios = require('axios');
2+
13
const utilityFunctions = {};
24

35
utilityFunctions.getUnixRange = (days, hours, minutes) => {
@@ -8,6 +10,6 @@ utilityFunctions.getUnixRange = (days, hours, minutes) => {
810

911
utilityFunctions.getDuration = (days, hours, minutes) => {
1012
return (minutes * 60 + hours * 60 * 60 + days * 60 * 60 * 24) * 1000;
11-
}
13+
};
1214

1315
module.exports = utilityFunctions;

0 commit comments

Comments
 (0)