Перейти к содержимому
Elemctl
Русский
Esc
navigateopen⌘Jpreview
На этой странице

Платформа изнутри

Console API v2, формат файла сборки и особенности поведения платформы, о которых стоит знать.

На этой странице – про платформу, а не про инструмент: как устроен Console API, из чего состоит файл сборки и как платформа ведёт себя в случаях, которые с первого раза удивляют. Всё это записано потому, что документация платформы такие углы не покрывает, а elemctl пришлось их изучить на практике.

Для работы с инструментом эта страница не нужна. Она пригодится, когда что-то ведёт себя странно и хочется понять, что происходит внутри, – или когда вы пишете собственный клиент.

Контракт Console API v2

Общий префикс: {base}/console/api/v2. Тела запросов и ответов - JSON (кроме загрузки сборки). Имена полей - в kebab-case.

Приложения

  • GET /applications - список. Query-параметр name существует, но платформа его ИГНОРИРУЕТ и возвращает полный список (проверено живым вызовом) - фильтрация по имени выполняется на клиенте.
  • GET /applications/{id} - карточка. Значимые поля ответа: id, status, uri (адрес работающего приложения), error (текст ошибки, если есть), technology-version, date-updated, display-name, publication-context, source (объект с информацией об источнике, содержит в т.ч. project-version - версию применённой сборки).
  • POST /applications - создать. Тело:
    • source - объект {"type": "repository"} плюс ровно один из ключей: project-version-id (id сборки-источника) либо image-id (id проекта);
    • display-name, publication-context - имя и путь публикации;
    • development-mode - булево, создавать ли среду разработки;
    • необязательные space-id, technology-version.
  • DELETE /applications/{id} - удалить.
  • PUT /applications/{id}/status/start - запустить.
  • PUT /applications/{id}/status/stop - остановить.
  • POST /applications/{id}/actions/debug - данные для сессии отладки (ApplicationDebugInfo: {"debug-token": ..., "debug-address": ...}). Тело запроса пустое; требует включённой отладки на сервере (config/debug.yml enabled: true).
  • POST /applications/{id}/project/update - применить сборку к приложению. Тело: {"source": {"type": "repository", "image-id": "<id сборки>"}} либо {"source": {"type": "repository", "project-id": "<id>", "assembly-version": "<версия>"}} (assembly-version необязательна).
  • POST /applications/{id}/dumps - создать дамп. Тело: include-users, include-binary-data (булевы), description (строка).
  • GET /applications/{id}/dumps/{dumpId} - статус дампа.

Статусы приложения: стабильные Running, Stopped, Error; переходные Starting, Stopping, Initializing, Updating, Frozen, Creating. Во время переходов поле status может быть и пустым.

Версия технологии

  • Чтение - из поля technology-version карточки приложения (отдельный endpoint чтения есть не во всех версиях платформы - не использовать).
  • Обновление: POST /tasks/group-tasks/update-applications-technology, тело {"technology-version": "<версия>", "applications": ["<app-id>"]}. Возвращает групповую задачу; её статус - GET /tasks/group-tasks/{taskId}.

Пространства и проекты

  • GET /spaces - список пространств.
  • GET /projects - список проектов; GET /projects/{id} - карточка; DELETE /projects/{id} - удаление.

