Файл настроек pss.json

Страница описывает формат файла pss.json: как устроен документ, что служба принимает при чтении и что теряется при записи. Она адресована тем, кто правит файл напрямую или переносит настройки на другой узел.

Правка файла действует со следующего запуска. Чтобы изменить конфигурацию работающей службы, используйте веб-интерфейс или HTTP API (Управление через HTTP API) — только они применяют изменение немедленно и сообщают результат.

Пошаговые процедуры правки, проверки и переноса — Правка, проверка и перенос настроек.

Что это за файл

pss.json — рабочий файл настроек в каталоге /opt/pss/config. Порядок загрузки, откат на pss_back.json и pss_default.json и архив повреждённых файлов в каталоге bad/ описаны в Поведение при старте и ошибках конфигурации.

Одно следствие этого порядка нужно держать в голове до того, как открыть файл в редакторе: единственное неприемлемое значение стоит всех потоков. Файл не исправляется по частям — он отвергается целиком, а откат ведёт на pss_default.json, в котором потоков нет вовсе. Резервная копия pss_back.json существует только там, где настройки хотя бы раз восстанавливали через веб-интерфейс (Обслуживание); регулярной резервной копии служба не ведёт. Именно поэтому файл проверяют до того, как его прочитает служба.

Файл не является полным описанием конфигурации: в нём хранятся только отличия от значений, с которыми собран продукт. Что из этого следует — в следующем разделе; это самое важное, что нужно понимать до правки.

В том же каталоге лежит pss.properties — глобальные параметры процесса (пути к данным и журналам и подобное). Это файл «ключ=значение» с собственным синтаксисом, к JSON он отношения не имеет, и всё сказанное здесь к нему не относится.

В файле только отличия от значений по умолчанию

При записи файла служба пропускает всякое простое значение, совпадающее со значением по умолчанию. Сохраняются только отличия.

Из этого следуют три вещи, каждая из которых встречается на практике:

  • По файлу нельзя понять, как настроена служба. Отсутствующий ключ означает значение по умолчанию, а само это значение в файле не записано нигде. Чтобы прочитать действующую конфигурацию целиком, запросите её у работающей службы через HTTP API: там возвращаются все ключи, включая оставшиеся по умолчанию.

  • Записать ключ с его значением по умолчанию бесполезно. Такое значение принимается, а при следующем сохранении файла исчезает.

  • Смена значения по умолчанию между версиями меняет поведение молча. Если узел никогда не переопределял этот ключ, его в файле нет — и после обновления он начнёт работать по новому умолчанию с первого же запуска, а файл об этом ничего не скажет. Это главный риск при переносе настроек между версиями, и по самому файлу он не обнаруживается. Увидеть такое изменение можно единственным способом — прочитав действующую конфигурацию обеих версий через HTTP API, где возвращаются и значения по умолчанию.

Пропуск касается только одиночных значений. Сами секции и списки записываются всегда, даже когда внутри ничего не осталось: "user-default": {} — это секция, все ключи которой в значениях по умолчанию, а "accept-stream": [] — пустой список, записанный по тому же правилу. Пустые скобки не говорят ни о том, что настройка задана, ни о том, что она пропущена: смотрите смысл конкретного ключа.

Структура документа

Документ — один объект JSON. Его члены верхнего уровня — секции настроек:

Секция

Тип

Что описывает

server

объект

Имя и роль узла, журналирование, обслуживание.

cluster

объект

Meshwork: адреса, имена и секреты соседних узлов.

user-default

объект

Зарезервировано, ключей пока не содержит.

user

массив

Учётные записи получателей потоков и партнёров.

web-server

объект

Веб-интерфейс и его учётные записи.

http-server

объект

Раздача потоков по HTTP.

epg-server

объект

Раздача телепрограммы.

cs

объект

Внешние серверы управления абонентами.

mosaic

объект

Включение мозаики.

epg

объект

Сбор телепрограммы и её источники.

alerter

объект

Пороги оповещений и адреса доставки.

acme

объект

Автоматическое получение сертификатов.

dvb-adapter

массив

Платы DVB-приёма.

dvr-storage-list

объект

Хранилища архива DVR.

stream

массив

Потоки.

stream-adaptive

массив

Группы адаптивного битрейта.

Массивы верхнего уровня всегда содержат объекты. Внутри секций и записей встречаются и простые списки значений — чисел и строк; о них см. Парные массивы сопоставляются по позиции. Объекты массивов, в свою очередь, содержат вложенные массивы объектов, поэтому наибольшая глубина документа — три уровня:

