Skip to content

Commit 6f31bca

Browse files
soyaczk0machi
authored andcommitted
improvement(view_widget): new nemesis stats widget
We want to see nemesis statistics run for selected release. Something similar we currently have in elasticsearch. In this initial version user gets 2 charts: 1. Pie chart showing statistics of overall nemesis pass/failure rate 2. Bar chart with corresponding nemesis pass/failure rates additionally, stats for number of hours nemesis run and distinct nemesis executed. All data can be filtered per release/specific patch version. refs: #446
1 parent 0dfe96b commit 6f31bca

File tree

5 files changed

+405
-1
lines changed

5 files changed

+405
-1
lines changed

argus/backend/controller/view_api.py

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from argus.backend.controller.views_widgets.highlights import bp as highlights_bp
99
from argus.backend.controller.views_widgets.summary import bp as summary_bp
1010
from argus.backend.controller.views_widgets.graphs import bp as graphs_bp
11+
from argus.backend.controller.views_widgets.nemesis_stats import bp as nemesis_stats_bp
1112
from argus.backend.error_handlers import handle_api_exception
1213
from argus.backend.models.web import User
1314
from argus.backend.service.stats import ViewStatsCollector
@@ -20,6 +21,7 @@
2021
bp.register_blueprint(highlights_bp)
2122
bp.register_blueprint(summary_bp)
2223
bp.register_blueprint(graphs_bp)
24+
bp.register_blueprint(nemesis_stats_bp)
2325
bp.register_error_handler(Exception, handle_api_exception)
2426

2527

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from uuid import UUID
2+
3+
from flask import Blueprint, request
4+
5+
from argus.backend.models.web import ArgusUserView
6+
from argus.backend.service.views_widgets.nemesis_stats import NemesisStatsService
7+
from argus.backend.service.user import api_login_required
8+
9+
10+
bp = Blueprint("nemesis_stats", __name__, url_prefix="/widgets")
11+
12+
13+
@bp.route("/nemesis_data", methods=["GET"])
14+
@api_login_required
15+
def get_nemesis_data():
16+
view_id = UUID(request.args.get("view_id"))
17+
view: ArgusUserView = ArgusUserView.get(id=view_id)
18+
service = NemesisStatsService()
19+
nemesis_data = []
20+
for test_id in view.tests:
21+
data = service.get_nemesis_data(test_id)
22+
nemesis_data.extend(data)
23+
return {
24+
"status": "ok",
25+
"response": {"nemesis_data": nemesis_data},
26+
}
27+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
from dataclasses import dataclass
2+
from uuid import UUID
3+
4+
5+
from argus.backend.db import ScyllaCluster
6+
from argus.backend.plugins.sct.testrun import SCTTestRun
7+
8+
@dataclass
9+
class NemesisStats:
10+
version: str
11+
name: str
12+
duration: int
13+
status: str
14+
15+
16+
class NemesisStatsService:
17+
18+
def __init__(self) -> None:
19+
self.cluster = ScyllaCluster.get()
20+
21+
def get_nemesis_data(self, test_id: UUID):
22+
rows = SCTTestRun.filter(test_id=test_id).only(["id", "nemesis_data", "investigation_status", "packages"]).all()
23+
nemesis_data = []
24+
for test in [row for row in rows if row["investigation_status"].lower() != "ignored"]:
25+
try:
26+
version = [package.version for package in test["packages"] if package.name == "scylla-server"][0]
27+
except (IndexError, TypeError):
28+
continue
29+
if not test["nemesis_data"]:
30+
continue
31+
for nemesis in [nemesis for nemesis in test["nemesis_data"] if nemesis.status in ("succeeded", "failed")]:
32+
nemesis_data.append({"version": version, "name": nemesis.name.split("disrupt_")[-1], "duration": nemesis.end_time - nemesis.start_time,
33+
"status": nemesis.status})
34+
return nemesis_data

frontend/Common/ViewTypes.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import ViewHighlights from "../Views/Widgets/ViewHighlights/ViewHighlights.svelt
1111
import IntegerValue from "../Views/WidgetSettingTypes/IntegerValue.svelte";
1212
import SummaryWidget from "../Views/Widgets/SummaryWidget/SummaryWidget.svelte";
1313
import GraphWidget from "../Views/Widgets/GraphsWidget/GraphsWidget.svelte";
14-
14+
import ViewNemesisStats from "../Views/Widgets/ViewNemesisStats.svelte";
1515

1616
export class Widget {
1717
constructor(position = -1, type = "testDashboard", settings = {}) {
@@ -127,6 +127,12 @@ export const WIDGET_TYPES = {
127127
friendlyName: "Graphs Views",
128128
settingDefinitions: {}
129129
},
130+
releaseStats: {
131+
type: ViewNemesisStats,
132+
friendlyName: "Nemesis stats",
133+
settingDefinitions: {
134+
},
135+
},
130136
};
131137

132138

0 commit comments

Comments
 (0)