Сборки проекта (assemblies)

  • Загрузка файла сборки - бинарный POST (Content-Type application/octet-stream, тело - байты файла):
    • POST /projects/{id}/assemblies - добавить сборку в существующий проект;
    • POST /projects - создать новый проект из сборки. Единственный query-параметр (необязательный): SpaceId; внимание: имя - в PascalCase. Параметров BranchName/CommitId/CommitMessage у метода НЕТ: в справочнике Console API их нет, а отправленные сервер игнорирует (прямой POST с настоящим хэшем отвечает commit-id: null) - коммит в карточке сборки проставляется только связью проекта с репозиторием. Ответ содержит id созданной сборки в одном из полей: image-id, assembly-id или id (проверять в этом порядке), и объект artifact, называющий проект, в который сборка легла: artifact-id (ид проекта – открывается карточкой проекта), configuration-id (Ид из Проект.yaml) и name (представление проекта). Панель показывает проект под именем последней залитой сборки (Name из манифеста), поэтому сборка, залитая в проект под другим именем, молча переименовывает этот проект; заливка сборки с родным именем возвращает имя обратно. elemctl предупреждает о таком несовпадении перед загрузкой.
  • Проект опознаётся парой Vendor + Name манифеста, а не Ид из Проект.yaml. Поэтому POST /projects не всегда создаёт проект: если пара уже знакома, сборка просто добавляется в проект-владелец, и он же приходит в artifact-id. Два способа получить 409 ALREADY_EXISTS: залить версию, которая уже есть (“Версия сборки … уже присутствует в группе проекта”), и попытаться зарегистрировать ту же пару поставщик+имя в другом проекте (“Сборка с именем поставщика … уже зарегистрирована в другом проекте”) – второе не обходится и генерацией нового Ид. Второй, одноразовый проект под те же исходники можно получить только их переименованием.
  • GET /projects/{id}/assemblies - список сборок. Элемент содержит assembly-version (строка вида 1.0-42) и id (id либо image-id). Ответ может быть как массивом, так и объектом со списком в поле items или assemblies.
  • GET /projects/{id}/assemblies/{assembly-id} - карточка сборки; DELETE .../{assembly-id} - удаление. API адресует сборку ТОЛЬКО UUID: на версию отвечает 400 “Version is not a valid UUID”. Клиент обязан принимать и версию (пользователь видит именно её), резолвя её в id по списку сборок (assembly-version/project-version); учитывать, что версию из манифеста платформа при загрузке перенумеровывает по-своему. Удаление сборки платформа отклоняет с 500, пока живо созданное из неё приложение; после того как это приложение действительно исчезло, тот же запрос проходит (сборка, лишь участвовавшая в применении – даже откатившемся, – удаляется без препятствий).

Сравнение версий сборок: по числовому суффиксу после последнего дефиса (1.0-10 новее 1.0-9; лексикографическое сравнение даёт неверный порядок).

Ветки среды разработки

  • GET /branches - список; необязательные query project-id, name.
  • GET /branches/{id} - карточка. Поля: name, kind, project, application, source-branch, deletion-mark, version-stamp.
  • POST /branches - создать. Тело: name, kind: "development", project: {"id": "<id>"}, необязательно application: {"id": "<id>"}.
  • PUT /branches/{id} - изменить. Платформа использует оптимистическую блокировку: сначала прочитать карточку, затем отправить тело, собранное из текущих значений - name, kind, deletion-mark, version-stamp (обязательно вернуть как есть), source-branch и application - свернуть до {"id": ...} (или {"name": ...}, если id нет). Для перепривязки к приложению заменить application на {"id": "<новый app-id>"}.
  • Принятие изменений ветки (merge) - тот же PUT /branches/{id} с дополнительным ключом тела write-parameters: {"merge": true}.
  • DELETE /branches/{id} - удалить ветку.

Инструмент работает ТОЛЬКО с документированным Console API v2. Внутренние (недокументированные) API консоли платформы не используются и не описываются.

Списки пользователей

Список пользователей держит пользователей приложения (у приложения есть свой, названный по нему - карточка приложения указывает на него полем default-user-list) либо панели управления (один на установку).

  • GET /user-lists - список: id, presentation, space-id; фильтра по имени на сервере нет. GET /user-lists/{id} - полная карточка. POST /user-lists создаёт, и требует карточку ЦЕЛИКОМ: на неполное тело отвечает 500 с обманчивым текстом “Failed to parse json”. DELETE /user-lists/{id} удаляет.
  • GET|PUT /user-lists/{id}/settings/self-registration - {enabled, phone-required, email-required}, это “Разрешить пользователям регистрироваться самостоятельно” из панели.
  • GET|POST /user-lists/{id}/settings/account-services-settings, PUT|DELETE .../{account-service-id} - сервисы учётных записей. Запись: {account-service-id, account-service-type, local-id, enabled, create-user-on-auth, additional-settings}; тип Local аутентифицирует паролем, остальные (OIDC, Cas, ActiveDirectory, Esia) внешние. Обе записи требуют запись целиком.
  • GET|POST|DELETE /applications/{id}/userlists - ид списков, подключённых к приложению. Внимание на написание: здесь userlists, а на верхнем уровне user-lists. Собственных настроек у связи нет.

Что стоит знать, прежде чем на это опираться:

  • правила разбора ответа сервиса учётных записей (presentation-rule, email-rule, phone-rule, response-kind) принимаются под ключом userPropertiesCalculationRules, хотя схема самого справочника называет поле calculation-rules - на такое написание приходит 400. GET правила не возвращает никогда: настройка на запись, и клиент API не может подтвердить её применение;
  • состава ФОРМ аутентификации приложения и настройки подключения “пользователи списка подключаются автоматически при входе” в API нет вовсе - это остаётся в панели;
  • GET сервиса учётных записей отдаёт client_secret OIDC-клиента открытым текстом, так что таким ответам не место в логах и отчётах как есть;
  • неизвестный путь Console API отвечает 401 с текстом “Handler of HTTP request … not found”, а не 404 - при переборе поверхности это и есть признак того, что метода нет.

