Конфигурация и система
Чтение и запись hastreamer.conf через API, проверка и откат, сертификаты, хранилища, ресурсы хоста, лицензия, журналы и аудит.
Конфигурация сервера — единственный источник истины: панель, API и файл hastreamer.conf правят одно
и то же. API даёт три способа изменить её, от самого грубого к самому точному:
| Способ | Маршрут | Когда применять |
|---|---|---|
| Записать файл целиком | PUT /config |
развёртывание из системы управления конфигурацией |
| Изменить глобальные директивы | PATCH /config/globals |
сменить порт, уровень журнала, переписать блок auth |
| Изменить один поток | PATCH /streams/{id} |
всё, что касается одного потока — см. Потоки |
Общие правила (BASE, TOKEN, форма ошибок, бейджи прав) — на странице
Введение и аутентификация.
Версии, хеш и защита от гонки#
Каждая записанная конфигурация получает номер версии epoch и хеш содержимого hash. Значение
epoch никогда не уменьшается: даже откат добавляет новую версию.
Хеш — это токен сравнения-и-замены. Передавайте его в поле base.hash при записи: если конфигурацию
изменил кто-то другой между вашим чтением и записью, сервер ответит 409 с актуальными epoch и
hash, а не затрёт чужую правку молча.
GET /config → hash=4a186afe…
← кто-то другой применил свою правку, hash стал 9f2c11a7…
PUT /config {text, base:{hash:"4a186afe…"}} → 409 config conflict, epoch=13, hash=9f2c11a7…
Правильная реакция на 409 — перечитать конфигурацию, наложить свою правку заново и повторить запрос.
Конфигурация#
GET /api/v1/config#
Запись — только сессия администратора или api_write_token.
Возвращает файл конфигурации дословно, его разобранную модель, текущие epoch и hash, сведения о
сборке и до 32 последних звеньев журнала версий.
Ответ содержит секреты в открытом виде: URL источников с паролями камер, ключи S3,
auth.admin_password, оба статических токена. Поэтому api_read_token получает здесь
403 {"error":"forbidden","reason":"read_token_cannot_read_config"} — иначе токен уровня чтения
одним запросом вышел бы за границы своего уровня.
Внешней панели, которой нужен только порог журналирования и хеш, отдавайте узкую проекцию
GET /config/logging.
curl -sS "$BASE/api/v1/config" -H "Authorization: Bearer $TOKEN"
{"epoch":10,"hash":"4a186afe976f6ef3","shared_hash":"85851d2f59d9e592", "version":"2026.8.0", "build":{"profile":"release","target":"x86_64-unknown-linux-gnu","features":["full"]}, "text":"http 8080;\nhttps 443;\n\nauth {\n admin_password \"…\";\n}\n\nstream cam1 {\n input rtsp://…;\n dvr local 6h 20G;\n}\n", "parsed":{"http_port":8080,"https_port":443,"cores":4,"log_level":"info","max_sessions":0}, "chain":[{"epoch":10,"hash":"4a186afe976f6ef3","shared_hash":"85851d2f59d9e592"}], "locked":false}
Ошибки
| Код | Тело | Когда |
|---|---|---|
403 |
{"error":"forbidden","reason":"read_token_cannot_read_config"} |
предъявлен токен чтения |
501 |
{"title":"config mutation unavailable (no config file)"} |
сервер запущен без файла конфигурации |
GET /api/v1/config/logging#
Чтение
Намеренно узкая проекция для внешних панелей: порог журналирования, хеш конфигурации и флаг заморозки. Никогда не отдаёт ни текст конфигурации, ни разобранную модель, ни секреты.
curl -sS "$BASE/api/v1/config/logging" -H "Authorization: Bearer $TOKEN"
{"configured_level":"info","hash":"4a186afe976f6ef3","locked":false}
GET /api/v1/config/streams#
Чтение
Голый массив — не конверт items. Все потоки из конфигурации, включая выключенные, которых
нет в рантайм-списке GET /streams. Именно отсюда берётся ответ на
вопрос «какие потоки настроены, но не работают».
curl -sS "$BASE/api/v1/config/streams" -H "Authorization: Bearer $TOKEN"
[{"path":"cam1","disabled":false,"record":true,"labels":[],"retention":"6h · 20G"}, {"path":"live/cam2","disabled":true,"record":false,"labels":["lobby"],"retention":""}]
GET /api/v1/config/history#
Чтение
Только дополняемый журнал версий, голый массив, от старых записей к новым.
curl -sS "$BASE/api/v1/config/history" -H "Authorization: Bearer $TOKEN"
[{"epoch":1,"hash":"d9b4d2d2a819ff24","shared_hash":"85851d2f59d9e592", "ts_ms":1786787600937,"actor":"system","via":"boot"}, {"epoch":2,"hash":"7c3e15b09ad2f846","shared_hash":"85851d2f59d9e592", "ts_ms":1786787630567,"actor":"admin","via":"api"}]
Поле via называет источник правки: boot (разбор файла при старте), api, cert-acme,
cert-delete и так далее. Поле actor — system или имя исполнителя.
GET /api/v1/config/schema#
Чтение
Статический реестр редактируемых глобальных настроек: имя поля, соответствующая директива, тип, значение по умолчанию, класс применения и подсказка. Из него панель строит форму конфигурации. Чистое чтение, не зависящее от состояния узла.
curl -sS "$BASE/api/v1/config/schema" -H "Authorization: Bearer $TOKEN"
{"fields":[{"field":"http_port","directive":"http","ty":"port","default":8080, "blast":"restart","group":"listeners","doc":"HLS / API / player HTTP port."}, {"field":"log_level","directive":"log_level","ty":"enum","default":"info", "blast":"hot","group":"tuning","doc":"Minimum severity captured."}]}
Поле blast — тот самый класс применения: hot действует сразу, restart требует перезапуска
службы. См. Применение изменений.
POST /api/v1/config/validate#
Запись
Классифицирует кандидата: разбирается ли он и что придётся перезапустить при применении. Ничего не пишет — это безопасная операция, её можно вызывать сколько угодно.
Тело запроса
| Поле | Тип | Обязательно | Смысл |
|---|---|---|---|
text |
строка | да | полный текст конфигурации-кандидата |
curl -sS -X POST "$BASE/api/v1/config/validate" \ -H "Authorization: Bearer $TOKEN" \ -H 'Content-Type: application/json' \ -d '{"text":"http 8080;\n\nstream cam1 {\n input rtsp://10.0.0.10:554/stream1;\n}\n"}'
{"ok":true, "classification":{"respawn":["cam1"],"added":["live/cam2"],"removed":[], "restart_required":["http_port 8080 → 8090"],"untouched":12}}
Смотрите на поле ok, а не на код ответа. Ошибочный кандидат выглядит так:
{"ok":false,"errors":"unknown directive \"sourse\" in stream \"cam1\""}
PUT /api/v1/config#
Запись
Записывает переданный текст как новую версию конфигурации. Перед записью текст разбирается и проверяется целиком; при ошибке на диск ничего не попадает.
Тело запроса
| Поле | Тип | Обязательно | Смысл |
|---|---|---|---|
text |
строка | да | полный текст новой конфигурации |
base.hash |
строка | нет, но настоятельно рекомендуется | хеш из последнего GET /config |
curl -sS -X PUT "$BASE/api/v1/config" \ -H "Authorization: Bearer $TOKEN" \ -H 'Content-Type: application/json' \ -d '{"text":"http 8080;\n\nstream cam1 {\n input rtsp://10.0.0.10:554/stream1;\n dvr local 6h 20G;\n}\n", "base":{"hash":"4a186afe976f6ef3"}}'
{"epoch":11,"hash":"9f2c11a70bd4e650","changed":true}
Ошибки
| Код | Тело | Когда |
|---|---|---|
400 |
{"title":"bad request","detail":"need \"text\""} |
в теле нет ключа text |
403 |
{"error":"forbidden","reason":"read_token_cannot_write"} |
предъявлен токен чтения |
409 |
{"title":"config conflict","detail":"the config changed under you — rebase and retry","epoch":13,"hash":"9f2c11a7…"} |
base.hash не совпал с текущим |
413 |
— | тело больше 1 МиБ |
422 |
{"title":"invalid config","detail":"…"} |
текст не разбирается |
423 |
{"title":"config locked"} |
существует файл <config>.locked |
501 |
{"title":"config mutation unavailable (no config file)"} |
сервер запущен без файла конфигурации |
PUT /config заменяет файл целикомВсё, чего нет в переданном text, будет удалено: потоки, хранилища, блок auth. Безопасная
последовательность — GET /config → правка поля text → POST /config/validate → PUT /config
с тем же base.hash.
PATCH /api/v1/config/globals#
Запись
Структурная правка верхнего уровня конфигурации — всего, кроме блоков stream. Операции применяются
строго в порядке set → blocks → unset, после чего результат проходит тот же путь, что и запись
целиком: сравнение-и-замена, журнал версий, классификация, аудит.
Тело запроса
| Поле | Тип | Смысл |
|---|---|---|
base.hash |
строка | хеш из последнего GET /config (защита от гонки) |
set |
объект директива → значение |
задать или изменить одиночные директивы |
blocks |
объект имя блока → тело |
переписать блок целиком (auth, vod, cluster, …) |
unset |
массив имён директив | удалить директивы |
# Сменить порог журналирования и убрать RTMP-слушатель curl -sS -X PATCH "$BASE/api/v1/config/globals" \ -H "Authorization: Bearer $TOKEN" \ -H 'Content-Type: application/json' \ -d '{"base":{"hash":"4a186afe976f6ef3"}, "set":{"log_level":"debug"}, "unset":["rtmp"]}'
{"epoch":12,"hash":"a41c9b2ee5f70d18","changed":true}
# Переписать блок auth целиком — так меняется пароль администратора curl -sS -X PATCH "$BASE/api/v1/config/globals" \ -H "Authorization: Bearer $TOKEN" \ -H 'Content-Type: application/json' \ -d '{"base":{"hash":"a41c9b2ee5f70d18"}, "blocks":{"auth":"admin_password \"новый-пароль\";\nadmin_ip_bind on;"}}'
blocks заменяет тело блока полностью. Если в примере выше не указать api_read_token, он будет
удалён из конфигурации. Прочитайте текущий блок в GET /config → text прежде, чем переписывать.
Ошибки
| Код | Когда |
|---|---|
400 |
тело не является объектом JSON |
403 |
предъявлен токен чтения |
409 |
base.hash не совпал с текущим |
413 |
тело больше 1 МиБ |
422 |
правку невозможно наложить (bad edit) либо результат не разбирается (invalid config) |
423 |
конфигурация заморожена |
501 |
сервер запущен без файла конфигурации |
POST /api/v1/config/rollback#
Запись
Применяет байты указанной версии заново — как новую версию. Журнал только дополняется.
Тело запроса
| Поле | Тип | Обязательно | Смысл |
|---|---|---|---|
epoch |
целое | да | номер версии из GET /config/history |
curl -sS -X POST "$BASE/api/v1/config/rollback" \ -H "Authorization: Bearer $TOKEN" \ -H 'Content-Type: application/json' \ -d '{"epoch":2}'
{"epoch":13,"hash":"7c3e15b09ad2f846","changed":true,"rolled_from":2}
Обратите внимание: epoch в ответе — новый (13), а hash совпадает с версией 2. Откат не
уменьшает номер версии, а добавляет её копию в конец журнала, поэтому откат отката тоже возможен.
Ошибки
| Код | Тело | Когда |
|---|---|---|
400 |
{"title":"bad request"} |
в теле нет ключа epoch |
403 |
— | предъявлен токен чтения |
404 |
{"title":"version not found","detail":"epoch 99: not in the journal"} |
такой версии в журнале нет |
422 |
— | байты версии больше не разбираются |
423 |
— | конфигурация заморожена |
501 |
— | сервер запущен без файла конфигурации |
Сертификаты#
Записи хранилища SNI плюс сертификат по умолчанию. Данные узло-локальные: поля читаются из сохранённого файла, а не из конфигурации, поэтому показывают то, что сервер реально предъявит.
GET /api/v1/certs#
Чтение
curl -sS "$BASE/api/v1/certs" -H "Authorization: Bearer $TOKEN"
{"certificates":[ {"name":"media.example.com","mode":"acme","hosts":["media.example.com"], "fingerprint":"5b7e2a09c4d16f83…", "certificate":{"subject":"CN=media.example.com","issuer":"…", "not_before":1786792102,"not_after":1794568101, "days_left":85,"renew_after":1791976101}, "acme":{"status":"ok","issued":1786795603,"checked":1786795603, "days_left":85,"fails":0,"error":"","scan_interval_secs":60}}], "default":{"cert":"","certificate":{"subject":"CN=localhost","days_left":755821}}}
POST /api/v1/certs/{name}#
Запись
Две взаимоисключающие формы тела: загрузка готового PEM либо заказ автовыпуска ACME.
Параметры пути
| Параметр | Тип и допустимые значения | Смысл |
|---|---|---|
name |
[A-Za-z0-9._-]+, без . и .., литеральный / отвергается |
имя записи в хранилище SNI |
Тело запроса — загрузка PEM
| Поле | Тип | Обязательно | Смысл |
|---|---|---|---|
hosts |
массив строк | да | имена, для которых предъявляется сертификат |
cert |
строка PEM | да | лист |
key |
строка PEM | да | закрытый ключ |
ca |
строка PEM | нет | промежуточные сертификаты |
curl -sS -X POST "$BASE/api/v1/certs/media.example.com" \ -H "Authorization: Bearer $TOKEN" \ -H 'Content-Type: application/json' \ -d "$(python3 - <<'PY' import json print(json.dumps({ "hosts": ["media.example.com"], "cert": open("/etc/ssl/media.example.com/fullchain.pem").read(), "key": open("/etc/ssl/media.example.com/privkey.pem").read(), })) PY )"
Тело запроса — автовыпуск ACME
| Поле | Тип | Обязательно | Смысл |
|---|---|---|---|
acme |
true |
да | режим автовыпуска |
hosts |
массив строк | да | только конкретные имена |
curl -sS -X POST "$BASE/api/v1/certs/media.example.com" \ -H "Authorization: Bearer $TOKEN" \ -H 'Content-Type: application/json' \ -d '{"acme":true,"hosts":["media.example.com"]}'
{"name":"media.example.com","hosts":["media.example.com"],"mode":"acme","changed":true}
Примечания. Пара «лист + ключ» проверяется на соответствие до того, как что-либо будет
сохранено; файлы кладутся с правами 0600 через временный файл и атомарное переименование, после чего
TLS подхватывает их без перезапуска. Ответ на заказ ACME подтверждает только регистрацию: сам
выпуск асинхронный, следите за полем acme.status в списке.
Ошибки
| Код | Тело | Когда |
|---|---|---|
403 |
— | предъявлен токен чтения |
413 |
— | тело больше 1 МиБ |
422 |
{"title":"invalid certificate","detail":"ACME/HTTP-01 cannot issue the wildcard \"*.example.com\" — give a concrete hostname"} |
неверное имя, нет ни одного хоста, нет cert/key, лист и ключ не пара, для ACME запрошено подстановочное имя |
423 |
— | конфигурация заморожена |
DELETE /api/v1/certs/{name}#
Запись
Убирает запись из хранилища SNI и обновляет TLS без перезапуска.
curl -sS -X DELETE "$BASE/api/v1/certs/media.example.com" \ -H "Authorization: Bearer $TOKEN"
{"name":"media.example.com","deleted":true,"changed":true}
Хранилища#
Хранилище — том для записи архива: локальный каталог или ярус S3. Управление хранилищами всегда узло-локально. Подробнее о смысле параметров — Хранилища и S3.
GET /api/v1/storages#
Чтение
Голый массив состояния всех хранилищ узла.
curl -sS "$BASE/api/v1/storages" -H "Authorization: Bearer $TOKEN"
[{"name":"local","path":"/var/lib/hastreamer/dvr", "identity":"","identity_healthy":true,"maintenance_healthy":true, "total_bytes":84444717056,"used_bytes":31312314368,"avail_bytes":53132402688, "evict_at_percent":90,"reclaimed_files":0,"reclaimed_bytes":0, "streams":[["cam1",21,21012998324],["cam2",8,1843442769]], "read_iops":0,"write_iops":5,"read_bps":0,"write_bps":1497217, "used_growth_bps":-380330,"fill_eta_secs":null, "s3_healthy":true,"s3_errors":0,"cold_bytes":0,"tiered_bytes":0}]
Элементы массива streams — тройки [идентификатор потока, число сегментов, занято байт].
Тело публикуется проходом обслуживания архива раз в dvr_cleanup_secs (по умолчанию 600 с); поверх
него в момент запроса накладываются живые счётчики S3. Не опрашивайте этот маршрут чаще, чем раз в
несколько секунд, — новых данных всё равно не будет.
GET /api/v1/storages/{name}/config#
Чтение
Разобранная модель одного хранилища — то, что нужно для предзаполнения формы правки.
curl -sS "$BASE/api/v1/storages/local/config" -H "Authorization: Bearer $TOKEN"
{"name":"local", "config":{"name":"local","path":"/var/lib/hastreamer/dvr","identity":"", "segment_secs":900,"evict_at_percent":90,"s3":null}}
Для ярусов S3 поле secret_key приходит незашифрованным — осознанно: замена блока целиком обязана
его вернуть. Не проксируйте этот ответ потребителю с меньшими правами.
Ошибки
| Код | Тело | Когда |
|---|---|---|
404 |
{"title":"not found","detail":"no storage \"cold\""} |
хранилища с таким именем нет в конфигурации |
POST /api/v1/storages#
Запись
Добавляет блок storage и применяет конфигурацию. Успех — 201.
Тело запроса
| Поле | Тип | Обязательно | Смысл |
|---|---|---|---|
name |
строка [A-Za-z0-9._-]+ |
да | имя хранилища |
arg2 |
строка | да | путь к каталогу либо литерал s3 |
directives |
строка | нет | тело блока: evict_at, параметры S3 и прочее |
# Локальный диск curl -sS -X POST "$BASE/api/v1/storages" \ -H "Authorization: Bearer $TOKEN" \ -H 'Content-Type: application/json' \ -d '{"name":"dvr2","arg2":"/srv/dvr2","directives":"evict_at 85;"}'
# Холодный ярус S3 curl -sS -X POST "$BASE/api/v1/storages" \ -H "Authorization: Bearer $TOKEN" \ -H 'Content-Type: application/json' \ -d '{"name":"cold","arg2":"s3", "directives":"endpoint s3.example.com;\nbucket archive;\naccess_key AKIAEXAMPLE;\nsecret_key ВАШ-КЛЮЧ;"}'
Ошибки
| Код | Когда |
|---|---|
400 |
в теле нет ключа name |
409 |
хранилище с таким именем уже есть |
422 |
неверное имя, не передан arg2, путь не является одним токеном конфигурации, итог не разбирается |
423 |
конфигурация заморожена |
PATCH /api/v1/storages/{name}#
Запись
Заменяет тело блока хранилища целиком — передавайте его полностью, включая секреты S3.
curl -sS -X PATCH "$BASE/api/v1/storages/dvr2" \ -H "Authorization: Bearer $TOKEN" \ -H 'Content-Type: application/json' \ -d '{"directives":"evict_at 80;"}'
DELETE /api/v1/storages/{name}#
Запись
curl -sS -X DELETE "$BASE/api/v1/storages/dvr2" -H "Authorization: Bearer $TOKEN"
Примечания. Удаление, которое оставило бы пишущий поток без хранилища, отклоняется кодом 422: разбор конфигурации целиком выполняется до записи на диск. Файлы записей на диске при этом не удаляются.
/storages/{name}/provision в этой сборке не работаетОн отвечает 400 {"title":"bad request","detail":"unknown verb \"provision\""} — разметка диска
компилируется только в управляемой сборке. Не используйте его в интеграции: создавайте каталог
средствами операционной системы и указывайте путь при создании хранилища.
Система, метрики и лицензия#
GET /api/v1/system#
Чтение
Снимок системного монитора, обновляемый примерно раз в секунду, плюс число рабочих ядер.
curl -sS "$BASE/api/v1/system" -H "Authorization: Bearer $TOKEN"
{"cpus":4,"worker_cores":4, "host_cpu_busy_pct":3.29,"per_core_busy_pct":[5.88,3.06,3.03,4.04], "proc_cpu_cores":0.1199,"rss_mb":153, "mem_total_mb":3910,"mem_available_mb":3259, "open_fds":61,"uptime_s":4077, "udp_ingest_kernel_drops":0,"udp_ingest_queue_dropped":0, "udp_ingest_recv_errs":0,"udp_ingest_rx_queued_kb":0,"udp_egress_bind_fails":0}
proc_cpu_cores — не то же самое, что %cpu из topЭто потребление CPU в ядрах, посчитанное как дельта процессорного времени, делённая на число
ядер. Значение 0.12 означает «примерно одна восьмая ядра». Сравнивать его напрямую с мгновенной
выборкой top не следует.
Ошибки
| Код | Когда |
|---|---|
405 |
использован метод, отличный от GET |
GET /api/v1/totals#
Чтение
Самый дешёвый эндпоинт наблюдаемости: тело фиксированного маленького размера, которое никогда не отвечает 413 при любом масштабе. Подходит для частого опроса.
curl -sS "$BASE/api/v1/totals" -H "Authorization: Bearer $TOKEN"
{"streams":10,"sessions":1, "bytes_in":6508772297,"bytes_out":105870921, "dvr_sessions":0,"dvr_bytes_out":24412877, "live_sessions":1,"live_bytes_out":81458044}
GET /api/v1/metrics#
Чтение
Весь снимок состояния одним ответом: массив потоков, массив сессий и агрегаты.
curl -sS "$BASE/api/v1/metrics" -H "Authorization: Bearer $TOKEN"
{"streams":[{"id":"cam1","core":0,"viewers":1,"bytes_in":4619859212,"fragments":18375,"…":"…"}], "sessions":[{"id":13,"stream":"cam1","protocol":"hls-fmp4","bytes_out":7364410,"…":"…"}], "totals":{"streams":10,"sessions":1,"bytes_in":6523182750,"bytes_out":106320842, "dvr_sessions":0,"dvr_bytes_out":24412877}}
GET /api/v1/metrics отдаёт JSON. Текстовая экспозиция Prometheus живёт по другому адресу — GET /metrics
в корне хоста, вне /api/v1; см. Мониторинг и метрики.
Если суммарное число строк (потоки + сессии) превышает 2000, ответ будет 413 со счётчиками, а не молча усечённым телом:
{"error":"rollup too large — use the paginated /api/v1/streams and /api/v1/sessions", "streams":2400,"sessions":15000}
На масштабе пользуйтесь пагинированными списками. Кроме того, поле totals здесь у́же, чем ответ
GET /totals: производных live_sessions и live_bytes_out в нём нет.
GET /api/v1/license#
Чтение
curl -sS "$BASE/api/v1/license" -H "Authorization: Bearer $TOKEN"
{"state":"licensed","customer":"example-customer","expires":"2027-01-31", "max_streams":50,"hwid":"<ОТПЕЧАТОК-ОБОРУДОВАНИЯ>"}
Отсутствующие поля опускаются, а не приходят как null: у бессрочной лицензии не будет ключа
expires, у лицензии без ограничения — ключа max_streams. Состояния state: licensed — всё в
порядке; grace — обновление лицензии не удаётся, но раздача продолжается; любое другое значение
означает, что медиа не отдаётся. См. Лицензирование.
Журналы#
GET /api/v1/logs#
Чтение
Ограниченное кольцо операционных записей, новые первыми.
Параметры запроса
| Параметр | Тип и допустимые значения | По умолчанию | Смысл |
|---|---|---|---|
level |
debug | info | warn | error |
debug |
минимальный уровень; неизвестное значение молча читается как debug |
stream |
строка | — | точное совпадение идентификатора потока |
q |
подстрока без учёта регистра | — | поиск по тексту записи |
after |
целое | 0 |
курсор «хвоста» — последний увиденный seq |
limit |
целое, не больше 2000 | 500 |
сколько записей вернуть |
curl -sS "$BASE/api/v1/logs?level=warn&limit=2" -H "Authorization: Bearer $TOKEN"
{"capture_level":"info","head_seq":17, "entries":[{"seq":17,"ts_ms":1787143225999,"level":"warn","target":"source", "stream":"cam1","msg":"[cam1] source stopped: error: Timeout"}, {"seq":16,"ts_ms":1787143017551,"level":"warn","target":"source", "stream":"cam1","msg":"[cam1] source stopped: error: Timeout"}]}
capture_level — это порог записи, а не порог показаТо, что ниже capture_level, в кольцо никогда не попадало. Фильтр ?level=debug на сервере с
capture_level: info не покажет отладочных записей — их просто нет. Чтобы они появились, поднимите
подробность директивой log_level (применяется горячо) и подождите новых событий; уже записанное
кольцо не пересобирается.
Чтение «хвоста». Опрашивайте маршрут, передавая в after наибольший seq из предыдущего ответа:
curl -sS "$BASE/api/v1/logs?after=17&limit=500" -H "Authorization: Bearer $TOKEN"
GET /api/v1/audit#
Чтение
Журнал административных действий, только дополняемый, новые первыми, со своим конвертом.
Параметры запроса
| Параметр | Тип и допустимые значения | По умолчанию | Смысл |
|---|---|---|---|
cursor |
целое | 0 |
0 — с самой свежей записи; иначе предыдущий next_cursor |
limit |
целое 1 … 200 |
50 |
размер страницы |
actor |
строка | — | точное совпадение исполнителя |
action |
строка | — | точное совпадение действия |
node |
строка | — | точное совпадение имени узла |
curl -sS "$BASE/api/v1/audit?limit=2" -H "Authorization: Bearer $TOKEN"
{"items":[{"id":42,"ts_ms":1787143225999,"actor":"admin","from":"10.0.0.55", "action":"stop","target":"cam1","status":200,"result":"ok"}], "limit":2,"next_cursor":41,"oldest":1,"tip":42}
Что записывается. Все императивные операции: жизненный цикл потока (create, clone, patch,
delete, start, stop, restart), config-apply, config-rollback, config-globals,
cert-upload, cert-delete, template-save, template-delete, vod-lib-save, vod-lib-delete,
storage-create, storage-patch, storage-delete, kick, cordon, uncordon, drain, restart,
rotate-session-keys, dvr-purge, dvr-candidates.
Чтения не записываются никогда. В поле result попадает только пояснение ошибки, но не тело
ответа, поэтому секреты в журнал не утекают.
Куда дальше#
- Готовые сценарии — эти операции, собранные в рабочие рецепты.
- Применение изменений — что применяется горячо, а что требует перезапуска.
- Справочник конфигурации — все директивы
hastreamer.conf. - Мониторинг и метрики — Prometheus, поток событий и что отслеживать.