argus-alm 0.12.3__tar.gz → 0.12.4b2__tar.gz
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_alm-0.12.4b2/PKG-INFO +129 -0
- argus_alm-0.12.4b2/README.md +109 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/controller/admin_api.py +26 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/controller/api.py +26 -1
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/controller/main.py +21 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/controller/testrun_api.py +16 -0
- argus_alm-0.12.4b2/argus/backend/controller/view_api.py +162 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/models/web.py +16 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/plugins/core.py +25 -10
- argus_alm-0.12.4b2/argus/backend/plugins/driver_matrix_tests/controller.py +63 -0
- argus_alm-0.12.4b2/argus/backend/plugins/driver_matrix_tests/model.py +421 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/plugins/driver_matrix_tests/raw_types.py +27 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/plugins/driver_matrix_tests/service.py +18 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/plugins/driver_matrix_tests/udt.py +14 -13
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/plugins/generic/model.py +5 -2
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/plugins/sct/service.py +13 -1
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/service/argus_service.py +116 -20
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/service/build_system_monitor.py +37 -7
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/service/jenkins_service.py +2 -1
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/service/release_manager.py +14 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/service/stats.py +147 -11
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/service/testrun.py +44 -5
- argus_alm-0.12.4b2/argus/backend/service/views.py +258 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/template_filters.py +7 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/util/common.py +14 -2
- argus_alm-0.12.4b2/argus/client/driver_matrix_tests/cli.py +110 -0
- argus_alm-0.12.4b2/argus/client/driver_matrix_tests/client.py +79 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/pyproject.toml +2 -1
- argus_alm-0.12.3/PKG-INFO +0 -207
- argus_alm-0.12.3/README.md +0 -187
- argus_alm-0.12.3/argus/backend/plugins/driver_matrix_tests/controller.py +0 -24
- argus_alm-0.12.3/argus/backend/plugins/driver_matrix_tests/model.py +0 -173
- argus_alm-0.12.3/argus/client/driver_matrix_tests/client.py +0 -216
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/LICENSE +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/__init__.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/.gitkeep +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/__init__.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/cli.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/controller/__init__.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/controller/admin.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/controller/auth.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/controller/client_api.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/controller/notification_api.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/controller/notifications.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/controller/team.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/controller/team_ui.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/db.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/error_handlers.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/events/event_processors.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/models/__init__.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/plugins/__init__.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/plugins/driver_matrix_tests/plugin.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/plugins/generic/plugin.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/plugins/generic/types.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/plugins/loader.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/plugins/sct/controller.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/plugins/sct/plugin.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/plugins/sct/resource_setup.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/plugins/sct/testrun.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/plugins/sct/types.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/plugins/sct/udt.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/plugins/sirenada/model.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/plugins/sirenada/plugin.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/plugins/sirenada/types.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/service/admin.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/service/client_service.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/service/event_service.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/service/notification_manager.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/service/team_manager_service.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/service/user.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/util/config.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/util/encoders.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/util/enums.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/util/logsetup.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/util/module_loaders.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/backend/util/send_email.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/client/__init__.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/client/base.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/client/generic/cli.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/client/generic/client.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/client/sct/client.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/client/sct/types.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/client/sirenada/client.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/db/.gitkeep +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/db/argus_json.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/db/cloud_types.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/db/config.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/db/db_types.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/db/interface.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/db/testrun.py +0 -0
- {argus_alm-0.12.3 → argus_alm-0.12.4b2}/argus/db/utils.py +0 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: argus-alm
|
|
3
|
+
Version: 0.12.4b2
|
|
4
|
+
Summary: Argus
|
|
5
|
+
Home-page: https://github.com/scylladb/argus
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Author: Alexey Kartashov
|
|
8
|
+
Author-email: alexey.kartashov@scylladb.com
|
|
9
|
+
Requires-Python: >=3.10,<4.0
|
|
10
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Requires-Dist: click (>=8.1.3,<9.0.0)
|
|
16
|
+
Requires-Dist: requests (>=2.26.0,<3.0.0)
|
|
17
|
+
Project-URL: Repository, https://github.com/scylladb/argus
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
|
|
20
|
+
# Argus
|
|
21
|
+
|
|
22
|
+
## Description
|
|
23
|
+
|
|
24
|
+
Argus is a test tracking system intended to provide observability into automated test pipelines which use long-running resources. It allows observation of a test status, its events and its allocated resources. It also allows easy comparison between particular runs of a specific test.
|
|
25
|
+
|
|
26
|
+
## Installation notes
|
|
27
|
+
|
|
28
|
+
### Development
|
|
29
|
+
|
|
30
|
+
For development setup instructions, see [dev-setup.md](./docs/dev-setup.md).
|
|
31
|
+
|
|
32
|
+
### Prerequisites
|
|
33
|
+
|
|
34
|
+
- Python >=3.10.0 (system-wide or pyenv)
|
|
35
|
+
|
|
36
|
+
- NodeJS >=16 (with npm)
|
|
37
|
+
|
|
38
|
+
- Yarn (can be installed globally with `npm -g install yarn`)
|
|
39
|
+
|
|
40
|
+
- nginx
|
|
41
|
+
|
|
42
|
+
- poetry >=1.2.0b1
|
|
43
|
+
|
|
44
|
+
### From source
|
|
45
|
+
|
|
46
|
+
#### Production
|
|
47
|
+
|
|
48
|
+
Perform the following steps:
|
|
49
|
+
|
|
50
|
+
Create a user that will be used by uwsgi:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
useradd -m -s /bin/bash argus
|
|
54
|
+
sudo -iu argus
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
(Optional) Install pyenv and create a virtualenv for this user:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
pyenv install 3.10.0
|
|
61
|
+
pyenv virtualenv argus
|
|
62
|
+
pyenv activate argus
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Clone the project into a directory somewhere where user has full write permissions
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
git clone https://github.com/scylladb/argus ~/app
|
|
69
|
+
cd ~/app
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Install project dependencies:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
poetry install --with default,dev,web-backend,docker-image
|
|
76
|
+
yarn install
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Compile frontend files from `/frontend` into `/public/dist`
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
yarn webpack
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Create a `argus.local.yaml` configuration file (used to configure database connection) and a `argus_web.yaml` (used for webapp secrets) in your application install directory.
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
cp argus_web.example.yaml argus_web.yaml
|
|
89
|
+
cp argus.yaml argus.local.yaml
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Open `argus.local.yaml` and add the database connection information (contact_points, user, password and keyspace name).
|
|
93
|
+
|
|
94
|
+
Open `argus_web.yaml` and change the `SECRET_KEY` value to something secure, like a sha512 digest of random bytes. Fill out GITHUB_* variables with their respective values.
|
|
95
|
+
|
|
96
|
+
Copy nginx configuration file from `docs/configs/argus.nginx.conf` to nginx virtual hosts directory:
|
|
97
|
+
|
|
98
|
+
Ubuntu:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
sudo cp docs/configs/argus.nginx.conf /etc/nginx/sites-available/argus
|
|
102
|
+
sudo ln -s /etc/nginx/sites-enabled/argus /etc/nginx/sites-available/argus
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
RHEL/Centos/Alma/Fedora:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
sudo cp docs/configs/argus.nginx.conf /etc/nginx/conf.d/argus.conf
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Adjust the webhost settings in that file as necessary, particularly `listen` and `server_name` directives.
|
|
112
|
+
|
|
113
|
+
Copy systemd service file from `docs/config/argus.service` to `/etc/systemd/system` directory:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
sudo cp docs/config/argus.service /etc/systemd/system
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Open it and adjust the path to the `start_argus.sh` script in the `ExecStart=` directive and the user/group, then reload systemd daemon configuration and enable (and optionally start) the service.
|
|
120
|
+
|
|
121
|
+
WARNING: `start_argus.sh` assumes pyenv is installed into `~/.pyenv`
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
sudo systemctl daemon-reload
|
|
125
|
+
sudo systemctl enable --now argus.service
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Argus
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
Argus is a test tracking system intended to provide observability into automated test pipelines which use long-running resources. It allows observation of a test status, its events and its allocated resources. It also allows easy comparison between particular runs of a specific test.
|
|
6
|
+
|
|
7
|
+
## Installation notes
|
|
8
|
+
|
|
9
|
+
### Development
|
|
10
|
+
|
|
11
|
+
For development setup instructions, see [dev-setup.md](./docs/dev-setup.md).
|
|
12
|
+
|
|
13
|
+
### Prerequisites
|
|
14
|
+
|
|
15
|
+
- Python >=3.10.0 (system-wide or pyenv)
|
|
16
|
+
|
|
17
|
+
- NodeJS >=16 (with npm)
|
|
18
|
+
|
|
19
|
+
- Yarn (can be installed globally with `npm -g install yarn`)
|
|
20
|
+
|
|
21
|
+
- nginx
|
|
22
|
+
|
|
23
|
+
- poetry >=1.2.0b1
|
|
24
|
+
|
|
25
|
+
### From source
|
|
26
|
+
|
|
27
|
+
#### Production
|
|
28
|
+
|
|
29
|
+
Perform the following steps:
|
|
30
|
+
|
|
31
|
+
Create a user that will be used by uwsgi:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
useradd -m -s /bin/bash argus
|
|
35
|
+
sudo -iu argus
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
(Optional) Install pyenv and create a virtualenv for this user:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pyenv install 3.10.0
|
|
42
|
+
pyenv virtualenv argus
|
|
43
|
+
pyenv activate argus
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Clone the project into a directory somewhere where user has full write permissions
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
git clone https://github.com/scylladb/argus ~/app
|
|
50
|
+
cd ~/app
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Install project dependencies:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
poetry install --with default,dev,web-backend,docker-image
|
|
57
|
+
yarn install
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Compile frontend files from `/frontend` into `/public/dist`
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
yarn webpack
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Create a `argus.local.yaml` configuration file (used to configure database connection) and a `argus_web.yaml` (used for webapp secrets) in your application install directory.
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
cp argus_web.example.yaml argus_web.yaml
|
|
70
|
+
cp argus.yaml argus.local.yaml
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Open `argus.local.yaml` and add the database connection information (contact_points, user, password and keyspace name).
|
|
74
|
+
|
|
75
|
+
Open `argus_web.yaml` and change the `SECRET_KEY` value to something secure, like a sha512 digest of random bytes. Fill out GITHUB_* variables with their respective values.
|
|
76
|
+
|
|
77
|
+
Copy nginx configuration file from `docs/configs/argus.nginx.conf` to nginx virtual hosts directory:
|
|
78
|
+
|
|
79
|
+
Ubuntu:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
sudo cp docs/configs/argus.nginx.conf /etc/nginx/sites-available/argus
|
|
83
|
+
sudo ln -s /etc/nginx/sites-enabled/argus /etc/nginx/sites-available/argus
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
RHEL/Centos/Alma/Fedora:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
sudo cp docs/configs/argus.nginx.conf /etc/nginx/conf.d/argus.conf
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Adjust the webhost settings in that file as necessary, particularly `listen` and `server_name` directives.
|
|
93
|
+
|
|
94
|
+
Copy systemd service file from `docs/config/argus.service` to `/etc/systemd/system` directory:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
sudo cp docs/config/argus.service /etc/systemd/system
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Open it and adjust the path to the `start_argus.sh` script in the `ExecStart=` directive and the user/group, then reload systemd daemon configuration and enable (and optionally start) the service.
|
|
101
|
+
|
|
102
|
+
WARNING: `start_argus.sh` assumes pyenv is installed into `~/.pyenv`
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
sudo systemctl daemon-reload
|
|
106
|
+
sudo systemctl enable --now argus.service
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
|
|
@@ -261,3 +261,29 @@ def get_tests_for_group():
|
|
|
261
261
|
"status": "ok",
|
|
262
262
|
"response": tests
|
|
263
263
|
}
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
@bp.route("/release/test/state/toggle", methods=["POST"])
|
|
267
|
+
@check_roles(UserRoles.Admin)
|
|
268
|
+
@api_login_required
|
|
269
|
+
def quick_toggle_test_enabled():
|
|
270
|
+
|
|
271
|
+
payload = get_payload(request)
|
|
272
|
+
res = ReleaseManagerService().toggle_test_enabled(test_id=payload["entityId"], new_state=payload["state"])
|
|
273
|
+
return {
|
|
274
|
+
"status": "ok",
|
|
275
|
+
"response": res
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
@bp.route("/release/group/state/toggle", methods=["POST"])
|
|
280
|
+
@check_roles(UserRoles.Admin)
|
|
281
|
+
@api_login_required
|
|
282
|
+
def quick_toggle_group_enabled():
|
|
283
|
+
|
|
284
|
+
payload = get_payload(request)
|
|
285
|
+
res = ReleaseManagerService().toggle_group_enabled(group_id=payload["entityId"], new_state=payload["state"])
|
|
286
|
+
return {
|
|
287
|
+
"status": "ok",
|
|
288
|
+
"response": res
|
|
289
|
+
}
|
|
@@ -12,7 +12,8 @@ from argus.backend.controller.notification_api import bp as notifications_bp
|
|
|
12
12
|
from argus.backend.controller.client_api import bp as client_bp
|
|
13
13
|
from argus.backend.controller.testrun_api import bp as testrun_bp
|
|
14
14
|
from argus.backend.controller.team import bp as team_bp
|
|
15
|
-
from argus.backend.
|
|
15
|
+
from argus.backend.controller.view_api import bp as view_bp
|
|
16
|
+
from argus.backend.service.argus_service import ArgusService, ScheduleUpdateRequest
|
|
16
17
|
from argus.backend.service.user import UserService, api_login_required
|
|
17
18
|
from argus.backend.service.stats import ReleaseStatsCollector
|
|
18
19
|
from argus.backend.models.web import ArgusRelease, ArgusGroup, ArgusTest, User, UserOauthToken
|
|
@@ -23,6 +24,7 @@ bp.register_blueprint(notifications_bp)
|
|
|
23
24
|
bp.register_blueprint(client_bp)
|
|
24
25
|
bp.register_blueprint(testrun_bp)
|
|
25
26
|
bp.register_blueprint(team_bp)
|
|
27
|
+
bp.register_blueprint(view_bp)
|
|
26
28
|
bp.register_error_handler(Exception, handle_api_exception)
|
|
27
29
|
LOGGER = logging.getLogger(__name__)
|
|
28
30
|
|
|
@@ -227,6 +229,8 @@ def release_schedules_submit():
|
|
|
227
229
|
groups=payload["groups"],
|
|
228
230
|
assignees=payload["assignees"],
|
|
229
231
|
tag=payload["tag"],
|
|
232
|
+
comments=payload.get("comments"),
|
|
233
|
+
group_ids=payload.get("groupIds"),
|
|
230
234
|
)
|
|
231
235
|
|
|
232
236
|
return jsonify({
|
|
@@ -251,6 +255,27 @@ def release_schedules_delete():
|
|
|
251
255
|
})
|
|
252
256
|
|
|
253
257
|
|
|
258
|
+
@bp.route("/release/schedules/update", methods=["POST"])
|
|
259
|
+
@api_login_required
|
|
260
|
+
def release_schedule_update():
|
|
261
|
+
payload = get_payload(request)
|
|
262
|
+
req = ScheduleUpdateRequest(**payload)
|
|
263
|
+
service = ArgusService()
|
|
264
|
+
update_result = service.update_schedule(
|
|
265
|
+
release_id=req.release_id,
|
|
266
|
+
schedule_id=req.schedule_id,
|
|
267
|
+
old_tests=req.old_tests,
|
|
268
|
+
new_tests=req.new_tests,
|
|
269
|
+
comments=req.comments,
|
|
270
|
+
assignee=req.assignee
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
return jsonify({
|
|
274
|
+
"status": "ok",
|
|
275
|
+
"response": update_result
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
|
|
254
279
|
@bp.route("/groups", methods=["GET"])
|
|
255
280
|
@api_login_required
|
|
256
281
|
def argus_groups():
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import json
|
|
1
3
|
import logging
|
|
2
4
|
from uuid import UUID
|
|
3
5
|
from flask import (
|
|
@@ -8,6 +10,7 @@ from argus.backend.controller.team_ui import bp as teams_bp
|
|
|
8
10
|
from argus.backend.service.argus_service import ArgusService
|
|
9
11
|
from argus.backend.models.web import WebFileStorage
|
|
10
12
|
from argus.backend.service.user import UserService, login_required
|
|
13
|
+
from argus.backend.service.views import UserViewService
|
|
11
14
|
|
|
12
15
|
LOGGER = logging.getLogger(__name__)
|
|
13
16
|
|
|
@@ -55,6 +58,24 @@ def releases():
|
|
|
55
58
|
return render_template("releases.html.j2", releases=all_releases)
|
|
56
59
|
|
|
57
60
|
|
|
61
|
+
@bp.route("/views")
|
|
62
|
+
@login_required
|
|
63
|
+
def views():
|
|
64
|
+
service = UserViewService()
|
|
65
|
+
all_views = service.get_all_views()
|
|
66
|
+
return render_template("views.html.j2", views=sorted(all_views, key=lambda view: view.created or datetime.datetime.fromtimestamp(0), reverse=True))
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@bp.route("/view/<string:view_name>")
|
|
70
|
+
@login_required
|
|
71
|
+
def view_dashboard(view_name: str):
|
|
72
|
+
service = UserViewService()
|
|
73
|
+
view = service.get_view_by_name(view_name=view_name)
|
|
74
|
+
data_json = view
|
|
75
|
+
view["widget_settings"] = json.loads(view["widget_settings"])
|
|
76
|
+
return render_template("view_dashboard.html.j2", data=data_json)
|
|
77
|
+
|
|
78
|
+
|
|
58
79
|
@bp.route("/alert_debug")
|
|
59
80
|
@login_required
|
|
60
81
|
def alert_debug():
|
|
@@ -289,6 +289,22 @@ def ignore_jobs():
|
|
|
289
289
|
}
|
|
290
290
|
|
|
291
291
|
|
|
292
|
+
@bp.route("/get_runs_by_test_id_run_id", methods=["POST"])
|
|
293
|
+
@api_login_required
|
|
294
|
+
def get_runs_by_test_id_run_id():
|
|
295
|
+
payload: list[tuple[UUID, UUID]] = get_payload(request)
|
|
296
|
+
service = TestRunService()
|
|
297
|
+
|
|
298
|
+
result = service.resolve_run_build_id_and_number_multiple(payload)
|
|
299
|
+
|
|
300
|
+
return {
|
|
301
|
+
"status": "ok",
|
|
302
|
+
"response": {
|
|
303
|
+
"runs": result
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
|
|
292
308
|
@bp.route("/jenkins/params", methods=["POST"])
|
|
293
309
|
@api_login_required
|
|
294
310
|
def get_jenkins_job_params():
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from uuid import UUID
|
|
3
|
+
from flask import (
|
|
4
|
+
Blueprint,
|
|
5
|
+
jsonify,
|
|
6
|
+
request,
|
|
7
|
+
)
|
|
8
|
+
from argus.backend.error_handlers import handle_api_exception
|
|
9
|
+
from argus.backend.models.web import User
|
|
10
|
+
from argus.backend.service.stats import ViewStatsCollector
|
|
11
|
+
from argus.backend.service.user import api_login_required
|
|
12
|
+
from argus.backend.service.views import UserViewService
|
|
13
|
+
from argus.backend.util.common import get_payload
|
|
14
|
+
|
|
15
|
+
bp = Blueprint('view_api', __name__, url_prefix='/views')
|
|
16
|
+
LOGGER = logging.getLogger(__name__)
|
|
17
|
+
bp.register_error_handler(Exception, handle_api_exception)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ViewApiException(Exception):
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@bp.route("/", methods=["GET"])
|
|
25
|
+
@api_login_required
|
|
26
|
+
def index():
|
|
27
|
+
return {
|
|
28
|
+
"status": "ok",
|
|
29
|
+
"response": {
|
|
30
|
+
"version": "v1",
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@bp.route("/create", methods=["POST"])
|
|
36
|
+
@api_login_required
|
|
37
|
+
def create_view():
|
|
38
|
+
payload = get_payload(request)
|
|
39
|
+
service = UserViewService()
|
|
40
|
+
view = service.create_view(
|
|
41
|
+
name=payload["name"],
|
|
42
|
+
items=payload["items"],
|
|
43
|
+
widget_settings=payload["settings"],
|
|
44
|
+
description=payload.get("description"),
|
|
45
|
+
display_name=payload.get("displayName")
|
|
46
|
+
)
|
|
47
|
+
return {
|
|
48
|
+
"status": "ok",
|
|
49
|
+
"response": view
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@bp.route("/get", methods=["GET"])
|
|
54
|
+
@api_login_required
|
|
55
|
+
def get_view():
|
|
56
|
+
view_id = request.args.get("viewId")
|
|
57
|
+
if not view_id:
|
|
58
|
+
raise ViewApiException("No viewId provided.")
|
|
59
|
+
service = UserViewService()
|
|
60
|
+
view = service.get_view(UUID(view_id))
|
|
61
|
+
return {
|
|
62
|
+
"status": "ok",
|
|
63
|
+
"response": view
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@bp.route("/all", methods=["GET"])
|
|
68
|
+
@api_login_required
|
|
69
|
+
def get_all_views():
|
|
70
|
+
user_id = request.args.get("userId")
|
|
71
|
+
if user_id:
|
|
72
|
+
user = User.get(id=user_id)
|
|
73
|
+
else:
|
|
74
|
+
user = None
|
|
75
|
+
service = UserViewService()
|
|
76
|
+
views = service.get_all_views(user)
|
|
77
|
+
return {
|
|
78
|
+
"status": "ok",
|
|
79
|
+
"response": views
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@bp.route("/update", methods=["POST"])
|
|
84
|
+
@api_login_required
|
|
85
|
+
def update_view():
|
|
86
|
+
payload = get_payload(request)
|
|
87
|
+
service = UserViewService()
|
|
88
|
+
res = service.update_view(view_id=payload["viewId"], update_data=payload["updateData"])
|
|
89
|
+
return {
|
|
90
|
+
"status": "ok",
|
|
91
|
+
"response": res
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@bp.route("/delete", methods=["POST"])
|
|
96
|
+
@api_login_required
|
|
97
|
+
def delete_view():
|
|
98
|
+
payload = get_payload(request)
|
|
99
|
+
service = UserViewService()
|
|
100
|
+
res = service.delete_view(payload["viewId"])
|
|
101
|
+
return {
|
|
102
|
+
"status": "ok",
|
|
103
|
+
"response": res
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
@bp.route("/search", methods=["GET"])
|
|
108
|
+
@api_login_required
|
|
109
|
+
def search_tests():
|
|
110
|
+
query = request.args.get("query")
|
|
111
|
+
service = UserViewService()
|
|
112
|
+
if query:
|
|
113
|
+
res = service.test_lookup(query)
|
|
114
|
+
else:
|
|
115
|
+
res = []
|
|
116
|
+
return {
|
|
117
|
+
"status": "ok",
|
|
118
|
+
"response": {
|
|
119
|
+
"hits": res,
|
|
120
|
+
"total": len(res)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
@bp.route("/stats", methods=["GET"])
|
|
125
|
+
@api_login_required
|
|
126
|
+
def view_stats():
|
|
127
|
+
view_id = request.args.get("viewId")
|
|
128
|
+
if not view_id:
|
|
129
|
+
raise ViewApiException("No view id provided.")
|
|
130
|
+
limited = bool(int(request.args.get("limited", 0)))
|
|
131
|
+
version = request.args.get("productVersion", None)
|
|
132
|
+
include_no_version = bool(int(request.args.get("includeNoVersion", True)))
|
|
133
|
+
force = bool(int(request.args.get("force", 0)))
|
|
134
|
+
collector = ViewStatsCollector(view_id=view_id, filter=version)
|
|
135
|
+
stats = collector.collect(limited=limited, force=force, include_no_version=include_no_version)
|
|
136
|
+
|
|
137
|
+
res = jsonify({
|
|
138
|
+
"status": "ok",
|
|
139
|
+
"response": stats
|
|
140
|
+
})
|
|
141
|
+
res.cache_control.max_age = 300
|
|
142
|
+
return res
|
|
143
|
+
|
|
144
|
+
@bp.route("/<string:view_id>/versions", methods=["GET"])
|
|
145
|
+
@api_login_required
|
|
146
|
+
def view_versions(view_id: str):
|
|
147
|
+
service = UserViewService()
|
|
148
|
+
res = service.get_versions_for_view(view_id)
|
|
149
|
+
return {
|
|
150
|
+
"status": "ok",
|
|
151
|
+
"response": res
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
@bp.route("/<string:view_id>/resolve", methods=["GET"])
|
|
155
|
+
@api_login_required
|
|
156
|
+
def view_resolve(view_id: str):
|
|
157
|
+
service = UserViewService()
|
|
158
|
+
res = service.resolve_view_for_edit(view_id)
|
|
159
|
+
return {
|
|
160
|
+
"status": "ok",
|
|
161
|
+
"response": res
|
|
162
|
+
}
|
|
@@ -146,6 +146,20 @@ class ArgusGroup(Model):
|
|
|
146
146
|
return super().__eq__(other)
|
|
147
147
|
|
|
148
148
|
|
|
149
|
+
class ArgusUserView(Model):
|
|
150
|
+
id = columns.UUID(primary_key=True, partition_key=True, default=uuid4)
|
|
151
|
+
name = columns.Text(required=True, index=True)
|
|
152
|
+
display_name = columns.Text()
|
|
153
|
+
description = columns.Text()
|
|
154
|
+
user_id = columns.UUID(required=True, index=True)
|
|
155
|
+
tests = columns.List(value_type=columns.UUID, default=lambda: [])
|
|
156
|
+
release_ids = columns.List(value_type=columns.UUID, default=lambda: [])
|
|
157
|
+
group_ids = columns.List(value_type=columns.UUID, default=lambda: [])
|
|
158
|
+
created = columns.DateTime(default=datetime.utcnow)
|
|
159
|
+
last_updated = columns.DateTime(default=datetime.utcnow)
|
|
160
|
+
widget_settings = columns.Text(required=True)
|
|
161
|
+
|
|
162
|
+
|
|
149
163
|
class ArgusTest(Model):
|
|
150
164
|
__table_name__ = "argus_test_v2"
|
|
151
165
|
id = columns.UUID(primary_key=True, default=uuid4)
|
|
@@ -180,6 +194,7 @@ class ArgusTestRunComment(Model):
|
|
|
180
194
|
test_run_id = columns.UUID(required=True, index=True)
|
|
181
195
|
user_id = columns.UUID(required=True, index=True)
|
|
182
196
|
release_id = columns.UUID(required=True, index=True)
|
|
197
|
+
test_id = columns.UUID(required=True, index=True)
|
|
183
198
|
posted_at = columns.Integer(
|
|
184
199
|
required=True, clustering_order="desc", primary_key=True)
|
|
185
200
|
message = columns.Text(min_length=1, max_length=65535)
|
|
@@ -350,6 +365,7 @@ USED_MODELS: list[Model] = [
|
|
|
350
365
|
Team,
|
|
351
366
|
WebFileStorage,
|
|
352
367
|
ArgusRelease,
|
|
368
|
+
ArgusUserView,
|
|
353
369
|
ArgusGroup,
|
|
354
370
|
ArgusTest,
|
|
355
371
|
ArgusTestRunComment,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from datetime import datetime
|
|
3
|
+
from math import ceil
|
|
3
4
|
from uuid import UUID
|
|
4
5
|
from time import time
|
|
5
6
|
|
|
@@ -16,8 +17,10 @@ from argus.backend.models.web import (
|
|
|
16
17
|
ArgusSchedule,
|
|
17
18
|
ArgusScheduleTest,
|
|
18
19
|
ArgusScheduleAssignee,
|
|
20
|
+
ArgusUserView,
|
|
19
21
|
User
|
|
20
22
|
)
|
|
23
|
+
from argus.backend.util.common import chunk
|
|
21
24
|
from argus.backend.util.enums import TestInvestigationStatus, TestStatus
|
|
22
25
|
|
|
23
26
|
LOGGER = logging.getLogger(__name__)
|
|
@@ -27,7 +30,7 @@ class PluginModelBase(Model):
|
|
|
27
30
|
_plugin_name = "unknown"
|
|
28
31
|
# Metadata
|
|
29
32
|
build_id = columns.Text(required=True, partition_key=True)
|
|
30
|
-
start_time = columns.DateTime(required=True, primary_key=True, clustering_order="DESC", default=datetime.
|
|
33
|
+
start_time = columns.DateTime(required=True, primary_key=True, clustering_order="DESC", default=datetime.utcnow, custom_index=True)
|
|
31
34
|
id = columns.UUID(index=True, required=True)
|
|
32
35
|
release_id = columns.UUID(index=True)
|
|
33
36
|
group_id = columns.UUID(index=True)
|
|
@@ -136,17 +139,14 @@ class PluginModelBase(Model):
|
|
|
136
139
|
cluster = ScyllaCluster.get()
|
|
137
140
|
query = cluster.prepare(cls._stats_query())
|
|
138
141
|
futures = []
|
|
139
|
-
step = 0
|
|
140
142
|
step_size = 90
|
|
141
|
-
total_tests = len(build_ids)
|
|
142
|
-
while total_tests > 0:
|
|
143
|
-
id_slice = build_ids[step:step+step_size]
|
|
144
|
-
futures.append(cluster.session.execute_async(query=query, parameters=(id_slice,)))
|
|
145
|
-
step += step_size
|
|
146
|
-
total_tests = max(0, total_tests - step_size)
|
|
147
143
|
|
|
148
|
-
|
|
144
|
+
for step in range(0, ceil(len(build_ids) / step_size)):
|
|
145
|
+
start_pos = step*step_size
|
|
146
|
+
next_slice = build_ids[start_pos:start_pos+step_size]
|
|
147
|
+
futures.append(cluster.session.execute_async(query=query, parameters=(next_slice,)))
|
|
149
148
|
|
|
149
|
+
return futures
|
|
150
150
|
@classmethod
|
|
151
151
|
def get_run_meta_by_build_id(cls, build_id: str, limit: int = 10):
|
|
152
152
|
cluster = ScyllaCluster.get()
|
|
@@ -177,6 +177,21 @@ class PluginModelBase(Model):
|
|
|
177
177
|
def get_distinct_product_versions(cls, release: ArgusRelease) -> list[str]:
|
|
178
178
|
raise NotImplementedError()
|
|
179
179
|
|
|
180
|
+
@classmethod
|
|
181
|
+
def get_distinct_versions_for_view(cls, tests: list[ArgusTest]) -> list[str]:
|
|
182
|
+
cluster = ScyllaCluster.get()
|
|
183
|
+
statement = cluster.prepare(f"SELECT scylla_version FROM {cls.table_name()} WHERE build_id IN ?")
|
|
184
|
+
futures = []
|
|
185
|
+
for batch in chunk(tests):
|
|
186
|
+
futures.append(cluster.session.execute_async(query=statement, parameters=([t.build_system_id for t in batch],)))
|
|
187
|
+
|
|
188
|
+
rows = []
|
|
189
|
+
for future in futures:
|
|
190
|
+
rows.extend(future.result())
|
|
191
|
+
unique_versions = {r["scylla_version"] for r in rows if r["scylla_version"]}
|
|
192
|
+
|
|
193
|
+
return sorted(list(unique_versions), reverse=True)
|
|
194
|
+
|
|
180
195
|
def update_heartbeat(self):
|
|
181
196
|
self.heartbeat = int(time())
|
|
182
197
|
|
|
@@ -189,7 +204,7 @@ class PluginModelBase(Model):
|
|
|
189
204
|
def submit_product_version(self, version: str):
|
|
190
205
|
raise NotImplementedError()
|
|
191
206
|
|
|
192
|
-
def
|
|
207
|
+
def set_full_version(self, version: str):
|
|
193
208
|
self.product_version = version
|
|
194
209
|
|
|
195
210
|
def submit_logs(self, logs: list[dict]):
|