Веб-сервис предназначен для создания лабораторных работ с автоматической проверкой решений учащихся на базе системы контроля версий Gitlab с использованием технологии CI/CD.
Для нормального функционирования веб-сервис необходим компьютер под управлением операционной системы семейства Unix на базе ядра Linux. Конструктор грейдеров написан на языке программирования Python версии 3.6. Программный интерфейс приложенния реализован при помощи асинхронного веб-фреймворка FastAPI с поддержкой Swagger UI, инструмента для автоматического документирования с возможностью взаимодействия с сервисом через веб-интерфейс. Для хранения данных используется СУБД PostgreSQL. Структура базы данных конструктора грейдеров приведена на рисунке ниже.
С целью оптимизации веб-сервиса осуществляется балансировка нагрузки при помощи NGINX. Для мониторинга и сбора статистики используются Grafana и Prometheus. Схема на рисунке ниже описывает связь всех компонентов системы, а также роль преподавателя и студентов в ней.
Для успешного запуска необходимо:
1. Склонировать репозиторий GitLab
2. Установить все зависимости (pip install -r requirements.txt
)
3. Установить и настроить СУБД PostgreSQL
4. Настроить параметры в файле конфигурации
5. Перейти в директорию graders_api (cd graders_api
)
Запуск веб-сервиса осуществляется при помощи команды python main.py
Еще одним вариантом запуска является сборка образа контейнера с помощью Dockerfile, расположеного в корне репозитория.
При реализации варианта эксплуатации с балансировкой нагрузки требуется изменить конфигурационный файл NGINX и разместить экземляры приложения на разных портах, указав в файле upstream с нужными портами.
...
upstream backend {
server localhost:8080;
server localhost:8081;
}
...
Для авторизации используется header "Authorization".
* в наименовании обозначает обязательный параметр.
Данные в примерах изменены!
Программный интерфейс конструктора грейдеров логически разделен на 3 группы обработчиков запросов: создание заданий, оценивание решений, взаимодействие с базой данных.
Требует авторизации!
Метод создания грейдера: генерируются ключи для привязки задания к LMS и создается группа задания в GitLab.
Наименование | Описание | Значение по умолчанию |
---|---|---|
string teacher_email * |
Email адрес учителя, далее может обозначаться как владелец курса | Не задано |
integer course_id * |
Идентификатор курса | Не задано |
string name * |
Название задания | Не задано |
string description * |
Описание, которое добавится в репозитории студентов в GitLab | Не задано |
string technology * |
Технология, для которой создается грейдер | Не задано |
string solution_filename * |
Название файла с решением в GitLab | Не задано |
|*string* `grader_id`| Идентификатор создаваемого грейдера | uuid4 (hex) |
|string mode
| Режим работы грейдера (train
- без ограничения попыток, exam
- с ограничением) | train |
|integer attempts
| Количество попыток для сдачи | 100 |
|datetime deadline
| Дедлайн задания | 2 недели от текущей даты |
{
"message": "Grader created",
"grader_id": "ea92reg14ab7424f9f34fef380h3e3b9",
"consumer_key": "vbjvlghMQE32n3f0ods3RPEd2sTJfx",
"shared_secret": "eTr2vghf34fef380hf0ods3RPEd3e3"
}
Task with this grader_id already exists
Incorrect Bearer
Validation Error
Требует авторизации!
Метод принимает файлы, генерирует Docker image и конфигурационный файл CI, загружает их в GitLab.
Наименование | Описание |
---|---|
integer grader_id * |
Идентификатор грейдера |
List[File] files * |
Список необходимых файлов |
{
"message": "OK"
}
Incorrect Bearer
Validation Error
Метод перенаправляет студента из LMS в репозиторий GitLab. Если студент переходит впервые, для него создается личный репозиторий внутри группы задания со всеми необходимыми настройками и переменными окружения. В случае, когда переходит преподаватель, перенаправление происходит в группу задания со всеми репозиториями студентов.
Наименование | Описание |
---|---|
integer assignment_id * |
Идентификатор группы задания в GitLab |
Form user_data * |
Закодированные данные о пользователе, осуществляющем переход |
{
RedirectResponse
}
Task not found!
Validation Error
Требует авторизации!
Метод для обновления оценки за тест и пересчета суммарной оценки за задание.
Наименование | Описание |
---|---|
integer task_id * |
Идентификатор задания |
string student_email * |
Почта студента |
integer grade * |
Оценка за тест |
integer test_num * |
Номер теста (если указывается -1 , оценки за тесты обнуляются) |
{
"message": "Grade update"
}
Incorrect Bearer
Validation Error
Требует авторизации!
Метод для выставления оценки в LMS с использованием сервиса GC Bridge. На данном этапе также создается запись в таблицу базы данных о попытке студента решить задание.
Наименование | Описание |
---|---|
integer task_id * |
Идентификатор задания |
string student_email * |
Почта студента |
integer test_num * |
Номер теста (если указывается не последний, оценка не выставляется) |
{
"message": "Skipping LTI"
}
{
"message": "Graded LTI"
}
Incorrect Bearer
Validation Error
Требует авторизации!
Метод для создания новой записи о курсе в базе данных.
Наименование | Описание |
---|---|
string name * |
Название курса |
{
"id": 1,
"name": "Пример курса"
}
Incorrect Bearer
Validation Error
Требует авторизации!
Метод для получения записей о курсах из базы данных.
None
[
{
"id": 1,
"name": "Пример курса"
},
{
"id": 2,
"name": "Проект 589"
}
]
Incorrect Bearer
Требует авторизации!
Метод для создания новой записи о преподавателе в базе данных.
Наименование | Описание |
---|---|
string email * |
Почта преподавателя |
List[integer] tasks |
Список идентификаторов заданий |
{
"id": 1,
"email": "teacher@miem.hse.ru"
}
Incorrect Bearer
Validation Error
Требует авторизации!
Метод для создания новой записи о студенте в базе данных.
Наименование | Описание |
---|---|
string email * |
Почта студента |
string name * |
ФИО студента |
{
"id": 1,
"email": "student@miem.hse.ru",
"name": "Илья Николаевич Осипов"
}
Incorrect Bearer
Validation Error
Требует авторизации!
Метод для получения записей о заданиях указанного преподавателя из базы данных.
Наименование | Описание |
---|---|
string owner_email |
Почта преподавателя (если указано all - выводит полный список заданий) |
[
{
"name": "task-1",
"tests_number": 3,
"course_id": 1,
"description": "Подробные инструкции по выполнению смотрите в SmartLMS",
"max_grade": 10,
"technology": "ffmpeg",
"mode": "train",
"external_id": "322",
"start": "2022-01-11T15:28:08.713088",
"git_id": 6677,
"deadline": "2022-01-25T15:28:08.713100",
"git_path": "test-589.task-1",
"attempts": 100,
"grader_id": "9149fc1aeee3b92a91aff380dcb74249",
"solution_filename": "solution.py",
"id": 1,
"gitlab_ci_filename": "grader_ffmpeg_9149fc1aeee3b92a91aff380dcb74249"
}
]
Incorrect Bearer
Owner not found
Validation Error
Требует авторизации!
Метод для получения записей о заданиях по указанному курсу из базы данных.
Наименование | Описание |
---|---|
string course_id |
Идентификатор курса |
[
{
"name": "task-1",
"tests_number": 3,
"course_id": 1,
"description": "Подробные инструкции по выполнению смотрите в SmartLMS",
"max_grade": 10,
"technology": "ffmpeg",
"mode": "train",
"external_id": "322",
"start": "2022-01-11T15:28:08.713088",
"git_id": 6677,
"deadline": "2022-01-25T15:28:08.713100",
"git_path": "test-589.task-1",
"attempts": 100,
"grader_id": "9149fc1aeee3b92a91aff380dcb74249",
"solution_filename": "solution.py",
"id": 1,
"gitlab_ci_filename": "grader_ffmpeg_9149fc1aeee3b92a91aff380dcb74249"
}
]
Incorrect Bearer
Validation Error
Требует авторизации!
Метод для создания новой записи о задании в базе данных.
Наименование | Описание | Значение по умолчанию |
---|---|---|
integer course_id * |
Идентификатор курса | Не задано |
string name * |
Название задания | Не задано |
string description * |
Описание, которое добавится в репозитории студентов в GitLab | Не задано |
string technology * |
Технология, для которой создается грейдер | Не задано |
string solution_filename * |
Название файла с решением в GitLab | Не задано |
|*string* `grader_id`| Идентификатор создаваемого грейдера | uuid4 (hex) |
|string mode
| Режим работы грейдера (train
- без ограничения попыток, exam
- с ограничением) | train |
|integer attempts
| Количество попыток для сдачи | 100 |
|datetime deadline
| Дедлайн задания | 2 недели от текущей даты |
{
"name": "task-1",
"tests_number": 3,
"course_id": 1,
"description": "Подробные инструкции по выполнению смотрите в SmartLMS",
"max_grade": 10,
"technology": "ffmpeg",
"mode": "train",
"external_id": "322",
"start": "2022-01-11T15:28:08.713088",
"git_id": 6677,
"deadline": "2022-01-25T15:28:08.713100",
"git_path": "test-589.task-1",
"attempts": 100,
"grader_id": "9149fc1aeee3b92a91aff380dcb74249",
"solution_filename": "solution.py",
"id": 1,
"gitlab_ci_filename": "grader_ffmpeg_9149fc1aeee3b92a91aff380dcb74249"
}
Incorrect Bearer
Validation Error
Шаблоны представляют собой набор проверок, необходимых для определения правильности выполнения студентом одного конкретного пункта задания. Для каждого шаблона подготавливаются непосредственно сам шаблон в формате .py.j2
и функция prepare_input
, которая обрабатывает входной и выходной файл. Входной файл представляет собой непосредственно результат, полученный студентом, например, видео. Выходной файл в таком случае может быть эталонным видео или, например, json-файлом с проверяемыми параметрами.
Шаблоны разделены по технологиям, с которыми они используются: FFmpeg, ImageMagick, Onvif, Python, Gstreamer. Спосок технологий может пополняться.
Технология для проверки работы студента с изображениями.
Данный шаблон используется для поиска различий между 2 изображениями(входной и выходной файлы). Если различий нет, то проверка пройдена.
Технология для проверки работы студента с видео.
Данный шаблон предназначен для проверки битрейта полученного студентом видео. В качестве параметров для проверки можно передать целый список возможных кодеков и значений для них: правильным будет считаться ответ студента, который будет соответствовать хотя бы одному из них. Может применяться для проверки битрейта видео и аудио.
[
{
"param": "-b:v" или "-b:a"(видео и аудио соответственно),
"codec_name": "name" (например "h264"),
"bit_rate": 0
},
{
...
}
]
[
{
"param": "-b:v",
"codec_name": "h264",
"bit_rate": 1500000
},
{
"param": "-b:v",
"codec_name": "mpeg4",
"bit_rate": 2500000
}
]
Данный шаблон предназначен для проверки правильности формата входного файла.
['format1', 'format2', ...]
["mp4", "mov", "m4v"]
Данный шаблон используется для проверки правильности хеша видео, полученного средствами FFmpeg.
Данный шаблон используется для проверки правильности полученного студентом видео, путем сравнения необходимого параметра с соответствующим ему параметром эталонного видео.
Аналог предыдущего шаблона, но сравнивает параметры не с соответстующими параметрами в эталонном видео, а с заданными в выходном json-файле.
[
{
"name": "param_name" (например "sample_rate"),
"value": "value" (например 48000),
"stream": 0 (0 для аудио, 1 для видео)
},
{
...
}
]
[
{
"name": "sample_rate",
"value": "48000",
"stream": 1
}
]
И вновь аналог шаблона param, с тем отличием, что параметры результата студента сравниваются с изначальным видео, до обработки. То есть эти параметры не должны были измениться(например, форма пикселя изображения).
[
{
"name": "param_name" (например "sample_aspect_ratio"),
"stream": 0 (0 для аудио, 1 для видео)
},
{
...
}
]
[
{
"name": "sample_aspect_ratio",
"stream": 0
}
]
Данный шаблон предназначен для определения правильности расположения видео или других прямоугольных элементов при компоновке.
Для правильного функционирования данного шаблона, изображение, которое студенты используют в качетсве фона, в контейнере должно заменяться на полностью красное изображение, а в видео, использующихся в компоновке, не должно быть ярко-красных мест по краям.
[
{
"borders": [..., ..., ..., ...], (список из 4 чисел - координаты левого верхнего угла и правого нижнего)
"frame": 10 (номер фрейма, на котором нужное изображение находится в нужных границах),
},
{
...
}
]
[
{
"borders": [10, 274, 953, 805],
"frame": 10
},
{
"borders": [966, 274, 1909, 805],
"frame": 10
}
]
Данный шаблон предназначен для проверки правильности наложения текста на видео.
[
{
"borders": [..., ..., ..., ...], (список из 4 чисел - координаты левого верхнего угла и правого нижнегоплашки с текстом)
"text": "some_text", (текст, который должен быть в данных границах(с запасом, лучше распологать на одноцветной плашке))
"frame": 10 (номер фрейма, на котором нужное изображение находится в нужных границах),
},
{
...
}
]
[
{
"borders": [1774, 1004, 1899, 1029],
"text": "MIEM HSE",
"frame": 100
}
]
Данный шаблон предназначен для проверки синхронизации видеопотоков при компановке.
[
[x1.1, y1.1, x2.1, y2.1], - координаты первого видео в компоновке
[x1.2, y1.2, x2.2, y2.2] - координаты второго видео в компоновке
]
[
[10, 274, 953, 805],
[966, 274, 1909, 805]
]
Данная технология предназначена для проверки умения студентов работать с onvif. Во всех шаблонах, описаных далее, используется лабораторный стенд с камерой, экраном, лампочками и т.д. Подготовка лабораторных работ по onvif предполагает также некоторую подготовку лабораторного стенда.
Шаблон для определения правильности положения камеры.
{
'x': 0, - координата сответствующая Position.PanTilt.x камеры
'y': 0, - координата сответствующая Position.PanTilt.y камеры
'zoom': 0 - координата сответствующая Position.Zoom.x камеры
}
{
'x': 0,
'y': 0,
'zoom': 0
}
Данный шаблон предназначен для проверки задания по настройке imaging камеры. Перед камерой должен находится экран, на котором должно быть изображение color bars
.
{
"color_bars": [[255, 255, 0], [0, 255, 255], [0, 255, 0], [255, 0, 255], [255, 0, 0]], - цвета "полосок" на экране камеры
"size_x": 250, - ширина вырезаемого из изображения одноцветного прямоугольника для проверки(часть полоски)
"size_y": 250, - высота вырезаемого из изображения одноцветного прямоугольника для проверки(часть полоски)
"start_x": 100, - координата x начала первого вырезаемого прямоугольника(первой полоски)
"step_x": 350, - шаг по x, с которым вырезаются прямоугольники для проверки
"height": 400, - координата y прямоугольников
"max_error": 25 - максимально-возможная ошибка в цвете
}
{
'color_bars': [[255, 255, 255], [255, 255, 0],
[0, 255, 255], [0, 255, 0], [255, 0, 255],
[255, 0, 0], [0, 0, 255], [0, 0, 0]],
'size_x': 1,
'size_y': 1,
'start_x': 256,
'step_x': 185,
'height': 500,
'max_error': 25
}
Данный шаблон предназначен для проверки параметра brightness imaging камеры.
value
' brightness 0
brightness 100
Данный шаблон предназначен для проверки параметра contrast imaging камеры.
value
' contrast 0
contrast 100
Довольно специфичный шаблон для одной из проведенных лабораторных. В момент, когда на камере активируется выход alarm_out, начинает проверку положения камеры(с определенным допуском), которая должна быть наведена на один из зажегшихся светодиодов.
{
'color1': {
'p': 1, координата сответствующая Position.PanTilt.x камеры
't': 1, координата сответствующая Position.PanTilt.y камеры
'z': 0 координата сответствующая Position.Zoom.x камеры
},
'color2': {
'p': -0.657167,
't': -0.632667,
'z': 0.333333
},
...
}
{
'green': {
'p': 1,
't': 1,
'z': 0
},
'red': {
'p': -0.657167,
't': -0.632667,
'z': 0.333333
},
...
}
Технология, предназначенная для проверки умения студентов работать с фреймворкой GStreamer.
Данный шаблон предназначен для проверки правильности ответа студента. У этого шаблона нет входных и выходных файлов и, соответственно, каких-либо параметров. Он проверяет, что в файле, сданном студентом ровно одна строка с командой gstreamer без точек с запятой.
Данный шаблон проверяет правильность формирования пайплайна студента, запуская его и дожидаясь окончания выполнения. В случае, если в процессе работы пайплайна произошла ошибка, выводится соответствующее сообщение.
{
'EXECUTE_ENDED_STR': 'str', - строка, означающая ожидаемый конец выполнения пайплайна
'ERROR_STR': 'str' - строка, выводимая в случае ошибки
}
{
'EXECUTE_ENDED_STR': 'Execution ended after 0:04:',
'ERROR_STR': 'Audio not played'
}
Шаблон, предназначенный для проверки отсутствия в коде студента запрещенных элементов.
['element_1', 'element_2', 'element_3', ...]
['playbin', 'uridecodebin', 'decodebin', 'autoaudiosink']
Шаблоны для работы с CI/CD платформой GitLab.
Шаблон первой джобы со скриптами подготовки к тестам.
PREPARATION_TEMPLATE = {
"stage": "preparation",
"tags": ["{{tag}}"],
"script": [],
}
PREPARATION_TEMPLATE = {
"stage": "preparation",
"tags": ["docker_cache_3"],
"script": [
'main_path="$(pwd)"',
"cd /grade",
"python3 /grade/preparation.py",],
}
Пример шаблона джобы с тестом.
TEST_TEMPLATE = {
"stage": "-",
"tags": ["{tag}"],
"needs": ["preparation"],
"script": [],
"artifacts": {"reports": {"junit": "report.xml"}},
}
TEST_TEMPLATE = {
"stage": "-",
"tags": ["docker_cache_3"],
"needs": ["preparation"],
"script": [
'main_path="$(pwd)"',
"ls",
"cp -r ./ /grade",
"cd /grade",
"pytest /grade/{0}/test_{1}.py --tb=line -rNv --junitxml=${{main_path}}/report.xml -o junit_family=legacy",
],
"artifacts": {"reports": {"junit": "report.xml"}},
}
Пример шаблона финальной джобы с, например, выставлением оценки.
FINAL_TEMPLATE = {
"stage": "final",
"tags": ["{tag}"],
"script": [],
"artifacts": {"reports": {"junit": "report.xml"}},
"when": "",
}
FINAL_TEMPLATE = {
"stage": "final",
"tags": ["docker_cache_3"],
"script": [
'main_path="$(pwd)"',
"cd /grade",
"python3 /grade/set_mark.py",
],
"artifacts": {"reports": {"junit": "report.xml"}},
"when": "always",
}
Для работы мониторинга используется Prometheus, для логирования используется Promtail, который читает логи и отправляет в агент Loki, который их преобразует. Для визуализации, составления графиков и дэшбордов используется Grafana.
Мониторинг предназначен для сбора статистики, просмотра ошибок, выявления проблем системы.
Подключение к Grafana происходит из веб-браузера, далее требуется пройти авторизацию или задать первоначальный пароль.
Далее:
1. Зайти во вкладку Dashboards.
2. Выбрать доступный дэшборд.
3. Перейти в edit и настроить запрос к метрикам вместе с графиком.
Логи позволяют прочитать ошибки системы с трейсингом.
Далее:
Резервное копирование поволяет восстановить данные в случае остановки и утери данных с базы Postgresql.
PGPASSWORD=$pg_password pg_dump -U $db_user -h localhost $db_name > $sqlfile