Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refining Quay UI elements #88

Merged
merged 1 commit into from
Mar 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions backend/app/api/v1/commons/example_responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,50 @@ def response_422():
]
}

quay_response_example ={
"startDate": "2023-09-20",
"endDate": "2023-09-20",
"results": [
{
"ciSystem": "PROW",
"uuid": "CPT-e3865b03-ce78-454a-becb-b79aeb806a6b",
"releaseStream": "stable-3.10",
"platform": "AWS",
"clusterType": "self-managed",
"benchmark": "quay-load-test",
"hitSize": 100,
"concurrency": 50,
"imagePushPulls": 10,
"masterNodesCount": 3,
"workerNodesCount": 252,
"infraNodesCount": 3,
"masterNodesType": "m6a.8xlarge",
"workerNodesType": "m5.2xlarge",
"infraNodesType": "r5.4xlarge",
"totalNodesCount": 258,
"clusterName": "quaytest-123sffdf",
"ocpVersion": "4.14.0-0.nightly-2023-09-15-233408",
"networkType": "OVNKubernetes",
"buildTag": "1704299395064795136",
"jobStatus": "success",
"buildUrl": "https://example.com/1704299395064795136",
"upstreamJob": "quay-pipeline",
"executionDate": "2023-09-20T02:14:07Z",
"jobDuration": "5261",
"startDate": "2023-09-20T02:14:07Z",
"endDate": "2023-09-20T03:41:48Z",
"timestamp": "2023-09-20T02:14:07Z",
"shortVersion": "4.14"
},
]
}

def ocp_200_response():
return response_200(ocp_response_example)

def quay_200_response():
return response_200(quay_response_example)

cpt_response_example ={
"startDate": "2023-11-18",
"endDate": "2023-11-23",
Expand Down
50 changes: 7 additions & 43 deletions backend/app/api/v1/commons/ocp.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from datetime import date
import pandas as pd
import app.api.v1.commons.utils as utils
from app.services.search import ElasticService


Expand Down Expand Up @@ -33,12 +34,12 @@ async def getData(start_datetime: date, end_datetime: date, configpath: str):
'publish', 'computeArch', 'controlPlaneArch']] = jobs[['ipsec', 'fips', 'encrypted',
'publish', 'computeArch', 'controlPlaneArch']].replace(r'^\s*$', "N/A", regex=True)
jobs['encryptionType'] = jobs.apply(fillEncryptionType, axis=1)
jobs['benchmark'] = jobs.apply(updateBenchmark, axis=1)
jobs['platform'] = jobs.apply(clasifyAWSJobs, axis=1)
jobs['jobType'] = jobs.apply(jobType, axis=1)
jobs['isRehearse'] = jobs.apply(isRehearse, axis=1)
jobs['jobStatus'] = jobs.apply(updateStatus, axis=1)
jobs['build'] = jobs.apply(getBuild, axis=1)
jobs['benchmark'] = jobs.apply(utils.updateBenchmark, axis=1)
jobs['platform'] = jobs.apply(utils.clasifyAWSJobs, axis=1)
jobs['jobType'] = jobs.apply(utils.jobType, axis=1)
jobs['isRehearse'] = jobs.apply(utils.isRehearse, axis=1)
jobs['jobStatus'] = jobs.apply(utils.updateStatus, axis=1)
jobs['build'] = jobs.apply(utils.getBuild, axis=1)

cleanJobs = jobs[jobs['platform'] != ""]

Expand All @@ -47,43 +48,6 @@ async def getData(start_datetime: date, end_datetime: date, configpath: str):

return jbs


def updateStatus(row):
return row["jobStatus"].lower()


def updateBenchmark(row):
if row["upstreamJob"].__contains__("upgrade"):
return "upgrade-" + row["benchmark"]
return row["benchmark"]


def jobType(row):
if row["upstreamJob"].__contains__("periodic"):
return "periodic"
return "pull request"


def isRehearse(row):
if row["upstreamJob"].__contains__("rehearse"):
return "True"
return "False"


def clasifyAWSJobs(row):
if row["upstreamJob"].__contains__("rosa-hcp"):
return "AWS ROSA-HCP"
if row["clusterType"].__contains__("rosa"):
return "AWS ROSA"
return row["platform"]


def getBuild(row):
releaseStream = row["releaseStream"] + "-"
ocpVersion = row["ocpVersion"]
return ocpVersion.replace(releaseStream, "")


def fillEncryptionType(row):
if row["encrypted"] == "N/A":
return "N/A"
Expand Down
39 changes: 39 additions & 0 deletions backend/app/api/v1/commons/quay.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
from datetime import date
import pandas as pd
import app.api.v1.commons.utils as utils
from app.services.search import ElasticService


