add Sphinx documentation
This commit is contained in:
+89
-89
@@ -2,15 +2,15 @@
|
||||
|
||||
## Transport
|
||||
|
||||
- Протокол: HTTPS.
|
||||
- Формат тела запроса и ответа: JSON.
|
||||
- Префикс API: `/api/v1`.
|
||||
- Формат времени: RFC 3339 / ISO 8601, например `2026-05-24T13:20:30Z`.
|
||||
- Авторизация клиента: bearer token в заголовке `Authorization`.
|
||||
- Protocol: HTTPS.
|
||||
- Request and response body format: JSON.
|
||||
- API prefix: `/api/v1`.
|
||||
- Time format: RFC 3339 / ISO 8601, e.g. `2026-05-24T13:20:30Z`.
|
||||
- Client authorization: bearer token in the `Authorization` header.
|
||||
|
||||
Пример заголовков:
|
||||
Example headers:
|
||||
|
||||
```http
|
||||
```text
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer <client-token>
|
||||
```
|
||||
@@ -19,12 +19,12 @@ Authorization: Bearer <client-token>
|
||||
|
||||
### `POST /api/v1/client/heartbeat`
|
||||
|
||||
Клиент вызывает эту ручку на каждом polling tick. Одна и та же ручка
|
||||
используется для трёх сценариев:
|
||||
The client calls this endpoint on every polling tick. The same endpoint serves
|
||||
three scenarios:
|
||||
|
||||
- сообщение "я жив";
|
||||
- регулярное обновление состояния;
|
||||
- отправка результата последней завершённой команды.
|
||||
- an "I'm alive" message;
|
||||
- a regular state update;
|
||||
- reporting the result of the last finished command.
|
||||
|
||||
### Request
|
||||
|
||||
@@ -45,19 +45,19 @@ Authorization: Bearer <client-token>
|
||||
}
|
||||
```
|
||||
|
||||
Поля:
|
||||
Fields:
|
||||
|
||||
- `client_id` - стабильный идентификатор, заданный при настройке клиента. Он не
|
||||
должен меняться при каждом рестарте.
|
||||
- `observed_at` - момент, когда клиент подготовил payload.
|
||||
- `client.hostname` - текущий hostname машины.
|
||||
- `client.platform` - платформа клиента. Желательно использовать названия,
|
||||
близкие к Python/platform: `linux`, `darwin`, `windows`.
|
||||
- `client.version` - версия nexus-sync client.
|
||||
- `state` - намеренно маленький объект. Может быть сюда позже можно добавить IP,
|
||||
disk usage, memory, battery status и другие метрики.
|
||||
- `last_command_result` - `null`, если клиенту нечего нового сообщать о
|
||||
выполнении команды.
|
||||
- `client_id` - a stable identifier set during client setup. It must not change
|
||||
on every restart.
|
||||
- `observed_at` - the moment the client prepared the payload.
|
||||
- `client.hostname` - the machine's current hostname.
|
||||
- `client.platform` - the client platform. Prefer names close to
|
||||
Python/platform: `linux`, `darwin`, `windows`.
|
||||
- `client.version` - the nexus-sync client version.
|
||||
- `state` - an intentionally small object. IP, disk usage, memory, battery
|
||||
status and other metrics may be added here later.
|
||||
- `last_command_result` - `null` if the client has nothing new to report about
|
||||
command execution.
|
||||
|
||||
### Request with command result
|
||||
|
||||
@@ -86,17 +86,16 @@ Authorization: Bearer <client-token>
|
||||
}
|
||||
```
|
||||
|
||||
Поля результата:
|
||||
Result fields:
|
||||
|
||||
- `command_id` должен совпадать с id команды, которую сервер ранее вернул
|
||||
клиенту.
|
||||
- `status` принимает одно из значений: `succeeded`, `failed`, `timed_out`,
|
||||
`rejected`.
|
||||
- `return_code` - exit code процесса, если процесс был запущен. Для
|
||||
`timed_out` или `rejected` поле может быть `null`, если финального exit code
|
||||
нет.
|
||||
- `stdout` и `stderr` клиент должен ограничивать по размеру перед отправкой.
|
||||
Конкретный лимит байт в этом контракте пока не фиксируется.
|
||||
- `command_id` must match the id of the command the server previously returned
|
||||
to the client.
|
||||
- `status` takes one of: `succeeded`, `failed`, `timed_out`, `rejected`.
|
||||
- `return_code` - the process exit code, if the process was started. For
|
||||
`timed_out` or `rejected` the field may be `null` when there is no final exit
|
||||
code.
|
||||
- `stdout` and `stderr` must be size-limited by the client before sending. This
|
||||
contract does not yet fix a specific byte limit.
|
||||
|
||||
### Response without command
|
||||
|
||||
@@ -126,36 +125,37 @@ Authorization: Bearer <client-token>
|
||||
}
|
||||
```
|
||||
|
||||
Поля команды:
|
||||
Command fields:
|
||||
|
||||
- `id` генерируется сервером и должен быть уникальным.
|
||||
- `kind` описывает тип executor. Пока определён только `exec`.
|
||||
- `name` - имя command preset.
|
||||
- `args` содержит аргументы, специфичные для конкретного preset.
|
||||
- `timeout_seconds` - максимальное время выполнения, которое сервер допускает
|
||||
для этой команды.
|
||||
- `id` is generated by the server and must be unique.
|
||||
- `kind` describes the executor type. Only `exec` is defined so far.
|
||||
- `name` - the command preset name.
|
||||
- `args` holds arguments specific to a particular preset.
|
||||
- `timeout_seconds` - the maximum execution time the server allows for this
|
||||
command.
|
||||
|
||||
Клиент обязан выполнять только те команды, которые он знает и локально
|
||||
разрешает. Неизвестные или запрещённые команды нужно возвращать как `rejected`.
|
||||
The client must run only commands it knows and locally allows. Unknown or
|
||||
forbidden commands must be returned as `rejected`.
|
||||
|
||||
## Server-side API
|
||||
|
||||
Эти ручки нужны серверной части/админке, чтобы видеть клиентов и ставить им
|
||||
команды в очередь. Клиенты напрямую используют только heartbeat.
|
||||
These endpoints are for the server/admin side, to see clients and queue commands
|
||||
for them. Clients directly use only the heartbeat.
|
||||
|
||||
### `GET /api/v1/server/clients`
|
||||
|
||||
Возвращает список известных клиентов с последними heartbeat-данными и
|
||||
Returns the list of known clients with their latest heartbeat data and
|
||||
`available_commands`.
|
||||
|
||||
### `GET /api/v1/server/clients/{client_id}`
|
||||
|
||||
Возвращает одного клиента или `404`, если сервер ещё не видел этот `client_id`.
|
||||
Returns a single client, or `404` if the server has not seen this `client_id`
|
||||
yet.
|
||||
|
||||
### `POST /api/v1/server/clients/{client_id}/commands`
|
||||
|
||||
Создаёт pending-команду для клиента. Клиент получит её на следующем heartbeat.
|
||||
Эта ручка принимает имя команды напрямую.
|
||||
Creates a pending command for the client. The client receives it on its next
|
||||
heartbeat. This endpoint accepts the command name directly.
|
||||
|
||||
Request:
|
||||
|
||||
@@ -188,66 +188,66 @@ Response:
|
||||
|
||||
### `GET /api/v1/server/commands/{command_id}`
|
||||
|
||||
Возвращает команду и, если клиент уже отчитался, поле `result`.
|
||||
Returns the command and, if the client has already reported, the `result` field.
|
||||
|
||||
## Command lifecycle
|
||||
|
||||
Жизненный цикл команды:
|
||||
Command lifecycle:
|
||||
|
||||
1. `pending`: команда создана на сервере и ещё не доставлена клиенту.
|
||||
2. `delivered`: команда была возвращена клиенту в heartbeat response.
|
||||
3. `succeeded`: клиент сообщил об успешном выполнении.
|
||||
4. `failed`: клиент сообщил об ошибке выполнения.
|
||||
5. `timed_out`: клиент сообщил о timeout.
|
||||
6. `rejected`: клиент отказался выполнять команду.
|
||||
1. `pending`: the command was created on the server and not yet delivered to the
|
||||
client.
|
||||
2. `delivered`: the command was returned to the client in a heartbeat response.
|
||||
3. `succeeded`: the client reported successful execution.
|
||||
4. `failed`: the client reported an execution error.
|
||||
5. `timed_out`: the client reported a timeout.
|
||||
6. `rejected`: the client refused to run the command.
|
||||
|
||||
Терминальные статусы: `succeeded`, `failed`, `timed_out`, `rejected`.
|
||||
Terminal statuses: `succeeded`, `failed`, `timed_out`, `rejected`.
|
||||
|
||||
## HTTP statuses
|
||||
|
||||
Heartbeat endpoint должен использовать такие HTTP-статусы:
|
||||
The heartbeat endpoint should use these HTTP statuses:
|
||||
|
||||
- `200 OK`: heartbeat принят; тело ответа соответствует контракту выше.
|
||||
- `400 Bad Request`: некорректный JSON или невалидные значения полей.
|
||||
- `401 Unauthorized`: bearer token отсутствует или невалиден.
|
||||
- `403 Forbidden`: token валиден, но не имеет права действовать как этот
|
||||
- `200 OK`: heartbeat accepted; the response body matches the contract above.
|
||||
- `400 Bad Request`: malformed JSON or invalid field values.
|
||||
- `401 Unauthorized`: the bearer token is missing or invalid.
|
||||
- `403 Forbidden`: the token is valid but not allowed to act as this
|
||||
`client_id`.
|
||||
- `409 Conflict`: результат ссылается на неизвестную, уже терминальную или
|
||||
несовместимую команду.
|
||||
- `429 Too Many Requests`: клиент опрашивает сервер слишком часто.
|
||||
- `500 Internal Server Error`: неожиданная ошибка сервера.
|
||||
- `409 Conflict`: the result references an unknown, already terminal, or
|
||||
incompatible command.
|
||||
- `429 Too Many Requests`: the client polls the server too often.
|
||||
- `500 Internal Server Error`: an unexpected server error.
|
||||
|
||||
Состояние выполнения команды выражается полями в JSON, а не HTTP-ошибками.
|
||||
Например, команда с exit code `1` всё равно отправляется через успешный
|
||||
Command execution state is expressed via JSON fields, not HTTP errors. For
|
||||
example, a command with exit code `1` is still delivered over a successful
|
||||
heartbeat request.
|
||||
|
||||
## Polling rules
|
||||
|
||||
Ответ сервера содержит `next_poll_after_seconds`.
|
||||
The server response contains `next_poll_after_seconds`.
|
||||
|
||||
Поведение:
|
||||
Behavior:
|
||||
|
||||
- обычный polling interval без команды: 60 секунд;
|
||||
- polling interval после получения команды: 10 секунд;
|
||||
- клиентский минимальный interval: 5 секунд;
|
||||
- клиентский максимальный interval: 300 секунд.
|
||||
- normal polling interval without a command: 60 seconds;
|
||||
- polling interval after receiving a command: 10 seconds;
|
||||
- client minimum interval: 5 seconds;
|
||||
- client maximum interval: 300 seconds.
|
||||
|
||||
Клиент должен воспринимать значение сервера как рекомендацию и зажимать его в
|
||||
локальные min/max границы.
|
||||
The client should treat the server value as a recommendation and clamp it to its
|
||||
local min/max bounds.
|
||||
|
||||
## Security constraints
|
||||
|
||||
Необходимо соблюдать эти ограничения:
|
||||
The following constraints must be respected:
|
||||
|
||||
- не выполнять произвольные shell-строки, полученные от сервера;
|
||||
- выполнять только локально известные command presets;
|
||||
- требовать bearer token для клиентских endpoint'ов;
|
||||
- включать `command_id` в каждый результат, чтобы не было неоднозначного
|
||||
сопоставления;
|
||||
- хранить command output как логи, а не как доверенные управляющие данные;
|
||||
- ограничивать размер command output перед отправкой на сервер;
|
||||
- выполнять каждую команду с timeout.
|
||||
- do not run arbitrary shell strings received from the server;
|
||||
- run only locally known command presets;
|
||||
- require a bearer token for client endpoints;
|
||||
- include `command_id` in every result to avoid ambiguous matching;
|
||||
- store command output as logs, not as trusted control data;
|
||||
- limit the size of command output before sending it to the server;
|
||||
- run every command with a timeout.
|
||||
|
||||
Эти ограничения намеренно являются частью контракта, потому что проект
|
||||
занимается удалённым управлением машинами. Дешевле строить первую реализацию
|
||||
вокруг них, чем добавлять их задним числом.
|
||||
These constraints are intentionally part of the contract because the project
|
||||
deals with remote machine management. It is cheaper to build the first
|
||||
implementation around them than to add them after the fact.
|
||||
|
||||
Reference in New Issue
Block a user