stream[]  ->  input[]   ->  ключи одного входа
          ->  output[]  ->  ключи одного выхода

Ключи простых секций необязательны все до одного, и отсутствие целой секции ошибкой не является.

Записи массивов — исключение. Кроме id каждая запись обязана нести свои опорные ключи: у потока — stream-name, у входа и выхода — type и адрес или путь выбранного транспорта, у платы приёма — name, у хранилища — name и dir-path, у учётной записи веб-интерфейса и телепрограммы — login и password, у источника телепрограммы — name и source. Пропуск любого из них отбрасывает весь файл. Схема эти ключи проверяет, так что проверка перед запуском такую запись поймает.

Справочник по отдельным ключам — тип, диапазон и значение по умолчанию каждого — находится в справочном документе по HTTP API (Справочные документы). Здесь он намеренно не повторяется: две копии одного справочника расходятся за один выпуск.

Что делает служба при чтении файла

Чтение устроено намеренно неровно: в одних случаях служба прощает ошибку, в других отвергает файл целиком — её первая задача поднять узел. Разница между опечаткой, которую вы заметите, и опечаткой, которую не заметите, состоит именно в этом.

Принимается, но не так, как задумал автор правки

Что в файле

Что делает служба

Неизвестный ключ

Игнорируется. В журнал пишется предупреждение с именем ключа и секции, которой он адресован (для записи массива называется массив, а не сама запись). Настройка, которую вы хотели изменить, просто не меняется, и опечатка в имени ключа не видна, пока не прочитан журнал. Из файла ключ исчезает при следующем сохранении конфигурации, но сам по себе сохранения не вызывает и может пролежать в файле долго.

Ключ отсутствует

Действует значение по умолчанию. Не ошибка.

Секция отсутствует

Все её ключи принимают значения по умолчанию. Не ошибка.

Один и тот же ключ дважды в одной секции

Молча побеждает последний. Ни ошибки, ни предупреждения.

Число или true и false в кавычках

Принимается: значение читается как текст и разбирается. Схема, однако, такое значение отвергнет, поэтому числа и признаки пишут без кавычек.

Число вне диапазона

Приводится к ближайшей границе с предупреждением в журнале, где указаны ключ, прочитанное значение и применённая граница. После загрузки служба пересохраняет файл с исправленным значением, поэтому при следующем запуске предупреждение не повторяется. То же значение, отправленное через HTTP API, не корректируется, а отклоняется с ошибкой.

Массив там, где ожидается одно значение

Игнорируется полностью, без единой записи в журнале. Настройка остаётся в значении по умолчанию, и никакой диагностики не появляется.

Ошибки формы вокруг списков и повторённый ключ — это те случаи, которые проходят совершенно молча: журнал о них не скажет ничего. Они и есть главный довод в пользу проверки файла по схеме перед запуском.

Примечание

Неизвестным оказывается и ключ, которого не поддерживает данная сборка. На узле, сборка которого не умеет принимать DVB, секция dvb-adapter из перенесённого файла целиком станет неизвестной: одно предупреждение в журнале — и при следующем сохранении она из файла исчезнет.

Отвергается вместе со всем файлом

Каждый из этих случаев прекращает загрузку. Файл перемещается в каталог bad/, и служба переходит к следующему файлу по порядку (Поведение при старте и ошибках конфигурации).

Что в файле

Пояснение

Синтаксическая ошибка JSON

Любая.

Значение null

Где угодно и для любого ключа. null не принимается никогда: чтобы вернуть настройку к значению по умолчанию, ключ удаляют.

Неверная форма значения

Объект там, где ожидается одно значение; одно значение там, где ожидается объект или список объектов.

Число или чужое слово вместо признака

Логические ключи принимают только true и false — в кавычках или без. Ни 1 и 0, ни "yes" и "no" не принимаются.

Строка длиннее допустимого

Ограничения длины, в отличие от числовых диапазонов, никогда не усекаются.

Дробное число там, где нужно целое

Значение не разбирается как целое, и загрузка прекращается. То же для строки, которая не читается как число.

Запись массива без опорного ключа

Кроме id запись обязана нести свои обязательные ключи (Структура документа).

Запись массива без id