async def getData(start_datetime: date, end_datetime: date, configpath: str):
query = {
"query": {
"bool": {
"filter": {
"range": {
"timestamp": {
"format": "yyyy-MM-dd"
}
}
}
}
}
}

es = ElasticService(configpath=configpath)
response = await es.post(query=query, start_date=start_datetime, end_date=end_datetime, timestamp_field='timestamp')
await es.close()
tasks = [item['_source'] for item in response]
jobs = pd.json_normalize(tasks)
if len(jobs) == 0:
return jobs

jobs[['masterNodesCount', 'workerNodesCount',
'infraNodesCount', 'totalNodesCount']] = jobs[['masterNodesCount', 'workerNodesCount', 'infraNodesCount', 'totalNodesCount']].fillna(0)
jobs.fillna('', inplace=True)
jobs['benchmark'] = jobs.apply(utils.updateBenchmark, axis=1)
jobs['platform'] = jobs.apply(utils.clasifyAWSJobs, axis=1)
jobs['jobStatus'] = jobs.apply(utils.updateStatus, axis=1)
jobs['build'] = jobs.apply(utils.getBuild, axis=1)
jobs['shortVersion'] = jobs['ocpVersion'].str.slice(0, 4)

return jobs[jobs['platform'] != ""]
37 changes: 36 additions & 1 deletion backend/app/api/v1/commons/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,39 @@ async def getMetadata(uuid: str, configpath: str) :
response = await es.post(query=query)
await es.close()
meta = [item['_source'] for item in response]
return meta[0]
return meta[0]

def updateStatus(job):
return job["jobStatus"].lower()


def updateBenchmark(job):
if job["upstreamJob"].__contains__("upgrade"):
return "upgrade-" + job["benchmark"]
return job["benchmark"]


def jobType(job):
if job["upstreamJob"].__contains__("periodic"):
return "periodic"
return "pull request"


def isRehearse(job):
if job["upstreamJob"].__contains__("rehearse"):
return "True"
return "False"


def clasifyAWSJobs(job):
if job["upstreamJob"].__contains__("rosa-hcp"):
return "AWS ROSA-HCP"
if job["clusterType"].__contains__("rosa"):
return "AWS ROSA"
return job["platform"]


def getBuild(job):
releaseStream = job["releaseStream"] + "-"
ocpVersion = job["ocpVersion"]
return ocpVersion.replace(releaseStream, "")
16 changes: 5 additions & 11 deletions backend/app/api/v1/endpoints/cpt/maps/quay.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
from ....commons.ocp import getData
from ....commons.quay import getData
from datetime import date


################################################################
#####################################################################
# This will return a DataFrame from Quay required by the CPT endpoint
################################################################
#####################################################################
async def quayMapper(start_datetime: date, end_datetime: date, configpath: str):
df = await getData(start_datetime, end_datetime, configpath)
df.insert(len(df.columns), "product", "quay")
df["releaseStream"] = df.apply(getReleaseStream, axis=1)
df["version"] = df["shortVersion"]
df["version"] = df["releaseStream"]
df["testName"] = df["benchmark"]
return df

def getReleaseStream(row):
if row["releaseStream"].__contains__("nightly"):
return "Nightly"
return "Stable"
return df
5 changes: 3 additions & 2 deletions backend/app/api/v1/endpoints/quay/quayGraphs.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,13 +291,14 @@ async def getMatchRuns(meta: dict):
"query_string": {
"query": (
f'benchmark: "{meta["benchmark"]}$"'
f' AND hitSize: "{meta["hitSize"]}"'
f' AND concurrency: "{meta["concurrency"]}"'
f' AND imagePushPulls: "{meta["imagePushPulls"]}"'
f' AND workerNodesType: "{meta["workerNodesType"]}"'
f' AND masterNodesType: "{meta["masterNodesType"]}"'
f' AND masterNodesCount: "{meta["masterNodesCount"]}"'
f' AND workerNodesCount: "{meta["workerNodesCount"]}"'
f' AND platform: "{meta["platform"]}"'
f' AND releaseStream: "{meta["releaseStream"]}"'
f' AND ocpVersion: {version}*'
f' AND jobStatus: success'
)
}
Expand Down
6 changes: 3 additions & 3 deletions backend/app/api/v1/endpoints/quay/quayJobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
from fastapi import Response
from datetime import datetime, timedelta, date
from fastapi import APIRouter
from ...commons.ocp import getData
from ...commons.example_responses import ocp_200_response, response_422
from ...commons.quay import getData
from ...commons.example_responses import quay_200_response, response_422
from fastapi.param_functions import Query