Задачи приложений

GET /tasks/application-tasks - список задач всех приложений (серверного фильтра нет - фильтровать на клиенте). Поля задачи: id, application-id, status (в т.ч. Error, Failed), operation-type, error-message, start-date (ISO 8601, может оканчиваться на Z).

Формат файла сборки (.xasm / .xlib)

Файл сборки - ZIP-архив (deflate):

  • в корне Assembly.yaml - манифест, плоские пары ключ-значение:

    ManifestVersion: 1.0
    ProjectKind: Application | Library
    Vendor: <поставщик>
    Name: <имя проекта>
    Version: <версия, например 1.0-42>
    Created: <UTC, формат YYYY.MM.DD HH:MM:SS>
    BranchName: <имя git-ветки>
    CommitId: <хэш коммита>

    Для библиотеки (ProjectKind: Library) в конце добавляется строка Release: (пустое значение); расширение файла .xlib, для приложения - .xasm.

  • далее файлы проекта путями {vendor}/{name}/... - относительно корня репозитория. Каталог проекта обязан лежать по схеме {repo}/{vendor}/{name}/Проект.yaml. Разделители путей в архиве - прямые слэши (и на Windows).

Имя файла сборки: {Имя} {Version}.xasm (через пробел).

Метаданные проекта - из Проект.yaml (YAML, достаточно разбора плоских пар ключ: значение верхнего уровня, вложенные строки с отступом пропускать). Двуязычие исходников - заявленная возможность платформы (дескриптор с английскими ключами применяется штатно), поэтому каждый ключ читается в обоих написаниях: Имя/Name, Поставщик/Vendor, Версия/Version (базовая, например 1.0), ВидПроекта/ProjectKind (значение Библиотека/Library означает библиотеку, иначе приложение). При обоих написаниях сразу приоритет у русского. Двуязычны и имена служебных файлов: конвертер платформы принимает Project.yaml/Проект.yaml и Subsystem.yaml/Подсистема.yaml, а английский дескриптор несёт английские и ЗНАЧЕНИЯ перечислений (VisibilityScope: Global).

Версия сборки, если не задана явно: {базовая версия}-{N+1}, где N - счётчик из версии последней сборки проекта. Без последней сборки суффикс берётся из номера прогона CI в окружении - первое числовое значение из CI_PIPELINE_IID, GITHUB_RUN_NUMBER, BUILD_NUMBER (в этом порядке): чистый рабочий каталог CI иначе давал бы -1 на каждом прогоне; нет и номера CI - {базовая версия}-1.

Git-метаданные (хэш коммита, имя ветки) - из git-репозитория, содержащего каталог проекта; при недоступности git оставить пустыми.

Отбор файлов в архив:

  • включаются только расширения: .yaml .xbsl .xbql .md .txt .json (исходники), .png .svg .jpg .jpeg .gif .webp .ico (изображения), .css .htm .html .js .woff .woff2 .ttf .eot (веб-ресурсы);
  • отбор по расширению НЕ действует внутри каталога Ресурсы (на любом уровне, включая подкаталоги): ресурс по документации платформы - произвольный файл, поэтому оттуда берётся всё;
  • где бы они ни лежали, включаются файлы описания клиента SOAP-сервиса: <ИмяКлиента>.Wsdl.<n> и <ИмяКлиента>.Xsd - платформа держит их рядом с элементом проекта и читает по имени;
  • исключаются каталоги .git, .claude, .github, __pycache__, node_modules, .venv и все скрытые (начинающиеся с точки);
  • исключаются файлы .gitignore, .env, .DS_Store и файлы *.xasm, *.xlib.

Разбор готового архива

Операция, обратная сборке: по файлу .xasm/.xlib - манифест, свойства проекта из его Проект.yaml внутри архива, состав. Нужна, чтобы подключить библиотеку к проекту, не разворачивая её исходники.

Раскладка внутри проекта (единственный источник истины о составе - каталоги):

  • каталог первого уровня - подсистема; Подсистема.yaml необязателен (у подсистемы библиотеки его может не быть вовсе), поэтому опираться на него при поиске подсистем нельзя;
  • вложенный каталог подсистемы - пакет; файла-описания у пакета нет, каждый каталог даёт сегмент имени;
  • полное имя типа: {vendor}::{name}::{подсистема}[::{пакет}]::{ИмяТипа}. То же имя без последнего сегмента указывается в Использование и импорт.

