argus-alm 0.15.2__py3-none-any.whl → 0.15.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- argus/_version.py +2 -2
- argus/client/generic_result.py +6 -1
- {argus_alm-0.15.2.dist-info → argus_alm-0.15.3.dist-info}/METADATA +1 -1
- argus_alm-0.15.3.dist-info/RECORD +22 -0
- argus/backend/.gitkeep +0 -0
- argus/backend/__init__.py +0 -0
- argus/backend/cli.py +0 -57
- argus/backend/controller/__init__.py +0 -0
- argus/backend/controller/admin.py +0 -20
- argus/backend/controller/admin_api.py +0 -355
- argus/backend/controller/api.py +0 -589
- argus/backend/controller/auth.py +0 -67
- argus/backend/controller/client_api.py +0 -109
- argus/backend/controller/main.py +0 -316
- argus/backend/controller/notification_api.py +0 -72
- argus/backend/controller/notifications.py +0 -13
- argus/backend/controller/planner_api.py +0 -194
- argus/backend/controller/team.py +0 -129
- argus/backend/controller/team_ui.py +0 -19
- argus/backend/controller/testrun_api.py +0 -513
- argus/backend/controller/view_api.py +0 -188
- argus/backend/controller/views_widgets/__init__.py +0 -0
- argus/backend/controller/views_widgets/graphed_stats.py +0 -54
- argus/backend/controller/views_widgets/graphs.py +0 -68
- argus/backend/controller/views_widgets/highlights.py +0 -135
- argus/backend/controller/views_widgets/nemesis_stats.py +0 -26
- argus/backend/controller/views_widgets/summary.py +0 -43
- argus/backend/db.py +0 -98
- argus/backend/error_handlers.py +0 -41
- argus/backend/events/event_processors.py +0 -34
- argus/backend/models/__init__.py +0 -0
- argus/backend/models/argus_ai.py +0 -24
- argus/backend/models/github_issue.py +0 -60
- argus/backend/models/plan.py +0 -24
- argus/backend/models/result.py +0 -187
- argus/backend/models/runtime_store.py +0 -58
- argus/backend/models/view_widgets.py +0 -25
- argus/backend/models/web.py +0 -403
- argus/backend/plugins/__init__.py +0 -0
- argus/backend/plugins/core.py +0 -248
- argus/backend/plugins/driver_matrix_tests/controller.py +0 -66
- argus/backend/plugins/driver_matrix_tests/model.py +0 -429
- argus/backend/plugins/driver_matrix_tests/plugin.py +0 -21
- argus/backend/plugins/driver_matrix_tests/raw_types.py +0 -62
- argus/backend/plugins/driver_matrix_tests/service.py +0 -61
- argus/backend/plugins/driver_matrix_tests/udt.py +0 -42
- argus/backend/plugins/generic/model.py +0 -86
- argus/backend/plugins/generic/plugin.py +0 -15
- argus/backend/plugins/generic/types.py +0 -14
- argus/backend/plugins/loader.py +0 -39
- argus/backend/plugins/sct/controller.py +0 -224
- argus/backend/plugins/sct/plugin.py +0 -37
- argus/backend/plugins/sct/resource_setup.py +0 -177
- argus/backend/plugins/sct/service.py +0 -682
- argus/backend/plugins/sct/testrun.py +0 -288
- argus/backend/plugins/sct/udt.py +0 -100
- argus/backend/plugins/sirenada/model.py +0 -118
- argus/backend/plugins/sirenada/plugin.py +0 -16
- argus/backend/service/admin.py +0 -26
- argus/backend/service/argus_service.py +0 -696
- argus/backend/service/build_system_monitor.py +0 -185
- argus/backend/service/client_service.py +0 -127
- argus/backend/service/event_service.py +0 -18
- argus/backend/service/github_service.py +0 -233
- argus/backend/service/jenkins_service.py +0 -269
- argus/backend/service/notification_manager.py +0 -159
- argus/backend/service/planner_service.py +0 -608
- argus/backend/service/release_manager.py +0 -229
- argus/backend/service/results_service.py +0 -690
- argus/backend/service/stats.py +0 -610
- argus/backend/service/team_manager_service.py +0 -82
- argus/backend/service/test_lookup.py +0 -172
- argus/backend/service/testrun.py +0 -489
- argus/backend/service/user.py +0 -308
- argus/backend/service/views.py +0 -219
- argus/backend/service/views_widgets/__init__.py +0 -0
- argus/backend/service/views_widgets/graphed_stats.py +0 -180
- argus/backend/service/views_widgets/highlights.py +0 -374
- argus/backend/service/views_widgets/nemesis_stats.py +0 -34
- argus/backend/template_filters.py +0 -27
- argus/backend/tests/__init__.py +0 -0
- argus/backend/tests/client_service/__init__.py +0 -0
- argus/backend/tests/client_service/test_submit_results.py +0 -79
- argus/backend/tests/conftest.py +0 -180
- argus/backend/tests/results_service/__init__.py +0 -0
- argus/backend/tests/results_service/test_best_results.py +0 -178
- argus/backend/tests/results_service/test_cell.py +0 -65
- argus/backend/tests/results_service/test_chartjs_additional_functions.py +0 -259
- argus/backend/tests/results_service/test_create_chartjs.py +0 -220
- argus/backend/tests/results_service/test_result_metadata.py +0 -100
- argus/backend/tests/results_service/test_results_service.py +0 -203
- argus/backend/tests/results_service/test_validation_rules.py +0 -213
- argus/backend/tests/view_widgets/__init__.py +0 -0
- argus/backend/tests/view_widgets/test_highlights_api.py +0 -532
- argus/backend/util/common.py +0 -65
- argus/backend/util/config.py +0 -38
- argus/backend/util/encoders.py +0 -56
- argus/backend/util/logsetup.py +0 -80
- argus/backend/util/module_loaders.py +0 -30
- argus/backend/util/send_email.py +0 -91
- argus/client/tests/__init__.py +0 -0
- argus/client/tests/conftest.py +0 -19
- argus/client/tests/test_package.py +0 -45
- argus/client/tests/test_results.py +0 -224
- argus_alm-0.15.2.dist-info/RECORD +0 -122
- {argus_alm-0.15.2.dist-info → argus_alm-0.15.3.dist-info}/WHEEL +0 -0
- {argus_alm-0.15.2.dist-info → argus_alm-0.15.3.dist-info}/entry_points.txt +0 -0
- {argus_alm-0.15.2.dist-info → argus_alm-0.15.3.dist-info}/licenses/LICENSE +0 -0
- {argus_alm-0.15.2.dist-info → argus_alm-0.15.3.dist-info}/top_level.txt +0 -0
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
from uuid import UUID
|
|
3
|
-
from flask import (
|
|
4
|
-
Blueprint,
|
|
5
|
-
jsonify,
|
|
6
|
-
request,
|
|
7
|
-
)
|
|
8
|
-
from argus.backend.controller.views_widgets.highlights import bp as highlights_bp
|
|
9
|
-
from argus.backend.controller.views_widgets.summary import bp as summary_bp
|
|
10
|
-
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
|
|
12
|
-
from argus.backend.controller.views_widgets.graphed_stats import bp as graphed_stats_bp
|
|
13
|
-
from argus.backend.error_handlers import handle_api_exception
|
|
14
|
-
from argus.backend.models.web import User
|
|
15
|
-
from argus.backend.service.stats import ViewStatsCollector
|
|
16
|
-
from argus.backend.service.user import api_login_required
|
|
17
|
-
from argus.backend.service.views import UserViewService
|
|
18
|
-
from argus.backend.util.common import get_payload
|
|
19
|
-
|
|
20
|
-
bp = Blueprint('view_api', __name__, url_prefix='/views')
|
|
21
|
-
LOGGER = logging.getLogger(__name__)
|
|
22
|
-
bp.register_blueprint(highlights_bp)
|
|
23
|
-
bp.register_blueprint(summary_bp)
|
|
24
|
-
bp.register_blueprint(graphs_bp)
|
|
25
|
-
bp.register_blueprint(graphed_stats_bp)
|
|
26
|
-
bp.register_blueprint(nemesis_stats_bp)
|
|
27
|
-
bp.register_error_handler(Exception, handle_api_exception)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
class ViewApiException(Exception):
|
|
31
|
-
pass
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
@bp.route("/", methods=["GET"])
|
|
35
|
-
@api_login_required
|
|
36
|
-
def index():
|
|
37
|
-
return {
|
|
38
|
-
"status": "ok",
|
|
39
|
-
"response": {
|
|
40
|
-
"version": "v1",
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
@bp.route("/create", methods=["POST"])
|
|
46
|
-
@api_login_required
|
|
47
|
-
def create_view():
|
|
48
|
-
payload = get_payload(request)
|
|
49
|
-
service = UserViewService()
|
|
50
|
-
view = service.create_view(
|
|
51
|
-
name=payload["name"],
|
|
52
|
-
items=payload["items"],
|
|
53
|
-
widget_settings=payload["settings"],
|
|
54
|
-
description=payload.get("description"),
|
|
55
|
-
display_name=payload.get("displayName")
|
|
56
|
-
)
|
|
57
|
-
return {
|
|
58
|
-
"status": "ok",
|
|
59
|
-
"response": view
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
@bp.route("/get", methods=["GET"])
|
|
64
|
-
@api_login_required
|
|
65
|
-
def get_view():
|
|
66
|
-
view_id = request.args.get("viewId")
|
|
67
|
-
if not view_id:
|
|
68
|
-
raise ViewApiException("No viewId provided.")
|
|
69
|
-
service = UserViewService()
|
|
70
|
-
view = service.get_view(UUID(view_id))
|
|
71
|
-
return {
|
|
72
|
-
"status": "ok",
|
|
73
|
-
"response": view
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
@bp.route("/all", methods=["GET"])
|
|
78
|
-
@api_login_required
|
|
79
|
-
def get_all_views():
|
|
80
|
-
user_id = request.args.get("userId")
|
|
81
|
-
if user_id:
|
|
82
|
-
user = User.get(id=user_id)
|
|
83
|
-
else:
|
|
84
|
-
user = None
|
|
85
|
-
service = UserViewService()
|
|
86
|
-
views = service.get_all_views(user)
|
|
87
|
-
return {
|
|
88
|
-
"status": "ok",
|
|
89
|
-
"response": views
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
@bp.route("/update", methods=["POST"])
|
|
94
|
-
@api_login_required
|
|
95
|
-
def update_view():
|
|
96
|
-
payload = get_payload(request)
|
|
97
|
-
service = UserViewService()
|
|
98
|
-
res = service.update_view(view_id=payload["viewId"], update_data=payload["updateData"])
|
|
99
|
-
return {
|
|
100
|
-
"status": "ok",
|
|
101
|
-
"response": res
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
@bp.route("/delete", methods=["POST"])
|
|
106
|
-
@api_login_required
|
|
107
|
-
def delete_view():
|
|
108
|
-
payload = get_payload(request)
|
|
109
|
-
service = UserViewService()
|
|
110
|
-
res = service.delete_view(payload["viewId"])
|
|
111
|
-
return {
|
|
112
|
-
"status": "ok",
|
|
113
|
-
"response": res
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
@bp.route("/search", methods=["GET"])
|
|
118
|
-
@api_login_required
|
|
119
|
-
def search_tests():
|
|
120
|
-
query = request.args.get("query")
|
|
121
|
-
service = UserViewService()
|
|
122
|
-
if query:
|
|
123
|
-
res = service.test_lookup(query)
|
|
124
|
-
else:
|
|
125
|
-
res = []
|
|
126
|
-
return {
|
|
127
|
-
"status": "ok",
|
|
128
|
-
"response": {
|
|
129
|
-
"hits": res,
|
|
130
|
-
"total": len(res)
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
@bp.route("/stats", methods=["GET"])
|
|
136
|
-
@api_login_required
|
|
137
|
-
def view_stats():
|
|
138
|
-
view_id = request.args.get("viewId")
|
|
139
|
-
if not view_id:
|
|
140
|
-
raise ViewApiException("No view id provided.")
|
|
141
|
-
limited = bool(int(request.args.get("limited", 0)))
|
|
142
|
-
version = request.args.get("productVersion", None)
|
|
143
|
-
include_no_version = bool(int(request.args.get("includeNoVersion", True)))
|
|
144
|
-
force = bool(int(request.args.get("force", 0)))
|
|
145
|
-
widget_id = request.args.get("widgetId", None)
|
|
146
|
-
if widget_id:
|
|
147
|
-
widget_id = int(widget_id)
|
|
148
|
-
collector = ViewStatsCollector(view_id=view_id, filter=version)
|
|
149
|
-
stats = collector.collect(limited=limited, force=force, include_no_version=include_no_version, widget_id=widget_id)
|
|
150
|
-
|
|
151
|
-
res = jsonify({
|
|
152
|
-
"status": "ok",
|
|
153
|
-
"response": stats
|
|
154
|
-
})
|
|
155
|
-
res.cache_control.max_age = 300
|
|
156
|
-
return res
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
@bp.route("/<string:view_id>/versions", methods=["GET"])
|
|
160
|
-
@api_login_required
|
|
161
|
-
def view_versions(view_id: str):
|
|
162
|
-
service = UserViewService()
|
|
163
|
-
res = service.get_versions_for_view(view_id)
|
|
164
|
-
return {
|
|
165
|
-
"status": "ok",
|
|
166
|
-
"response": res
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
@bp.route("/<string:view_id>/resolve", methods=["GET"])
|
|
171
|
-
@api_login_required
|
|
172
|
-
def view_resolve(view_id: str):
|
|
173
|
-
service = UserViewService()
|
|
174
|
-
res = service.resolve_view_for_edit(view_id)
|
|
175
|
-
return {
|
|
176
|
-
"status": "ok",
|
|
177
|
-
"response": res
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
@bp.route("/<string:view_id>/resolve/tests", methods=["GET"])
|
|
181
|
-
@api_login_required
|
|
182
|
-
def view_resolve_tests(view_id: str):
|
|
183
|
-
service = UserViewService()
|
|
184
|
-
res = service.resolve_view_tests(view_id)
|
|
185
|
-
return {
|
|
186
|
-
"status": "ok",
|
|
187
|
-
"response": res
|
|
188
|
-
}
|
|
File without changes
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
from uuid import UUID
|
|
2
|
-
|
|
3
|
-
from argus.backend.util.common import get_payload
|
|
4
|
-
from flask import Blueprint, request
|
|
5
|
-
|
|
6
|
-
from argus.backend.models.web import ArgusUserView
|
|
7
|
-
from argus.backend.service.views_widgets.graphed_stats import GraphedStatsService
|
|
8
|
-
from argus.backend.service.user import api_login_required
|
|
9
|
-
|
|
10
|
-
bp = Blueprint("graphed_stats", __name__, url_prefix="/widgets")
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
@bp.route("/graphed_stats", methods=["GET"])
|
|
14
|
-
@api_login_required
|
|
15
|
-
def get_graphed_stats():
|
|
16
|
-
view_id = UUID(request.args.get("view_id"))
|
|
17
|
-
view: ArgusUserView = ArgusUserView.get(id=view_id)
|
|
18
|
-
service = GraphedStatsService()
|
|
19
|
-
response_data = {
|
|
20
|
-
"test_runs": [],
|
|
21
|
-
"nemesis_data": []
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
filters = request.args.get("filters")
|
|
25
|
-
|
|
26
|
-
for test_id in view.tests:
|
|
27
|
-
data = service.get_graphed_stats(test_id, filters)
|
|
28
|
-
response_data["test_runs"].extend(data["test_runs"])
|
|
29
|
-
response_data["nemesis_data"].extend(data["nemesis_data"])
|
|
30
|
-
return {
|
|
31
|
-
"status": "ok",
|
|
32
|
-
"response": response_data
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
@bp.route("/runs_details", methods=["POST"])
|
|
37
|
-
@api_login_required
|
|
38
|
-
def get_runs_details():
|
|
39
|
-
"""Get detailed information for provided test runs including assignee and attached issues."""
|
|
40
|
-
data = get_payload(request)
|
|
41
|
-
if not data or "run_ids" not in data:
|
|
42
|
-
raise ValueError("Missing run_ids parameter")
|
|
43
|
-
|
|
44
|
-
run_ids = data["run_ids"]
|
|
45
|
-
if not isinstance(run_ids, list):
|
|
46
|
-
raise ValueError("run_ids must be a list")
|
|
47
|
-
|
|
48
|
-
service = GraphedStatsService()
|
|
49
|
-
result = service.get_runs_details(run_ids)
|
|
50
|
-
|
|
51
|
-
return {
|
|
52
|
-
"status": "ok",
|
|
53
|
-
"response": result
|
|
54
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
from uuid import UUID
|
|
2
|
-
from datetime import datetime, timezone
|
|
3
|
-
|
|
4
|
-
from flask import Blueprint, request
|
|
5
|
-
|
|
6
|
-
from argus.backend.models.web import ArgusUserView, ArgusTest
|
|
7
|
-
from argus.backend.service.results_service import ResultsService
|
|
8
|
-
from argus.backend.service.user import api_login_required
|
|
9
|
-
bp = Blueprint("graphs", __name__, url_prefix="/widgets")
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
@bp.route("/graphs/graph_views", methods=["GET"])
|
|
13
|
-
@api_login_required
|
|
14
|
-
def get_graph_views():
|
|
15
|
-
view_id = UUID(request.args.get("view_id"))
|
|
16
|
-
view: ArgusUserView = ArgusUserView.get(id=view_id)
|
|
17
|
-
start_date = request.args.get("start_date")
|
|
18
|
-
end_date = request.args.get("end_date")
|
|
19
|
-
service = ResultsService()
|
|
20
|
-
response = {}
|
|
21
|
-
tests_details = {}
|
|
22
|
-
|
|
23
|
-
for test_id in view.tests:
|
|
24
|
-
test_uuid = test_id
|
|
25
|
-
graph_views = service.get_argus_graph_views(test_uuid)
|
|
26
|
-
if graph_views:
|
|
27
|
-
test_name = ArgusTest.get(id=test_uuid).name
|
|
28
|
-
tests_details[str(test_id)] = {"name": test_name}
|
|
29
|
-
view_data = []
|
|
30
|
-
|
|
31
|
-
for graph_view in graph_views:
|
|
32
|
-
# Get unique table names from all graphs in the view
|
|
33
|
-
table_names = set()
|
|
34
|
-
for graph_name in graph_view.graphs.keys():
|
|
35
|
-
table_name = graph_name.rsplit(" - ", 1)[0]
|
|
36
|
-
table_names.add(table_name)
|
|
37
|
-
|
|
38
|
-
# Get graphs data for these tables
|
|
39
|
-
start_dt = datetime.fromisoformat(start_date).astimezone(timezone.utc) if start_date else None
|
|
40
|
-
end_dt = datetime.fromisoformat(end_date).astimezone(timezone.utc) if end_date else None
|
|
41
|
-
graphs, ticks, releases_filters = service.get_test_graphs(
|
|
42
|
-
test_id=test_uuid,
|
|
43
|
-
start_date=start_dt,
|
|
44
|
-
end_date=end_dt,
|
|
45
|
-
table_names=list(table_names)
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
# filter out graphs that are not in the graph views
|
|
49
|
-
graphs = [graph for graph in graphs if graph["options"]
|
|
50
|
-
["plugins"]["title"]["text"] in graph_view.graphs.keys()]
|
|
51
|
-
|
|
52
|
-
if graphs:
|
|
53
|
-
view_data.append({
|
|
54
|
-
"id": str(graph_view.id),
|
|
55
|
-
"name": graph_view.name,
|
|
56
|
-
"description": graph_view.description,
|
|
57
|
-
"graphs": graphs,
|
|
58
|
-
"ticks": ticks,
|
|
59
|
-
"releases_filters": releases_filters
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
response[str(test_id)] = view_data
|
|
63
|
-
|
|
64
|
-
return {
|
|
65
|
-
"status": "ok",
|
|
66
|
-
"response": response,
|
|
67
|
-
"tests_details": tests_details
|
|
68
|
-
}
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
from dataclasses import asdict
|
|
2
|
-
from uuid import UUID
|
|
3
|
-
|
|
4
|
-
from flask import Blueprint, request, g
|
|
5
|
-
|
|
6
|
-
from argus.backend.service.user import api_login_required
|
|
7
|
-
from argus.backend.service.views_widgets.highlights import (
|
|
8
|
-
HighlightCreate,
|
|
9
|
-
HighlightsService,
|
|
10
|
-
HighlightArchive,
|
|
11
|
-
HighlightUpdate,
|
|
12
|
-
HighlightSetAssignee,
|
|
13
|
-
HighlightSetCompleted,
|
|
14
|
-
CommentUpdate,
|
|
15
|
-
CommentDelete,
|
|
16
|
-
CommentCreate,
|
|
17
|
-
)
|
|
18
|
-
from argus.backend.util.common import get_payload
|
|
19
|
-
|
|
20
|
-
bp = Blueprint("view_widgets", __name__, url_prefix="/widgets")
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
@bp.route("/highlights/create", methods=["POST"])
|
|
24
|
-
@api_login_required
|
|
25
|
-
def create_highlight():
|
|
26
|
-
creator_id = g.user.id
|
|
27
|
-
payload = HighlightCreate(**get_payload(request))
|
|
28
|
-
service = HighlightsService()
|
|
29
|
-
highlight = service.create(creator_id, payload)
|
|
30
|
-
return {"status": "ok", "response": asdict(highlight)}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
@bp.route("/highlights", methods=["GET"])
|
|
34
|
-
@api_login_required
|
|
35
|
-
def get_highlights():
|
|
36
|
-
view_id = UUID(request.args.get("view_id"))
|
|
37
|
-
index = int(request.args.get("index"))
|
|
38
|
-
service = HighlightsService()
|
|
39
|
-
highlights, action_items = service.get_highlights(view_id, index)
|
|
40
|
-
return {
|
|
41
|
-
"status": "ok",
|
|
42
|
-
"response": {
|
|
43
|
-
"highlights": [asdict(h) for h in highlights],
|
|
44
|
-
"action_items": [asdict(a) for a in action_items],
|
|
45
|
-
},
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
@bp.route("/highlights/archive", methods=["POST"])
|
|
50
|
-
@api_login_required
|
|
51
|
-
def archive_highlight():
|
|
52
|
-
payload = HighlightArchive(**get_payload(request))
|
|
53
|
-
service = HighlightsService()
|
|
54
|
-
service.archive_highlight(payload)
|
|
55
|
-
return {"status": "ok"}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
@bp.route("/highlights/unarchive", methods=["POST"])
|
|
59
|
-
@api_login_required
|
|
60
|
-
def unarchive_highlight():
|
|
61
|
-
payload = HighlightArchive(**get_payload(request))
|
|
62
|
-
service = HighlightsService()
|
|
63
|
-
service.unarchive_highlight(payload)
|
|
64
|
-
return {"status": "ok"}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
@bp.route("/highlights/update", methods=["POST"])
|
|
68
|
-
@api_login_required
|
|
69
|
-
def update_highlight():
|
|
70
|
-
payload = HighlightUpdate(**get_payload(request))
|
|
71
|
-
service = HighlightsService()
|
|
72
|
-
updated_highlight = service.update_highlight(g.user.id, payload)
|
|
73
|
-
return {"status": "ok", "response": asdict(updated_highlight)}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
@bp.route("/highlights/set_assignee", methods=["POST"])
|
|
77
|
-
@api_login_required
|
|
78
|
-
def set_assignee():
|
|
79
|
-
payload = HighlightSetAssignee(**get_payload(request))
|
|
80
|
-
service = HighlightsService()
|
|
81
|
-
updated_action_item = service.set_assignee(payload)
|
|
82
|
-
if payload.assignee_id:
|
|
83
|
-
service.send_action_notification(sender_id=g.user.id, username=g.user.username, view_id=payload.view_id,
|
|
84
|
-
assignee_id=payload.assignee_id, action=updated_action_item.content)
|
|
85
|
-
return {"status": "ok", "response": asdict(updated_action_item)}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
@bp.route("/highlights/set_completed", methods=["POST"])
|
|
89
|
-
@api_login_required
|
|
90
|
-
def set_completed():
|
|
91
|
-
payload = HighlightSetCompleted(**get_payload(request))
|
|
92
|
-
service = HighlightsService()
|
|
93
|
-
updated_action_item = service.set_completed(payload)
|
|
94
|
-
return {"status": "ok", "response": asdict(updated_action_item)}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
@bp.route("/highlights/comments/create", methods=["POST"])
|
|
98
|
-
@api_login_required
|
|
99
|
-
def create_comment():
|
|
100
|
-
creator_id = g.user.id
|
|
101
|
-
payload = CommentCreate(**get_payload(request))
|
|
102
|
-
service = HighlightsService()
|
|
103
|
-
comment = service.create_comment(creator_id, payload)
|
|
104
|
-
return {"status": "ok", "response": asdict(comment)}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
@bp.route("/highlights/comments/update", methods=["POST"])
|
|
108
|
-
@api_login_required
|
|
109
|
-
def update_comment():
|
|
110
|
-
user_id = g.user.id
|
|
111
|
-
payload = CommentUpdate(**get_payload(request))
|
|
112
|
-
service = HighlightsService()
|
|
113
|
-
updated_comment = service.update_comment(user_id, payload)
|
|
114
|
-
return {"status": "ok", "response": asdict(updated_comment)}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
@bp.route("/highlights/comments/delete", methods=["POST"])
|
|
118
|
-
@api_login_required
|
|
119
|
-
def delete_comment():
|
|
120
|
-
user_id = g.user.id
|
|
121
|
-
payload = CommentDelete(**get_payload(request))
|
|
122
|
-
service = HighlightsService()
|
|
123
|
-
service.delete_comment(user_id, payload)
|
|
124
|
-
return {"status": "ok"}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
@bp.route("/highlights/comments", methods=["GET"])
|
|
128
|
-
@api_login_required
|
|
129
|
-
def get_comments():
|
|
130
|
-
view_id = UUID(request.args.get("view_id"))
|
|
131
|
-
index = int(request.args.get("index"))
|
|
132
|
-
highlight_created_at = float(request.args.get("created_at"))
|
|
133
|
-
service = HighlightsService()
|
|
134
|
-
comments = service.get_comments(view_id, index, highlight_created_at)
|
|
135
|
-
return {"status": "ok", "response": [asdict(c) for c in comments]}
|
|
@@ -1,26 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
from uuid import UUID
|
|
2
|
-
|
|
3
|
-
from flask import Blueprint, request, g
|
|
4
|
-
|
|
5
|
-
from argus.backend.models.web import ArgusUserView
|
|
6
|
-
from argus.backend.service.results_service import ResultsService
|
|
7
|
-
from argus.backend.service.user import api_login_required
|
|
8
|
-
from argus.backend.util.common import get_payload
|
|
9
|
-
|
|
10
|
-
bp = Blueprint("summary", __name__, url_prefix="/widgets")
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
@bp.route("/summary/versioned_runs", methods=["GET"])
|
|
14
|
-
@api_login_required
|
|
15
|
-
def get_versioned_runs():
|
|
16
|
-
view_id = UUID(request.args.get("view_id"))
|
|
17
|
-
view: ArgusUserView = ArgusUserView.get(id=view_id)
|
|
18
|
-
service = ResultsService()
|
|
19
|
-
versioned_runs = service.get_tests_by_version("scylla-server", view.tests)
|
|
20
|
-
return {
|
|
21
|
-
"status": "ok",
|
|
22
|
-
"response": versioned_runs,
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
@bp.route("/summary/runs_results", methods=["POST"])
|
|
27
|
-
@api_login_required
|
|
28
|
-
def get_runs_results():
|
|
29
|
-
versioned_runs = get_payload(request)
|
|
30
|
-
service = ResultsService()
|
|
31
|
-
response = {}
|
|
32
|
-
for test_id, test_methods in versioned_runs.items():
|
|
33
|
-
response[test_id] = {}
|
|
34
|
-
for method, run in test_methods.items():
|
|
35
|
-
response[test_id][method] = {}
|
|
36
|
-
run_id = run['run_id']
|
|
37
|
-
response[test_id][method][run_id] = service.get_run_results(UUID(test_id), UUID(run_id), key_metrics=[
|
|
38
|
-
"P99 read", "P99 write", "duration", "Throughput write", "Throughput read", "allocs_per_op",
|
|
39
|
-
"cpu_cycles_per_op", "instructions_per_op", "logallocs_per_op"])
|
|
40
|
-
return {
|
|
41
|
-
"status": "ok",
|
|
42
|
-
"response": response,
|
|
43
|
-
}
|
argus/backend/db.py
DELETED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
from functools import cached_property
|
|
2
|
-
import logging
|
|
3
|
-
from typing import Optional
|
|
4
|
-
from flask import g, Flask
|
|
5
|
-
from cassandra.policies import WhiteListRoundRobinPolicy
|
|
6
|
-
from cassandra import ConsistencyLevel
|
|
7
|
-
from cassandra.cluster import ExecutionProfile, EXEC_PROFILE_DEFAULT, Cluster
|
|
8
|
-
from cassandra.cluster import PreparedStatement
|
|
9
|
-
from cassandra.cqlengine.management import sync_table, sync_type
|
|
10
|
-
from cassandra.cqlengine import connection
|
|
11
|
-
from cassandra.query import dict_factory
|
|
12
|
-
from cassandra.auth import PlainTextAuthProvider
|
|
13
|
-
from argus.backend.util.config import Config
|
|
14
|
-
|
|
15
|
-
from argus.backend.models.web import USED_MODELS, USED_TYPES
|
|
16
|
-
|
|
17
|
-
LOGGER = logging.getLogger(__name__)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class ScyllaCluster:
|
|
21
|
-
APP_INSTANCE: Optional['ScyllaCluster'] = None
|
|
22
|
-
|
|
23
|
-
def __init__(self, config=None):
|
|
24
|
-
if not config:
|
|
25
|
-
config = Config.load_yaml_config()
|
|
26
|
-
self.config = config
|
|
27
|
-
self.auth_provider = PlainTextAuthProvider(
|
|
28
|
-
username=config["SCYLLA_USERNAME"], password=config["SCYLLA_PASSWORD"])
|
|
29
|
-
self.lb_policy = WhiteListRoundRobinPolicy(hosts=config["SCYLLA_CONTACT_POINTS"])
|
|
30
|
-
self.execution_profile = ExecutionProfile(
|
|
31
|
-
load_balancing_policy=self.lb_policy, consistency_level=ConsistencyLevel.QUORUM)
|
|
32
|
-
connection.setup(hosts=config["SCYLLA_CONTACT_POINTS"], default_keyspace=config["SCYLLA_KEYSPACE_NAME"],
|
|
33
|
-
auth_provider=self.auth_provider,
|
|
34
|
-
protocol_version=4,
|
|
35
|
-
execution_profiles={EXEC_PROFILE_DEFAULT: self.execution_profile})
|
|
36
|
-
self.cluster: Cluster = connection.get_cluster(connection='default')
|
|
37
|
-
self.prepared_statements = {}
|
|
38
|
-
self.read_exec_profile = ExecutionProfile(
|
|
39
|
-
consistency_level=ConsistencyLevel.ONE,
|
|
40
|
-
row_factory=dict_factory,
|
|
41
|
-
load_balancing_policy=self.lb_policy
|
|
42
|
-
)
|
|
43
|
-
self.read_named_tuple_exec_profile = ExecutionProfile(
|
|
44
|
-
consistency_level=ConsistencyLevel.ONE,
|
|
45
|
-
load_balancing_policy=self.lb_policy
|
|
46
|
-
)
|
|
47
|
-
self.cluster.add_execution_profile("read_fast", self.read_exec_profile)
|
|
48
|
-
self.cluster.add_execution_profile("read_fast_named_tuple", self.read_named_tuple_exec_profile)
|
|
49
|
-
|
|
50
|
-
@cached_property
|
|
51
|
-
def session(self):
|
|
52
|
-
return self.cluster.connect(keyspace=self.config["SCYLLA_KEYSPACE_NAME"])
|
|
53
|
-
|
|
54
|
-
@classmethod
|
|
55
|
-
def get(cls, config: Config = None) -> 'ScyllaCluster':
|
|
56
|
-
if cls.APP_INSTANCE:
|
|
57
|
-
return cls.APP_INSTANCE
|
|
58
|
-
|
|
59
|
-
cls.APP_INSTANCE = cls(config)
|
|
60
|
-
return cls.APP_INSTANCE
|
|
61
|
-
|
|
62
|
-
@classmethod
|
|
63
|
-
def shutdown(cls):
|
|
64
|
-
if cls.APP_INSTANCE:
|
|
65
|
-
cls.APP_INSTANCE.cluster.shutdown()
|
|
66
|
-
cls.APP_INSTANCE = None
|
|
67
|
-
|
|
68
|
-
def prepare(self, query: str) -> PreparedStatement:
|
|
69
|
-
if not (statement := self.prepared_statements.get(query)):
|
|
70
|
-
LOGGER.info("Unprepared statement %s, preparing...", query)
|
|
71
|
-
statement = self.session.prepare(query=query)
|
|
72
|
-
self.prepared_statements[query] = statement
|
|
73
|
-
return statement
|
|
74
|
-
|
|
75
|
-
def sync_core_tables(self):
|
|
76
|
-
for udt in USED_TYPES:
|
|
77
|
-
LOGGER.info("Syncing type: %s..", udt.__name__)
|
|
78
|
-
sync_type(ks_name=self.config["SCYLLA_KEYSPACE_NAME"], type_model=udt)
|
|
79
|
-
LOGGER.info("Core Types synchronized.")
|
|
80
|
-
for model in USED_MODELS:
|
|
81
|
-
LOGGER.info("Syncing model: %s..", model.__name__)
|
|
82
|
-
sync_table(model, keyspaces=[self.config["SCYLLA_KEYSPACE_NAME"]])
|
|
83
|
-
LOGGER.info("Core Models synchronized.")
|
|
84
|
-
|
|
85
|
-
@classmethod
|
|
86
|
-
def get_session(cls):
|
|
87
|
-
cluster = cls.get()
|
|
88
|
-
if 'scylla_session' not in g:
|
|
89
|
-
g.scylla_session = cluster.session
|
|
90
|
-
return g.scylla_session
|
|
91
|
-
|
|
92
|
-
@classmethod
|
|
93
|
-
def close_session(cls, error=None):
|
|
94
|
-
g.pop("scylla_session", None)
|
|
95
|
-
|
|
96
|
-
@classmethod
|
|
97
|
-
def attach_to_app(cls, app: Flask):
|
|
98
|
-
app.teardown_appcontext(cls.close_session)
|
argus/backend/error_handlers.py
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import base64
|
|
2
|
-
from hashlib import sha256
|
|
3
|
-
import logging
|
|
4
|
-
import os
|
|
5
|
-
from traceback import format_exception
|
|
6
|
-
from flask import request
|
|
7
|
-
|
|
8
|
-
LOGGER = logging.getLogger(__name__)
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class APIException(Exception):
|
|
12
|
-
pass
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class DataValidationError(APIException):
|
|
16
|
-
pass
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def handle_api_exception(exception: Exception):
|
|
20
|
-
trace_id = base64.encodebytes(sha256(os.urandom(64)).digest()).decode(encoding="utf-8").strip()
|
|
21
|
-
if issubclass(exception.__class__, APIException):
|
|
22
|
-
LOGGER.info("[TraceId: %s] Endpoint %s responded with error %s: %s", trace_id,
|
|
23
|
-
request.endpoint, exception.__class__.__name__, str(exception))
|
|
24
|
-
LOGGER.info("[TraceId: %s] Headers\n%s", trace_id, request.headers)
|
|
25
|
-
LOGGER.info("[TraceId: %s] Request Data Start\n%s\nRequest Data End", trace_id,
|
|
26
|
-
request.json if request.is_json else request.get_data(as_text=True))
|
|
27
|
-
else:
|
|
28
|
-
LOGGER.error("[TraceId: %s] Exception in %s\n%s", trace_id,
|
|
29
|
-
request.endpoint, "".join(format_exception(exception)))
|
|
30
|
-
LOGGER.error("[TraceId: %s] Headers\n%s", trace_id, request.headers)
|
|
31
|
-
LOGGER.error("[TraceId: %s] Request Data Start\n%s\nRequest Data End", trace_id,
|
|
32
|
-
request.json if request.is_json else request.get_data(as_text=True))
|
|
33
|
-
|
|
34
|
-
return {
|
|
35
|
-
"status": "error",
|
|
36
|
-
"response": {
|
|
37
|
-
"trace_id": trace_id,
|
|
38
|
-
"exception": exception.__class__.__name__,
|
|
39
|
-
"arguments": exception.args
|
|
40
|
-
}
|
|
41
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
from argus.backend.models.web import ArgusEventTypes
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
def event_process_posted_comment(event: dict) -> dict:
|
|
5
|
-
return event["message"].format(**event)
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def event_process_status_changed(event: dict) -> dict:
|
|
9
|
-
return event["message"].format(**event)
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def event_process_investigation_status_changed(event: dict) -> dict:
|
|
13
|
-
return event["message"].format(**event)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def event_process_assignee_changed(event: dict) -> dict:
|
|
17
|
-
return event["message"].format(**event)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def event_process_issue_added(event: dict) -> dict:
|
|
21
|
-
return event["message"].format(**event)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
EVENT_PROCESSORS = {
|
|
25
|
-
ArgusEventTypes.AssigneeChanged: event_process_assignee_changed,
|
|
26
|
-
ArgusEventTypes.TestRunStatusChanged: event_process_status_changed,
|
|
27
|
-
ArgusEventTypes.TestRunCommentPosted: event_process_posted_comment,
|
|
28
|
-
ArgusEventTypes.TestRunCommentUpdated: event_process_posted_comment,
|
|
29
|
-
ArgusEventTypes.TestRunCommentDeleted: event_process_posted_comment,
|
|
30
|
-
ArgusEventTypes.TestRunIssueAdded: event_process_issue_added,
|
|
31
|
-
ArgusEventTypes.TestRunIssueRemoved: event_process_issue_added,
|
|
32
|
-
ArgusEventTypes.TestRunInvestigationStatusChanged: event_process_investigation_status_changed,
|
|
33
|
-
ArgusEventTypes.TestRunBatchInvestigationStatusChange: event_process_investigation_status_changed,
|
|
34
|
-
}
|