Идентификатор обязателен. Исключение — массив stream: там пропущенный id читается как 0, а это допустимое значение, поэтому отвергнута будет только вторая запись без идентификатора, как повтор.

Повторяющийся id

Две записи одного массива с одинаковым идентификатором.

Повтор значения, объявленного уникальным

Ряд массивов требует уникальности ключа среди своих записей: имена учётных записей, имена и пути хранилищ, имена потоков, адреса источников и другие.

Пустое значение там, где нужен текст

Внутри записей массивов это требование строгое; в простых секциях оно соблюдается не везде, и полагаться на послабление не стоит.

Значение, не прошедшее проверку секции

Часть секций проверяет свои значения целиком, и такая проверка тоже прекращает загрузку: недопустимые символы или превышение длины в имени узла и имени домена, неизвестный уровень журналирования, неверно записанный дополнительный домен, несовпадающее число записей в парных массивах Meshwork, несовпадающая длина списков имён и значений переменных окружения.

Журнал — часть процедуры

Ошибки из первой таблицы не мешают запуску, ошибки из второй его прекращают. Единственное место, где видны первые, — журнал после первого запуска. Любая строка о проигнорированном ключе или о приведённом к границе значении означает, что файл говорит не то, что вы в нём написали.

Правила, которых в файле не видно

Это свойства чтения, а не синтаксиса. Файл может быть безупречным JSON, пройти все проверки предыдущего раздела и всё равно означать не то, на что похож.

Порядок ключей внутри объекта значим

Ключи применяются в том порядке, в каком записаны. В нескольких местах ключ определяет, какие ключи вообще существуют дальше в той же записи, и потому обязан стоять перед ними. Ключ, записанный выше своего определяющего ключа, в момент чтения ещё не опознан и отбрасывается как неизвестный — с предупреждением в журнале и без ошибки загрузки.

Так устроены:

  • type в записи входа или выхода — выбирает транспорт и всё, что к нему относится;

  • mpts и stream-name в записи потока. mpts выбирает вид потока и должен предшествовать в том числе массивам input и output, а stream-name открывает параметры OTT, архива и мультиплекса, если ключа mpts в записи нет. Умолчание ключа enable-mosaic, взятое от mpts, окончательно определяется в момент чтения mpts (а при его отсутствии — stream-name): явно заданный enable-mosaic выше этого места перезаписывается этим значением, ниже — сохраняется;

  • type и mode в записи платы DVB — вместе они определяют набор параметров настройки, и оба должны стоять до ключа name.

Одно исключение из общего правила: если массивы input и output стоят выше mpts, входы и выходы строятся как для потока с одной программой, и тип, допустимый только для потока с несколькими программами, приводит к отказу от всего файла, а не к предупреждению.

Файл, записанный самой службой, этим правилам удовлетворяет всегда: служба выводит ключи в фиксированном безопасном порядке. Уязвим только файл, в котором порядок изменили вручную. JSON Schema понятия порядка не имеет, поэтому схемой это не проверяется. Практическое правило простое: ничего не переставляйте — сохраняйте тот порядок, в котором файл записала служба.

Идентификаторы проставляются вручную

Каждая запись каждого массива имеет ключ id. Идентификаторы назначаются автоматически только при создании записи через HTTP API; при чтении файла их не назначает никто.

Поэтому добавленная вручную запись обязана нести явный id:

  • он обязателен в любом массиве — без него отвергается весь файл;

  • он должен быть уникален внутри своего массива;

  • наименьшее допустимое значение — 1 везде, кроме массива stream, где допустим и 0.

У массива stream из этого следует ловушка: пропущенный id читается там как 0, то есть как настоящий идентификатор. Первая запись без id пройдёт, вторая столкнётся с ней и отбросит весь файл. По той же причине поток с id 0 записывается в файл вообще без строки id — это не ошибка записи, а следствие того, что ноль здесь и есть значение по умолчанию.

Уникальность идентификаторов средствами JSON Schema невыразима, поэтому это одно из немногих правил, которое схема за вас не проверит. Готовая команда для поиска повторов — Проверки, которых схема не делает.

Порядок записей в массиве не сохраняется

Крупные списки служба сортирует при каждом чтении, каждый по своему ключу: потоки — по отображаемому имени, входы и выходы потока — по ключу порядка, учётные записи — по логину, хранилища и платы приёма — по имени. В каком бы порядке вы ни записали такие записи, сохранённый файл будет отличаться. Не вкладывайте смысл в их порядок: там, где последовательность важна, для неё есть отдельный ключ.