router = APIRouter()
Expand All @@ -17,7 +17,7 @@
`startDate`: will be set to the day of the request minus 5 days.\
`endDate`: will be set to the day of the request.",
responses={
200: ocp_200_response(),
200: quay_200_response(),
422: response_422(),
},)
async def jobs(start_date: date = Query(None, description="Start date for searching jobs, format: 'YYYY-MM-DD'", examples=["2020-11-10"]),
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/OCP/BenchmarkResults.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Grid, GridItem} from "@patternfly/react-core";
import InstallCard from "../commons/InstallCard";
import InstallCard from "./InstallCard";
import React from "react";
import {DisplayGraph} from "./DisplayGraph";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ 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 { DisplayGrafana } from "./DisplayGrafana";
import { DisplayGrafana } from "../commons/DisplayGrafana";


export default function InstallCard(props) {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/Quay/BenchmarkResults.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Grid, GridItem} from "@patternfly/react-core";
import InstallCard from "../commons/InstallCard";
import InstallCard from "./InstallCard";
import React from "react";
import {DisplayGraph} from "./DisplayGraph";

Expand Down
90 changes: 90 additions & 0 deletions frontend/src/components/Quay/InstallCard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
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 { DisplayGrafana } from "../commons/DisplayGrafana";


export default function InstallCard(props) {
let config = props.data
const [isExpanded, setExpanded] = React.useState([true, null])


const onExpand = () => {
setExpanded(!isExpanded)
};

const icons = {
"failed": <><FaExclamationCircle color="red"/></>,
"success": <><FaCheck color="green"/></>,
"upstream_failed": <><FaExclamationTriangle color="yellow"/></>,

}

if (config) {
return (
<Card isExpanded={isExpanded}>
<CardHeader
onExpand={onExpand}
toggleButtonProps={{
id: 'toggle-button',
'aria-label': 'Details',
'aria-labelledby': 'titleId toggle-button',
'aria-expanded': isExpanded
}}
>
<CardTitle>Configs</CardTitle>

</CardHeader>
<CardExpandableContent>
<CardBody>
<Grid>
<GridItem rowSpan="1">
<Card><CardHeader><CardTitle>Cluster Metadata</CardTitle></CardHeader>
<CardBody><ul>
<li><span class="list-item-key">Release Binary</span>: {config.cluster_version && config.cluster_version || config.ocpVersion}</li>
<li><span class="list-item-key">Cluster Name</span>: {config.cluster_name && config.cluster_name || config.clusterName}</li>
<li><span class="list-item-key">Cluster Type</span>: {config.cluster_type && config.cluster_type || config.clusterType}</li>
<li><span class="list-item-key">Network Type</span>: {config.network_type && config.network_type || config.networkType}</li>
<li><span class="list-item-key">Benchmark Status</span>: {icons[config.job_status && config.job_status || config.jobStatus] || config.job_status && config.job_status || config.jobStatus}</li>
<li><span class="list-item-key">Duration</span>: {formatTime(config.job_duration && config.job_duration || config.jobDuration)}</li>
<li><span class="list-item-key">Test ID</span>: {config.uuid}</li>
</ul>
</CardBody></Card></GridItem>
<DisplayGrafana benchmarkConfigs={ config } />
<GridItem span="6">
<Card><CardHeader><CardTitle>Node Types</CardTitle></CardHeader>
<CardBody><ul>
<li><span class="list-item-key">Master</span>: {config.master_type && config.master_type || config.masterNodesType}</li>
<li><span class="list-item-key">Worker</span>: {config.worker_type && config.worker_type || config.workerNodesType}</li>
<li><span class="list-item-key">Workload</span>: {config.workload_type && config.workload_type || config.benchmark}</li>
<li><span class="list-item-key">Infra</span>: {config.infra_type && config.infra_type || config.infraNodesType}</li>
</ul>
</CardBody></Card></GridItem><GridItem span="6">
<Card><CardHeader><CardTitle>Node Counts</CardTitle></CardHeader>
<CardBody><ul>
<li><span class="list-item-key">Master</span>: {config.master_count && config.master_count || config.masterNodesCount}</li>
<li><span class="list-item-key">Worker</span>: {config.worker_count && config.worker_count || config.workerNodesCount}</li>
<li><span class="list-item-key">Infra</span>: {config.infra_count && config.infra_count || config.infraNodesCount}</li>
<li><span class="list-item-key">Total Nodes</span>: {config.workload_count && config.workload_count || config.totalNodesCount}</li>
</ul>
</CardBody></Card>
</GridItem>
</Grid>
</CardBody></CardExpandableContent>


</Card>)
} else {
return (
<Card>
<CardTitle>Install Configuration</CardTitle>
<CardBody><Spinner isSVG /><br />Awaiting Results</CardBody>
<CardFooter></CardFooter>
</Card>
)
}

}
Loading
Loading