diff --git a/backend/app/api/v1/commons/example_responses.py b/backend/app/api/v1/commons/example_responses.py
index d5b527e3..da95c682 100644
--- a/backend/app/api/v1/commons/example_responses.py
+++ b/backend/app/api/v1/commons/example_responses.py
@@ -124,17 +124,21 @@ def response_422():
"endDate": "2023-09-20",
"results": [
{
+ "uuid": "4de79cb7a1b071bce282e8d0ce2006c7",
+ "encryptedData": "gAAAAABmR0NYcO6AZo4nGjkT1IBVeoD=",
"ciSystem": "Jenkins",
- "uuid": "2cc5d4ca895ca5d84cab0fd7923db93b",
- "encrypted": "gAAAAABmQALtP0g5UPMsOjQw46tZ-aBz77yl-8QNI4jwLfIEV1POnOlA1ny89cp3Nrik3OzpNwXrWO3K4ZwtOliTfk0SO5NkNZHY8reJhvOVJBGFEw2enyjRaHp9hIaJdE0Vrfuqt_NjiYX-vOZo0Sjc84R76LvxjAC6f_urceGGZICH36IkT2g=",
- "releaseStream": "Release Candidate",
+ "benchmark": "deployment",
+ "shortVersion": "4.16",
+ "ocpVersion": "4.16.0-0.nightly-2024-05-16-092402",
+ "releaseStream": "Nightly",
+ "nodeName": "kni-qe-66",
+ "cpu": "Intel(R) Xeon? Gold 5423N",
+ "formal": "true",
+ "startDate": "2024-05-16 19:39:48+00:00",
+ "endDate": "2024-05-16 20:41:48+00:00",
+ "buildUrl": "https://ci-jenkins-csb-kniqe.apps.ocp-c1.prod.psi.redhat.com/job/ocp-far-edge-vran-tests/10506",
"jobStatus": "success",
- "buildUrl": "https://ci-jenkins-csb-kniqe.apps.ocp-c1.prod.psi.redhat.com/job/ocp-far-edge-vran-tests/532",
- "startDate": "2024-05-09 14:10:51+00:00",
- "endDate": "2024-05-09 14:43:51+00:00",
- "product": "telco",
- "version": "4.16",
- "testName": "reboot"
+ "jobDuration": 3720
},
]
}
diff --git a/backend/app/api/v1/commons/telco.py b/backend/app/api/v1/commons/telco.py
index 01b2c0f6..c2af92fd 100644
--- a/backend/app/api/v1/commons/telco.py
+++ b/backend/app/api/v1/commons/telco.py
@@ -3,6 +3,7 @@
from app.services.splunk import SplunkService
import app.api.v1.commons.hasher as hasher
from datetime import datetime, timezone
+import app.api.v1.commons.utils as utils
async def getData(start_datetime: date, end_datetime: date, configpath: str):
@@ -35,18 +36,25 @@ async def getData(start_datetime: date, end_datetime: date, configpath: str):
start_timestamp = end_timestamp - execution_time_seconds
start_time_utc = datetime.fromtimestamp(start_timestamp, tz=timezone.utc)
end_time_utc = datetime.fromtimestamp(end_timestamp, tz=timezone.utc)
+ kernel = test_data['kernel'] if 'kernel' in test_data else "Undefined"
mapped_list.append({
"uuid": hash_digest,
"encryptedData": encrypted_data.decode('utf-8'),
"ciSystem": "Jenkins",
- "testName": test_data['test_type'],
- "version": test_data['ocp_version'],
- "releaseStream": test_data['ocp_build'],
+ "benchmark": test_data['test_type'],
+ "kernel": kernel,
+ "shortVersion": test_data['ocp_version'],
+ "ocpVersion": test_data['ocp_build'],
+ "releaseStream": utils.getReleaseStream({'releaseStream': test_data['ocp_build']}),
+ "nodeName": test_data['node_name'],
+ "cpu": test_data['cpu'],
+ 'formal': test_data['formal'],
"startDate": str(start_time_utc),
"endDate": str(end_time_utc),
"buildUrl": jenkins_url + str(test_data['cluster_artifacts']['ref']['jenkins_build']),
- "jobStatus": "success"
+ "jobStatus": "success",
+ "jobDuration": execution_time_seconds,
})
jobs = pd.json_normalize(mapped_list)
diff --git a/backend/app/api/v1/endpoints/cpt/maps/telco.py b/backend/app/api/v1/endpoints/cpt/maps/telco.py
index 4052c923..c924f0f8 100644
--- a/backend/app/api/v1/endpoints/cpt/maps/telco.py
+++ b/backend/app/api/v1/endpoints/cpt/maps/telco.py
@@ -10,4 +10,6 @@ async def telcoMapper(start_datetime: date, end_datetime: date):
df = await getData(start_datetime, end_datetime, f'telco.splunk')
df.insert(len(df.columns), "product", "telco")
df["releaseStream"] = df.apply(getReleaseStream, axis=1)
+ df["version"] = df["shortVersion"]
+ df["testName"] = df["benchmark"]
return df
diff --git a/frontend/public/assets/images/splunk-icon.png b/frontend/public/assets/images/splunk-icon.png
new file mode 100644
index 00000000..b96ad790
Binary files /dev/null and b/frontend/public/assets/images/splunk-icon.png differ
diff --git a/frontend/src/App.js b/frontend/src/App.js
index 2715590a..4b8c6382 100644
--- a/frontend/src/App.js
+++ b/frontend/src/App.js
@@ -6,13 +6,14 @@ import {
PageSection,
PageSectionVariants,
} from '@patternfly/react-core';
-import {fetchOCPJobsData, fetchCPTJobsData, fetchQuayJobsData} from "./store/Actions/ActionCreator";
+import {fetchOCPJobsData, fetchCPTJobsData, fetchQuayJobsData, fetchTelcoJobsData} from "./store/Actions/ActionCreator";
import {useDispatch} from "react-redux";
import {Route, Switch, BrowserRouter as Router} from "react-router-dom";
import {NavBar} from "./components/NavBar/NavBar";
import {HomeView} from "./components/Home/HomeView";
import {OCPHome} from './components/OCP/OCPHome';
import {QuayHome} from './components/Quay/QuayHome';
+import {TelcoHome} from './components/Telco/TelcoHome';
export const App = () => {
@@ -23,6 +24,7 @@ export const App = () => {
await dispatch(fetchOCPJobsData())
await dispatch(fetchCPTJobsData())
await dispatch(fetchQuayJobsData())
+ await dispatch(fetchTelcoJobsData())
}
fetchData()
}, [dispatch])
@@ -45,6 +47,7 @@ export const App = () => {
+
diff --git a/frontend/src/components/NavBar/ToolBar.js b/frontend/src/components/NavBar/ToolBar.js
index 3179a916..24161d93 100644
--- a/frontend/src/components/NavBar/ToolBar.js
+++ b/frontend/src/components/NavBar/ToolBar.js
@@ -23,9 +23,10 @@ export const ToolBar = () => {
return styles;
};
- // Selectors for both ocpJobs and quayJobs
+ // Selectors for OCP, Quay and Telco jobs
const ocpJobResults = useSelector((state) => state.ocpJobs);
const quayJobResults = useSelector((state) => state.quayJobs);
+ const telcoJobResults = useSelector((state) => state.telcoJobs);
const NavItems = (
<>
@@ -45,7 +46,6 @@ export const ToolBar = () => {
onClick={() => setActive("/ocp")}
/>
- {/* New Quay ToolbarItem */}
{
onClick={() => setActive("/quay")}
/>
+
+ setActive("/telco")}
+ />
+
>
);
@@ -70,7 +78,11 @@ export const ToolBar = () => {
diff --git a/frontend/src/components/Telco/BenchmarkResults.js b/frontend/src/components/Telco/BenchmarkResults.js
new file mode 100644
index 00000000..b2692dd7
--- /dev/null
+++ b/frontend/src/components/Telco/BenchmarkResults.js
@@ -0,0 +1,21 @@
+import {Grid, GridItem} from "@patternfly/react-core";
+import InstallCard from "./InstallCard";
+import React from "react";
+import {DisplayGraph} from "./DisplayGraph";
+
+
+export const BenchmarkResults = ({dataset, isExpanded}) => {
+ return (
+ <> {
+ ( isExpanded &&
+
+
+
+
+
+ ) || <>NO Data>
+ }
+ >
+ )
+}
diff --git a/frontend/src/components/Telco/DisplayGraph.js b/frontend/src/components/Telco/DisplayGraph.js
new file mode 100644
index 00000000..a9e18244
--- /dev/null
+++ b/frontend/src/components/Telco/DisplayGraph.js
@@ -0,0 +1,38 @@
+import {PlotlyView} from "../ReactGraphs/plotly/PlotlyView";
+import React, {useEffect} from "react";
+import {useDispatch, useSelector} from "react-redux";
+import CardView from "../PatternflyComponents/Card/CardView";
+import {Text6} from "../PatternflyComponents/Text/Text";
+import {SplitView} from "../PatternflyComponents/Split/SplitView";
+import {Spinner} from "@patternfly/react-core";
+import {fetchGraphData} from "../../store/Actions/ActionCreator";
+
+
+export const DisplayGraph = ({uuid, benchmark}) => {
+
+ const [isExpanded, setExpanded] = React.useState(true)
+ const onExpand = () => setExpanded(!isExpanded)
+
+ const dispatch = useDispatch()
+ const job_results = useSelector(state => state.graph)
+ const graphData = job_results.uuid_results[uuid]
+
+ useEffect(() => {
+ dispatch(fetchGraphData(uuid))
+ }, [dispatch, uuid])
+
+ const getGraphBody = () => {
+ return (job_results.graphError && ) ||
+ (graphData && ) ||
+ , ]} />
+ }
+
+ return <>
+ }
+ body={ getGraphBody() }
+ isExpanded={isExpanded}
+ expandView={true}
+ onExpand={onExpand}
+ />
+ >
+}
diff --git a/frontend/src/components/Telco/InstallCard.js b/frontend/src/components/Telco/InstallCard.js
new file mode 100644
index 00000000..895401e4
--- /dev/null
+++ b/frontend/src/components/Telco/InstallCard.js
@@ -0,0 +1,97 @@
+import React from 'react';
+import { Card, CardTitle, CardBody, CardFooter, CardHeader, CardExpandableContent } from '@patternfly/react-core';
+import { Grid, GridItem } from '@patternfly/react-core';
+import { Spinner } from '@patternfly/react-core';
+import { formatTime } from '../../helpers/Formatters'
+import { FaCheck, FaExclamationCircle, FaExclamationTriangle } from "react-icons/fa";
+import { DisplaySplunk } from '../commons/DisplaySplunk';
+
+
+export default function InstallCard(props) {
+ let config = props.data
+ const [isExpanded, setExpanded] = React.useState([true, null])
+
+
+ const onExpand = () => {
+ setExpanded(!isExpanded)
+ };
+
+ const icons = {
+ "failed": <>>,
+ "success": <>>,
+ "upstream_failed": <>>,
+
+ }
+
+ if (config) {
+ return (
+
+
+ Configs
+
+
+
+
+
+
+ Cluster Metadata
+
+
+ - Release Binary: {config.cluster_version && config.cluster_version || config.ocpVersion}
+ - Cluster Name: {config.cluster_name && config.cluster_name || config.nodeName}
+ - Cluster Type: {config.cluster_type && config.cluster_type || "SNO spoke"}
+ - Network Type: {config.network_type && config.network_type || "OVNKubernetes"}
+ - CPU: {config.cpu_version && config.cpu_version || config.cpu}
+ - Kernel: {config.kernel_version && config.kernel_version || config.kernel}
+ - IsFormal: {config.is_formal && config.is_formal || config.formal}
+ - Benchmark Status: {icons[config.job_status && config.job_status || config.jobStatus] || config.job_status && config.job_status || config.jobStatus}
+ - Duration: {formatTime(config.job_duration && config.job_duration || config.jobDuration)}
+
+
+
+
+
+
+ Node Types
+
+
+ - Master: {config.master_type && config.master_type || "Baremetal"}
+ - Workload: {config.workload_type && config.workload_type || config.benchmark}
+
+
+
+
+
+ Node Counts
+
+
+ - Master: {config.master_count && config.master_count || "1"}
+ - Total Nodes: {config.workload_count && config.workload_count || "1"}
+
+
+
+
+
+
+
+
+ )
+ } else {
+ return (
+
+ Install Configuration
+
Awaiting Results
+
+
+ )
+ }
+
+}
diff --git a/frontend/src/components/Telco/TelcoHome.js b/frontend/src/components/Telco/TelcoHome.js
new file mode 100644
index 00000000..557198c4
--- /dev/null
+++ b/frontend/src/components/Telco/TelcoHome.js
@@ -0,0 +1,90 @@
+import '../css/PlatformView.css';
+import "@patternfly/react-core/dist/styles/base.css";
+import React, {useEffect, useState} from 'react';
+
+import {HomeLayout} from "../templates/HomeLayout";
+import {useDispatch, useSelector} from "react-redux";
+import {useHistory, useLocation} from "react-router-dom";
+import {updateTelcoDataFilter} from "../../store/reducers/TelcoJobsReducer";
+import {fetchTelcoJobsData} from "../../store/Actions/ActionCreator";
+import {BenchmarkResults} from "./BenchmarkResults";
+
+
+export function TelcoHome() {
+
+ const dispatch = useDispatch()
+ const {search} = useLocation();
+ const searchParams = new URLSearchParams(search);
+ const history = useHistory();
+ const telcoJobs = useSelector(state => state.telcoJobs)
+
+ const topHeadersData = [
+ {loading: telcoJobs.waitForUpdate, title: 'No. Jobs', value: telcoJobs.total},
+ {loading: telcoJobs.waitForUpdate, title: 'Success', value: telcoJobs.success},
+ {loading: telcoJobs.waitForUpdate, title: 'Failure', value: telcoJobs.failure},
+ {loading: telcoJobs.waitForUpdate, title: 'Others', value: telcoJobs.others},
+ {loading: telcoJobs.waitForUpdate, title: 'Duration Running', value: telcoJobs.duration}
+ ]
+
+ const [ciSystem, setCiSystem] = useState(searchParams.get("ciSystem") || telcoJobs.selectedCiSystem)
+ const [benchmark, setBenchmark] = useState(searchParams.get("benchmark") || telcoJobs.selectedBenchmark)
+ const [version, setVersion] = useState(searchParams.get("version") || telcoJobs.selectedVersion)
+ const [releaseStream, setReleaseStream] = useState(searchParams.get("releaseStream") || telcoJobs.selectedReleaseStream)
+ const [formal, setFormal] = useState(searchParams.get("formal") || telcoJobs.selectedFormal)
+ const [cpu, setCpu] = useState(searchParams.get("cpu") || telcoJobs.selectedCpu)
+ const [nodeName, setNodeName] = useState(searchParams.get("nodeName") || telcoJobs.selectedNodeName)
+ const [startDate, setStartDate] = useState(searchParams.get("startDate") || telcoJobs.startDate) || ""
+ const [endDate, setEndDate] = useState(searchParams.get("endDate") || telcoJobs.endDate) || ""
+
+ const sidebarComponents = [
+ {name: "DateComponent", options: [], onChange: null, value: null, startDate: startDate, endDate: endDate, setStartDate: setStartDate, setEndDate: setEndDate},
+ {name: "Ci System", onChange: setCiSystem, value: ciSystem, options: telcoJobs.ciSystems},
+ {name: "Benchmark", onChange: setBenchmark, value: benchmark, options: telcoJobs.benchmarks },
+ {name: "Versions", onChange: setVersion, value: version, options: telcoJobs.versions},
+ {name: "Release Streams", onChange: setReleaseStream, value: releaseStream, options: telcoJobs.releaseStreams},
+ {name: "isFormal", onChange: setFormal, value: formal, options: telcoJobs.formals},
+ {name: "Cpu", onChange: setCpu, value: cpu, options: telcoJobs.cpus},
+ {name: "Node Name", onChange: setNodeName, value: nodeName, options: telcoJobs.nodeNames},
+ ]
+
+ useEffect(() => {
+ let buildParams = ''
+ if(ciSystem !== '') buildParams += `&ciSystem=${ciSystem}`
+ if(benchmark !== '') buildParams += `&benchmark=${benchmark}`
+ if(version !== '') buildParams += `&version=${version}`
+ if(releaseStream !== '') buildParams += `&releaseStream=${releaseStream}`
+ if(formal !== '') buildParams += `&formal=${formal}`
+ if(cpu !== '') buildParams += `&cpu=${cpu}`
+ if(nodeName !== '') buildParams += `&nodeName=${nodeName}`
+ if(startDate !== '') buildParams += `&startDate=${startDate}`
+ if(endDate !== '') buildParams += `&endDate=${endDate}`
+ history.push(`/telco?${buildParams.substring(1)}`, { replace: true });
+
+ }, [history, ciSystem, benchmark, version, releaseStream, formal, cpu, nodeName, startDate, endDate])
+
+ useEffect( ()=>{
+ dispatch(updateTelcoDataFilter({ciSystem, benchmark, version, releaseStream, formal, cpu, nodeName}))
+ }, [ ciSystem, benchmark, version, releaseStream, formal, cpu, nodeName, dispatch ])
+
+ useEffect(() => {
+ if(startDate || endDate){
+ dispatch(fetchTelcoJobsData(startDate, endDate))
+ }
+ }, [startDate, endDate, dispatch])
+
+ useEffect(() => {
+ if(endDate === ""){
+ setEndDate(telcoJobs.endDate)
+ setStartDate(telcoJobs.startDate)
+ }
+ }, [endDate, setEndDate, setStartDate, telcoJobs.startDate, telcoJobs.endDate])
+
+
+ return (
+
+ );
+}
diff --git a/frontend/src/components/commons/DisplayGrafana.js b/frontend/src/components/commons/DisplayGrafana.js
index 84c27f6b..d200527a 100644
--- a/frontend/src/components/commons/DisplayGrafana.js
+++ b/frontend/src/components/commons/DisplayGrafana.js
@@ -5,6 +5,7 @@ import {SplitView} from "../PatternflyComponents/Split/SplitView";
import CardView from "../PatternflyComponents/Card/CardView";
import ListView from "../PatternflyComponents/List/ListView";
import {Text6} from "../PatternflyComponents/Text/Text";
+import { getBuildLink } from './commons';
export function DisplayGrafana({benchmarkConfigs}) {
@@ -38,18 +39,6 @@ export function DisplayGrafana({benchmarkConfigs}) {
}
-const getBuildLink = (benchmarkConfigs) => {
- var icon = "assets/images/jenkins-icon.svg"
- if (benchmarkConfigs.ciSystem === "PROW") {
- icon = "assets/images/prow-icon.png"
- }
- return
-
-
-}
-
-
const getGrafanaData = (benchmarkConfigs) => {
const grafanaURL = "https://grafana.rdu2.scalelab.redhat.com:3000/d/";
const dashboardKubeBurner = "D5E8c5XVz/kube-burner-report-mode?orgId=1"
diff --git a/frontend/src/components/commons/DisplaySplunk.js b/frontend/src/components/commons/DisplaySplunk.js
new file mode 100644
index 00000000..d391490b
--- /dev/null
+++ b/frontend/src/components/commons/DisplaySplunk.js
@@ -0,0 +1,91 @@
+import React from 'react';
+import { FaCheck, FaExclamationCircle, FaExclamationTriangle } from "react-icons/fa";
+import {formatTime} from "../../helpers/Formatters";
+import {SplitView} from "../PatternflyComponents/Split/SplitView";
+import CardView from "../PatternflyComponents/Card/CardView";
+import ListView from "../PatternflyComponents/List/ListView";
+import {Text6} from "../PatternflyComponents/Text/Text";
+import { getBuildLink } from './commons';
+
+
+export function DisplaySplunk({benchmarkConfigs}) {
+
+
+
+ const icons = {
+ "failed": ,
+ "failure": ,
+ "success": ,
+ "upstream_failed": ,
+
+ }
+
+ const { getSplunkLink, getTimeFormat, status } = getSplunkData(benchmarkConfigs)
+
+ return (
+ ]
+ }
+ /> || }
+ />
+ )
+
+}
+
+const getSplunkData = (benchmarkConfigs) => {
+ const splunkURL = "https://rhcorporate.splunkcloud.com/en-GB/app/search/";
+ let status = null;
+ let getTimeFormat = null;
+ let getSplunkLink = null;
+ if(benchmarkConfigs){
+ const startDate = new Date(benchmarkConfigs.startDate)
+ const endDate = new Date(benchmarkConfigs.endDate)
+
+ // Adding 10 more minutes for a buffer.
+ endDate.setMinutes(endDate.getMinutes() + 10);
+
+ let getSplunkURL = null;
+ switch(benchmarkConfigs.benchmark) {
+ case 'cyclictest':
+ getSplunkURL = `${splunkURL}cyclictest_kpis?form.global_time.earliest=${encodeURIComponent(startDate.toISOString())}&form.global_time.latest=${encodeURIComponent(endDate.toISOString())}&form.ocp_view=ocp_version&form.formal_tag=${encodeURIComponent(benchmarkConfigs.formal)}&form.ocp_version=${encodeURIComponent(benchmarkConfigs.shortVersion)}&form.ocp_build=${encodeURIComponent(benchmarkConfigs.ocpVersion)}&form.node_name=${encodeURIComponent(benchmarkConfigs.nodeName)}&form.general_statistics=${encodeURIComponent(benchmarkConfigs.shortVersion)}&form.dashboard_kernels=${encodeURIComponent(benchmarkConfigs.kernel)}`;
+ break;
+ case 'cpu_util':
+ getSplunkURL = `${splunkURL}cpu_util_kpis?form.global_time.earliest=${encodeURIComponent(startDate.toISOString())}&form.global_time.latest=${encodeURIComponent(endDate.toISOString())}&form.high_cpu_treshhold=0.03&form.formal_tag=${encodeURIComponent(benchmarkConfigs.formal)}&form.ocp_version=${encodeURIComponent(benchmarkConfigs.shortVersion)}&form.ocp_build=${encodeURIComponent(benchmarkConfigs.ocpVersion)}&form.node_name=${encodeURIComponent(benchmarkConfigs.nodeName)}&form.dashboard_kernels=${encodeURIComponent(benchmarkConfigs.kernel)}&form.selected_duration=*&form.general_statistics=${encodeURIComponent(benchmarkConfigs.shortVersion)}`;
+ break;
+ case 'deployment':
+ getSplunkURL = `${splunkURL}deployment_kpis?form.global_time.earliest=${encodeURIComponent(startDate.toISOString())}&form.global_time.latest=${encodeURIComponent(endDate.toISOString())}&form.formal_tag=${encodeURIComponent(benchmarkConfigs.formal)}&form.charts_comparison=ocp_version&form.ocp_version=${encodeURIComponent(benchmarkConfigs.shortVersion)}&form.ocp_build=${encodeURIComponent(benchmarkConfigs.ocpVersion)}&form.node_name=${encodeURIComponent(benchmarkConfigs.nodeName)}&form.general_statistics=${encodeURIComponent(benchmarkConfigs.shortVersion)}`;
+ break;
+ case 'oslat':
+ getSplunkURL = `${splunkURL}oslat_kpis?form.global_time.earliest=${encodeURIComponent(startDate.toISOString())}&form.global_time.latest=${encodeURIComponent(endDate.toISOString())}&form.ocp_view=ocp_version&form.formal_tag=${encodeURIComponent(benchmarkConfigs.formal)}&form.ocp_version=${encodeURIComponent(benchmarkConfigs.shortVersion)}&form.ocp_build=${encodeURIComponent(benchmarkConfigs.ocpVersion)}&form.node_name=${encodeURIComponent(benchmarkConfigs.nodeName)}&form.general_statistics=${encodeURIComponent(benchmarkConfigs.shortVersion)}&form.dashboard_kernels=${encodeURIComponent(benchmarkConfigs.kernel)}`;
+ break;
+ case 'ptp':
+ getSplunkURL = `${splunkURL}ptp_kpis?form.global_time.earliest=${encodeURIComponent(startDate.toISOString())}&form.global_time.latest=${encodeURIComponent(endDate.toISOString())}&form.formal_tag=${encodeURIComponent(benchmarkConfigs.formal)}&form.bubble_chart_legend=ocp_build&form.ocp_version=${encodeURIComponent(benchmarkConfigs.shortVersion)}&form.ocp_build=${encodeURIComponent(benchmarkConfigs.ocpVersion)}&form.node_name=${encodeURIComponent(benchmarkConfigs.nodeName)}&form.general_statistics=${encodeURIComponent(benchmarkConfigs.shortVersion)}&form.dashboard_kernels=${encodeURIComponent(benchmarkConfigs.kernel)}`;
+ break;
+ case 'reboot':
+ getSplunkURL = `${splunkURL}reboot_kpis?form.global_time.earliest=${encodeURIComponent(startDate.toISOString())}&form.global_time.latest=${encodeURIComponent(endDate.toISOString())}&form.formal_tag=${encodeURIComponent(benchmarkConfigs.formal)}&form.charts_comparison=ocp_version&form.reboot_type=soft_reboot&form.ocp_version=${encodeURIComponent(benchmarkConfigs.shortVersion)}&form.ocp_build=${encodeURIComponent(benchmarkConfigs.ocpVersion)}&form.node_name=${encodeURIComponent(benchmarkConfigs.nodeName)}&form.general_statistics=${encodeURIComponent(benchmarkConfigs.shortVersion)}&form.dashboard_kernels=${encodeURIComponent(benchmarkConfigs.kernel)}`;
+ break;
+ case 'rfc-2544':
+ getSplunkURL = `${splunkURL}rfc2544_?form.global_time.earliest=${encodeURIComponent(startDate.toISOString())}&form.global_time.latest=${encodeURIComponent(endDate.toISOString())}&form.bubble_chart_legend=kernel&form.formal_tag=${encodeURIComponent(benchmarkConfigs.formal)}&form.ocp_version=${encodeURIComponent(benchmarkConfigs.shortVersion)}&form.ocp_build=${encodeURIComponent(benchmarkConfigs.ocpVersion)}&form.node_name=${encodeURIComponent(benchmarkConfigs.nodeName)}&form.general_statistics=${encodeURIComponent(benchmarkConfigs.shortVersion)}&form.histogram=${encodeURIComponent(benchmarkConfigs.ocpVersion)}&form.dashboard_kernels=${encodeURIComponent(benchmarkConfigs.kernel)}`;
+ break;
+ }
+
+ getTimeFormat = status !== "upstream_failed" ?
+ formatTime(benchmarkConfigs.job_duration &&
+ benchmarkConfigs.job_duration || benchmarkConfigs.jobDuration)
+ : "Skipped"
+ getSplunkLink =
+
+
+ }
+ return {
+ getSplunkLink, getTimeFormat, status
+ }
+}
diff --git a/frontend/src/components/commons/commons.js b/frontend/src/components/commons/commons.js
new file mode 100644
index 00000000..4cced70e
--- /dev/null
+++ b/frontend/src/components/commons/commons.js
@@ -0,0 +1,10 @@
+export function getBuildLink(benchmarkConfigs) {
+ var icon = "assets/images/jenkins-icon.svg"
+ if (benchmarkConfigs.ciSystem === "PROW") {
+ icon = "assets/images/prow-icon.png"
+ }
+ return
+
+
+}
\ No newline at end of file
diff --git a/frontend/src/store/Actions/ActionCreator.js b/frontend/src/store/Actions/ActionCreator.js
index a6112761..938d914e 100644
--- a/frontend/src/store/Actions/ActionCreator.js
+++ b/frontend/src/store/Actions/ActionCreator.js
@@ -1,5 +1,5 @@
-import {BASE_URL, OCP_GRAPH_API_V1, OCP_JOBS_API_V1, CPT_JOBS_API_V1, QUAY_JOBS_API_V1, QUAY_GRAPH_API_V1} from "../Shared";
+import {BASE_URL, OCP_GRAPH_API_V1, OCP_JOBS_API_V1, CPT_JOBS_API_V1, QUAY_JOBS_API_V1, QUAY_GRAPH_API_V1, TELCO_JOBS_API_V1} from "../Shared";
import axios from "axios";
import {
errorOCPCall,
@@ -19,6 +19,12 @@ import {
setWaitForQuayUpdate,
updateQuayMetaData
} from "../reducers/QuayJobsReducer";
+import {
+ errorTelcoCall,
+ getTelcoJobsData,
+ setWaitForTelcoUpdate,
+ updateTelcoMetaData
+} from "../reducers/TelcoJobsReducer";
import {getUuidResults, setGraphError} from "../reducers/GraphReducer";
import {getQuayUuidResults, setQuayGraphError} from "../reducers/QuayGraphReducer";
@@ -158,6 +164,48 @@ export const fetchQuayJobsData = (startDate = '', endDate='') => async dispatch
}
}
+export const fetchTelcoJobsData = (startDate = '', endDate='') => async dispatch => {
+ let buildUrl = `${BASE_URL}${TELCO_JOBS_API_V1}`
+ dispatch(setWaitForTelcoUpdate({waitForUpdate:true}))
+ if(startDate !== '' && endDate !== '') {
+ buildUrl += `?start_date=${startDate}&end_date=${endDate}`
+ }
+ try{
+ let api_data = await fetchAPI(buildUrl)
+ dispatch(setWaitForTelcoUpdate({waitForUpdate:false}))
+ api_data = JSON.parse(api_data)
+ if(api_data){
+ const results = api_data.results
+ if(results){
+ const benchmarks = GetBenchmarks(results)
+ const versions = GetVersions(results)
+ const releaseStreams = GetReleaseStreams(results)
+ const ciSystems = GetCiSystems(results)
+ const formals = GetFormals(results)
+ const nodeNames = GetNodeNames(results)
+ const cpus = GetCpus(results)
+ const updatedTime = new Date().toLocaleString().replace(', ', ' ').toString();
+ await dispatch(getTelcoJobsData({
+ data: results, benchmarks, versions, releaseStreams, waitForUpdate: false, formals, nodeNames, cpus,
+ updatedTime, ciSystems, startDate: api_data.startDate, endDate: api_data.endDate
+ }))
+ await dispatch(updateTelcoMetaData({data: results}))
+ }
+ }
+ }
+ catch (e) {
+ const error = e
+ if(error.response){
+ await dispatch(errorTelcoCall({error: error.response.data.error}))
+ alert(error.response.data.error)
+ }
+ else{
+ console.log(error)
+ }
+ dispatch(setWaitForTelcoUpdate({waitForUpdate:false}))
+ }
+}
+
export const fetchCPTJobsData = (startDate = '', endDate='') => async dispatch => {
let buildUrl = `${BASE_URL}${CPT_JOBS_API_V1}`
dispatch(setWaitForCPTUpdate({waitForUpdate:true}))
@@ -206,7 +254,7 @@ const GetCiSystems = (api_data) => {
}
export const GetVersions = (api_data) => {
- return Array.from(new Set(api_data.map(item => item.shortVersion.toLowerCase().trim()))).sort()
+ return Array.from(new Set(api_data.map(item => item.shortVersion).filter(shortVersion => shortVersion !== null && shortVersion !== "").map(shortVersion => shortVersion.toUpperCase().trim()))).sort();
}
export const GetBenchmarks = (api_data) => {
@@ -249,7 +297,19 @@ const GetStatuses = (api_data) => {
}
const GetReleaseStreams = (api_data) => {
- return Array.from(new Set(api_data.map(item => item.releaseStream.toUpperCase().trim()))).sort()
+ return Array.from(new Set(api_data.map(item => item.releaseStream).filter(releaseStream => releaseStream !== null && releaseStream !== "").map(releaseStream => releaseStream.toUpperCase().trim()))).sort();
+}
+
+const GetFormals = (api_data) => {
+ return Array.from(new Set(api_data.map(item => item.formal).filter(formal => formal !== null && formal !== "").map(formal => formal.toUpperCase().trim()))).sort();
+}
+
+const GetNodeNames = (api_data) => {
+ return Array.from(new Set(api_data.map(item => item.nodeName).filter(nodeName => nodeName !== null && nodeName !== "").map(nodeName => nodeName.toUpperCase().trim()))).sort();
+}
+
+const GetCpus = (api_data) => {
+ return Array.from(new Set(api_data.map(item => item.cpu).filter(cpu => cpu !== null && cpu !== "").map(cpu => cpu.toUpperCase().trim()))).sort();
}
const GetTestNames = (api_data) => {
diff --git a/frontend/src/store/Shared.js b/frontend/src/store/Shared.js
index 31a078c9..fd2856f5 100644
--- a/frontend/src/store/Shared.js
+++ b/frontend/src/store/Shared.js
@@ -13,4 +13,6 @@ export const OCP_GRAPH_API_V1 = "/api/v1/ocp/graph"
export const CPT_JOBS_API_V1 = "/api/v1/cpt/jobs"
export const QUAY_JOBS_API_V1 = "/api/v1/quay/jobs"
-export const QUAY_GRAPH_API_V1 = "/api/v1/quay/graph"
\ No newline at end of file
+export const QUAY_GRAPH_API_V1 = "/api/v1/quay/graph"
+
+export const TELCO_JOBS_API_V1 = "/api/v1/telco/jobs"
\ No newline at end of file
diff --git a/frontend/src/store/reducers/InitialData.js b/frontend/src/store/reducers/InitialData.js
index f70aa1bc..e60bbfbe 100644
--- a/frontend/src/store/reducers/InitialData.js
+++ b/frontend/src/store/reducers/InitialData.js
@@ -91,6 +91,44 @@ export const QUAY_INITIAL_DATA = {
{name: "Status", value: "jobStatus"}],
}
+export const TELCO_INITIAL_DATA = {
+ initialState: true,
+ success: 0,
+ failure: 0,
+ total: 0,
+ others: 0,
+ duration:0,
+ ciSystems: ["All"],
+ benchmarks: ["All"],
+ versions: ["All"],
+ releaseStreams: ["All"],
+ formals: ["All"],
+ nodeNames: ["All"],
+ cpus: ["All"],
+ selectedCiSystem: "All",
+ selectedBenchmark: "All",
+ selectedVersion: "All",
+ selectedReleaseStream: "All",
+ selectedFormal: "All",
+ selectedCpu: "All",
+ selectedNodeName: "All",
+ waitForUpdate: false,
+ copyData: [],
+ data: [],
+ updatedTime: 'Loading',
+ error: null,
+ startDate: '',
+ endDate: '',
+ tableData : [{ name: "Benchmark", value: "benchmark" },
+ {name:"Release Stream", value: "releaseStream"},
+ {name:"Build", value: "ocpVersion"},
+ {name:"CPU", value: "cpu"},
+ {name:"Node Name", value: "nodeName"},
+ {name: "Start Date", value: "startDate"},
+ {name: "End Date", value: "endDate"},
+ {name: "Status", value: "jobStatus"}],
+}
+
export const CPT_INITIAL_DATA = {
initialState: true,
success: 0,
diff --git a/frontend/src/store/reducers/TelcoJobsReducer.js b/frontend/src/store/reducers/TelcoJobsReducer.js
new file mode 100644
index 00000000..8e9f8654
--- /dev/null
+++ b/frontend/src/store/reducers/TelcoJobsReducer.js
@@ -0,0 +1,61 @@
+import {createSlice, original} from "@reduxjs/toolkit";
+import {TELCO_INITIAL_DATA} from "./InitialData";
+import { getTelcoUpdatedData, getTelcoSummary } from './Utils';
+
+const jobsSlice = createSlice({
+ initialState: {
+ ...TELCO_INITIAL_DATA,
+ },
+ name: 'telcoSplunk',
+ reducers: {
+ getTelcoJobsData: (state, action) => {
+ state.initialState = false
+ state.copyData = action.payload.data
+ state.data = action.payload.data
+ state.benchmarks = ["All", ...action.payload.benchmarks]
+ state.versions = ["All", ...action.payload.versions]
+ state.releaseStreams = ["All", ...action.payload.releaseStreams]
+ state.ciSystems = ["All", ...action.payload.ciSystems]
+ state.formals = ["All", ...action.payload.formals]
+ state.nodeNames = ["All", ...action.payload.nodeNames]
+ state.cpus = ["All", ...action.payload.cpus]
+ state.waitForUpdate = action.payload.waitForUpdate
+ state.updatedTime = action.payload.updatedTime
+ state.error = null
+ Object.assign(state, getTelcoSummary(state.data))
+ state.startDate = action.payload.startDate
+ state.endDate = action.payload.endDate
+ },
+ updateTelcoDataFilter: (state, action) => {
+ const {ciSystem, benchmark, version, releaseStream, formal, nodeName, cpu} = action.payload
+ state.selectedBenchmark = benchmark
+ state.selectedVersion = version
+ state.selectedReleaseStream = releaseStream
+ state.selectedCiSystem = ciSystem
+ state.selectedFormal = formal
+ state.selectedNodeName = nodeName
+ state.selectedCpu = cpu
+ state.data = getTelcoUpdatedData(original(state.copyData), benchmark, version, releaseStream, ciSystem, formal, nodeName, cpu)
+ Object.assign(state, getTelcoSummary(state.data))
+ },
+ updateTelcoMetaData: (state, action) => {
+ state.data = getTelcoUpdatedData(action.payload.data, state.selectedBenchmark, state.selectedVersion, state.selectedReleaseStream,
+ state.selectedCiSystem, state.selectedFormal, state.selectedNodeName, state.selectedCpu)
+ Object.assign(state, getTelcoSummary(state.data))
+ },
+ setWaitForTelcoUpdate: (state, action) => {
+ state.waitForUpdate = action.payload.waitForUpdate
+ },
+ errorTelcoCall: (state, action) => {
+ state.error = action.payload.error
+ }
+ }
+})
+export const {
+ getTelcoJobsData,
+ updateTelcoDataFilter,
+ updateTelcoMetaData,
+ setWaitForTelcoUpdate,
+ errorTelcoCall,
+} = jobsSlice.actions
+export default jobsSlice.reducer
diff --git a/frontend/src/store/reducers/Utils.js b/frontend/src/store/reducers/Utils.js
index 5ae40fb2..a826b4c2 100644
--- a/frontend/src/store/reducers/Utils.js
+++ b/frontend/src/store/reducers/Utils.js
@@ -56,6 +56,22 @@ const getQuayUpdatedData = (data, platform, benchmark, releaseStream, workerCoun
return filteredData
}
+const getTelcoUpdatedData = (data, benchmark, version, releaseStream, ciSystem, formal, nodeName, cpu) => {
+ const filterValues = {
+ "cpu": cpu, "benchmark": benchmark, "shortVersion": version,
+ "releaseStream": releaseStream, "formal": formal, "ciSystem": ciSystem,
+ "nodeName": nodeName,
+ }
+ let filteredData = data
+ console.log(filteredData)
+ for (let [keyName, value] of Object.entries(filterValues))
+ filteredData = getFilteredData(filteredData, value, keyName)
+ console.log(filterValues)
+ console.log(filteredData)
+
+ return filteredData
+}
+
const getCPTSummary = (api_data) => {
let success = 0;
let failure = 0;
@@ -100,5 +116,20 @@ const getQuaySummary = (api_data) => {
return { success, failure, others, total, duration };
}
+const getTelcoSummary = (api_data) => {
+ let success = 0;
+ let failure = 0;
+ let others = 0;
+ let duration = 0;
+ api_data.forEach(item => {
+ if(item.jobStatus.toLowerCase() === "success") success++
+ else if(item.jobStatus.toLowerCase() === "failure") failure++;
+ else others++;
+ duration += parseInt(item.jobDuration) ? parseInt(item.jobDuration) : 0;
+ })
+ const total = success + failure + others
+
+ return { success, failure, others, total, duration };
+}
-export { getCPTUpdatedData, getOCPUpdatedData, getQuayUpdatedData, getCPTSummary, getOCPSummary, getQuaySummary };
\ No newline at end of file
+export { getCPTUpdatedData, getOCPUpdatedData, getQuayUpdatedData, getTelcoUpdatedData, getCPTSummary, getOCPSummary, getQuaySummary, getTelcoSummary };
\ No newline at end of file
diff --git a/frontend/src/store/reducers/index.js b/frontend/src/store/reducers/index.js
index a057312d..ea1b6f90 100644
--- a/frontend/src/store/reducers/index.js
+++ b/frontend/src/store/reducers/index.js
@@ -1,6 +1,7 @@
import ocpJobsReducer from "./OCPJobsReducer";
import cptJobsReducer from "./CPTJobsReducer";
import quayJobsReducer from "./QuayJobsReducer";
+import telcoJobsReducer from "./TelcoJobsReducer";
import graphReducer from "./GraphReducer";
import quayGraphReducer from "./QuayGraphReducer";
@@ -9,6 +10,7 @@ export const rootReducer = {
'ocpJobs': ocpJobsReducer,
'cptJobs': cptJobsReducer,
'quayJobs': quayJobsReducer,
+ 'telcoJobs': telcoJobsReducer,
'graph': graphReducer,
'quayGraph': quayGraphReducer,
}