Правило не всеобщее, и на два исключения стоит обратить внимание:

  • несколько списков сохраняют порядок из файла — в частности группы адаптивного битрейта и серверы управления абонентами;

  • простые списки значений не переупорядочиваются никогда. Это существенно: именно на их порядке держатся парные массивы (Парные массивы сопоставляются по позиции).

Парные массивы сопоставляются по позиции

Несколько настроек выражены параллельными массивами, которые сопоставляются по номеру: запись N одного массива относится к записи N остальных. Так устроены адреса, имена и секреты соседних узлов Meshwork, имена и значения переменных окружения, а также списки «было — стало» при переназначении идентификаторов. Удаление записи из одного массива без удаления соответствующей записи из остальных сдвигает всё, что идёт следом.

Схема проверит, что каждый массив содержит элементы нужного типа, но не то, что длины массивов совпадают. Служба проверяет это сама и отбрасывает весь файл при расхождении длин у соседей Meshwork, у переменных окружения, у списков «было — стало» при переназначении PID (mpegts-pid-old и mpegts-pid-new), у списков смены языка (mpegts-lang-set-pid и mpegts-lang-set) и у ключей дескремблирования (biss-pnr и biss-key). У четвёрки адресов RIST (rist-addr-*) расхождение длин загрузку не прекращает, но вход не открывается, и причина пишется в журнал. Готовая команда сверки — Равная длина парных массивов.

Комментарии читаются, но не сохраняются

Чтение допускает блочные комментарии вида /* ... */ — они удобны во время работы над файлом. Только эту форму: строчный комментарий // не поддерживается и делает файл синтаксически неверным, то есть отбрасывает его целиком. По той же причине не пишите сочетание /* внутри текстового значения — оно будет принято за начало комментария.

Комментарии не переживают сохранения: служба каждый раз формирует документ заново из того, что держит в памяти, поэтому первое же сохранение стирает их все. Считайте их пометками на время правки, а то, что должно сохраниться, записывайте в ключ note, который есть у большинства секций и записей.

Строгие инструменты JSON — в том числе валидатор из Правка, проверка и перенос настроек — файл с комментариями не разберут. Перед проверкой комментарии удаляют.

Условные наборы ключей

Два ключа работают как переключатели, определяющие, какие ключи рядом с ними допустимы:

  • В записях входов и выходов type выбирает транспорт. У каждого транспорта свой набор ключей; ключ другого транспорта не опознаётся.

  • В записях DVB-плат type выбирает систему вещания, а mode — режим работы. Вместе они определяют набор ключей настройки, вплоть до того, есть ли вообще ключи конвертера.

Схема воспроизводит эти условия и отвергнет ключ, не принадлежащий выбранному варианту. Единственный случай, который она выразить не может, — ключ, чья форма зависит от переключателя в объемлющем объекте: в потоке с несколькими программами ключ дескремблирования (biss-key) записывается списком, а в потоке с одной программой — одиночным значением. Схема принимает обе формы везде, где этот ключ встречается; правильную выбирает только служба.

Значения, которые нельзя пересылать

Файл хранит пароли и ключи в открытом виде. Прежде чем передать конфигурацию кому бы то ни было — коллеге, в запрос в поддержку, в систему учёта заявок, в общедоступный репозиторий, — замените значения:

  • паролей учётных записей в секциях веб-интерфейса, телепрограммы и получателей потоков, пароля сервера управления абонентами, а также логина и пароля источника телепрограммы;

  • собственного секрета узла и секретов соседних узлов Meshwork;

  • парольных фраз транспортов и паролей клиента у входов PS1 и SRT, пароля входа RTSP, логина и пароля входа HLS/HTTP;

  • ключей и идентификаторов ключей защиты содержимого и общих секретов;

  • ключей дескремблирования;

  • токена бота службы сообщений и пароля почтовой учётной записи;

  • ключа привязки удостоверяющего центра.

Два ключа не названы в честь секретов, но регулярно их содержат: адрес публикации у выхода на внешнюю площадку и адрес источника у входа, если учётные данные записаны прямо в ссылке.

Список растёт с каждым новым транспортом, поэтому не полагайтесь на него как на исчерпывающий: перед отправкой файла найдите в нём password, secret, key, token и passphrase и просмотрите каждую ссылку.

Файл — не единственный путь к этим значениям: через HTTP API они доступны на чтение любой учётной записи узла, включая роль только для чтения (Доступ).