Наружу, в подключивший проект, видны только типы с ОбластьВидимости: Глобально (умолчание - ВПодсистеме, глобальная область пишется явно).

Совместимость проверяется по свойству РежимСовместимости файла Проект.yaml. Свойства ВерсияТехнологии в Проект.yaml не существует - оно относится к телу запроса Console API на создание приложения, а не к файлу проекта.

Поведенческие особенности платформы (обязательны к учёту)

  1. Тихий откат применения. Если применение сборки к приложению падает (например, ошибка компиляции), платформа молча откатывает приложение на предыдущую сборку и запускает его - статус Running НЕ означает успех. Достоверная проверка результата деплоя:
    • задачи приложения (п. 4.6) со статусом Error/Failed, у которых start-date не раньше момента начала деплоя (старые ошибки из истории не учитывать!);
    • сверка фактически применённой версии (source.project-version карточки приложения) с версией загруженной сборки;
    • информационно - контрольный GET по uri приложения (коды 401/403 нормальны для закрытых приложений и успеху не противоречат).
  2. Пустой каркас при создании. Создание приложения с источником “проект” (image-id = id проекта) на части конфигураций платформы даёт пустое приложение без данных проекта. Надёжный источник - конкретная сборка (project-version-id), например последняя сборка проекта.
  3. Удаление с черновиками. Если в среде разработки приложения есть неопубликованные правки, DELETE /applications/{id} возвращает 400 с FAILED_PRECONDITION в теле. Принудительного удаления в API нет - только панель управления; инструмент обязан дать понятную подсказку.
  4. Готовность нового приложения. После создания приложение какое-то время в переходных статусах и без uri - предусмотреть ожидание готовности (появился uri и стабильный статус). Статус Error при ожидании - немедленная ошибка.
  5. Перезапуск после применения. project/update может сам перезапустить приложение. После вызова дождаться выхода из переходных статусов; если итог не Running - остановить (если не Stopped), дождаться Stopped, запустить, дождаться Running. Разумные таймауты: ожидание остановки ~3 мин, запуска/стабилизации ~5 мин, опрос каждые ~10 с.
  6. Error терминален. Стабильный Error (например, после неудачного применения) - немедленная ошибка: сразу показать тексты ошибок задач приложения. Не пытаться останавливать/перезапускать такое приложение и не ждать другого статуса - из Error оно в Stopped не переходит, ожидание лишь съедает весь таймаут.
  7. Windows. Временные файлы и кеши - только через tempfile; вывод консоли перевести в UTF-8 (reconfigure для stdout/stderr), иначе кириллица ломается.
  8. Проект опознаётся поставщиком и именем. См. загрузку сборки выше: личность проекта – пара Vendor + Name манифеста. Загрузка без ид проекта означает не “создать новый проект”, а “положить туда, где этой паре место”.
  9. Удаление асинхронно и упорядочено. DELETE /applications/{id} возвращается сразу, приложение ещё какое-то время живёт с задачей DeleteApplication. Пока оно существует, удаление сборки, из которой оно создано, отклоняется с 500. Порядок уборки: удалить приложение, дождаться, когда его карточка ответит 404 (или статус станет Deleted), и только затем удалять сборку.
  10. Компиляция серверная и происходит на применении. Локальная сборка лишь упаковывает архив: синтаксис, типы и видимость исходников проверяет серверный компилятор при применении сборки или создании приложения из неё. Отдельной конечной точки “скомпилировать” нет. Вместе с пунктами 8 и 9 из этого и собран elemctl probe: исходники уходят в свой же проект сборкой с одноразовой версией, до компилятора добираются через одноразовое приложение, и обе сущности потом удаляются – рабочее приложение не рискует ничем.
  11. Вход в только что созданное приложение. Новое приложение получает СВОЙ пустой список пользователей (карточка указывает на него полем default-user-list), вход по логину и паролю в нём выключен, а сервиса учётных записей у него нет. Поэтому учётные записи, которыми входят в другие приложения, здесь не работают – и подключение чужого списка пользователей (POST /applications/{id}/userlists) вместе с включением локального входа этого НЕ меняют. Работает учётная запись ПАНЕЛИ УПРАВЛЕНИЯ: её пользователей платформа подключает к приложению сама, и они входят сразу. Полезно знать, поднимая стенд под задачу: способ входа из карточки не следует, а перебирать учётки не стоит – у пользователя есть счётчик неудачных попыток.

Последнее обновление 31 августа 2026 г.

Эта страница была полезной?