Предупреждение

Замена секрета пустой строкой безопасна не всегда: часть этих ключей пустое значение не принимает, и файл будет отвергнут целиком. Подставляйте очевидную замену правдоподобной длины.

Проверка по JSON Schema

Вместе с документацией публикуется машиночитаемое описание файла настроек в формате JSON Schema. Оно ловит целый класс ошибок, которые сама служба поглощает молча, — прежде всего опечатку в имени ключа и массив, записанный вместо одиночного значения.

Два файла схемы

Файл

Назначение

pss.schema.json

Строгая. Каждый ключ должен быть из числа объявленных продуктом. Используется для файла, предназначенного версии, указанной в заголовке схемы.

pss.compat.schema.json

Мягкая. Типы, диапазоны, перечни и обязательные ключи проверяются по-прежнему, но ключи, которых продукт не знает, пропускаются. Первый проход при переносе настроек с другой версии, где неизвестные ключи ожидаемы, а не подозрительны.

Обе схемы несут версию продукта, для которой они сформированы. Конфигурация осмысленно проверяется только схемой той версии, которая будет её читать. Проверка схемой другого выпуска даёт уверенный и неверный ответ.

Предупреждение

Мягкая схема пропускает не только незнакомые ключи. Принадлежность ключа выбранному варианту (Условные наборы ключей) в схеме держится на том же механизме, поэтому при мягкой проверке проходит и настоящий ключ, записанный не в тот тип входа, не в тот режим платы или не в тот вид потока — а вместе с ним не проверяется и его собственный диапазон. Мягкая схема — только первый проход; последнее слово всегда за строгой.

Примечание

Схемы входят в комплект документации, а не в состав продукта: копии в каталоге настроек работающего узла нет, и она там не нужна. Их публикуют на сайте документации — https://doc2.pstreamer.tv/schema/, каталог на каждую версию. Возьмите схему для своей версии и держите её на той машине, где правите файл.

Адрес, записанный внутри самой схемы в ключе $id, — это её идентификатор, а не указание что-то скачивать: проверка файла работает и без доступа в сеть.

Что схема проверяет

  • имена ключей — опечатка становится ошибкой вместо молчаливого игнорирования;

  • типы значений, в том числе массив, записанный вместо одиночного значения;

  • числовые диапазоны и ограничения длины текста;

  • замкнутые наборы допустимых значений;

  • наличие обязательных ключей, прежде всего id и type;

  • принадлежность варианту — ключ чужого транспорта или чужой системы вещания будет отмечен.

Чего схема не проверяет

Всё перечисленное проверяет сама служба при чтении файла, и большая часть этого прекращает загрузку. Схема сокращает разрыв, но не закрывает его: успешная проверка означает, что файл корректен и правдоподобен, а не что служба его примет.

Примечание

HTTP API содержит семейство запросов /schema, которые возвращают списки допустимых значений и обнаруженного оборудования — типы входов и выходов, поддерживаемые данной сборкой, языки, найденные платы, устройства транскодера. К файлу pss.schema.json они отношения не имеют, и одно другим не заменяется. Совпадение в названиях — только совпадение.

Совместимость между версиями

Предупреждение

Обратная совместимость не гарантируется. При обновлении могут измениться и файл настроек, и схема, и HTTP API: состав и имена ключей, диапазоны значений, форма запросов и ответов. Обновление не переносит настройки и не предупреждает о расхождениях. Проверяйте файл заново после каждого обновления, а сценарии, работающие с HTTP API, — заново после каждого обновления тоже.

Отдельные ключи между выпусками добавляются, переименовываются и удаляются, а допустимые диапазоны — сужаются. Удалённый ключ становится неизвестным и игнорируется, поэтому настройка просто перестаёт действовать; новый ключ действует по умолчанию, пока не записан; значение, вышедшее из сузившегося диапазона, приводится к границе. Ни об одном из трёх служба не сообщает.

В файле нет отметки о версии. Ничто внутри него не указывает выпуск, который его записал, и служба не выполняет никакого преобразования, читая файл от более старой или более новой сборки. Вместе с разреженностью файла это означает, что перенесённый файл применяется как есть.

Поэтому схема — единственный практический способ узнать, какие ключи существующего файла данный выпуск уже не понимает. Проверяйте файл заново после каждого обновления; порядок действий — Перенос настроек на другую версию.