# CLI и конфигурация Имя команды: `gpu-rent`. Windows и Linux. Лицензия MIT, в репозитории нет секретов и имён личных чекпоинтов. ## Команды | Команда | Поведение | | --- | --- | | `gpu-rent doctor` | Preflight **без** create: Keystone, квота GPU, flavor в AZ, диски, Civitai token+`.red`, манифесты, SSH-ключ. Код выхода ≠ 0, если сессию нельзя начать | | `gpu-rent up` | Preflight → create/unshelve (с фоллбеком flavor) → extensions → autocomplete → Civitai seed → push локальных папок → ждать UI → toast/звук | | `gpu-rent up --no-spot` | Обычный (не preemptible) сервер | | `gpu-rent up --flavor … --yes` | Без вопросов. `--flavor` бьёт список фоллбека. `--yes` без `--flavor` берёт первый доступный из `FLAVOR_PREFERENCE` | | `gpu-rent tunnel` | SSH-проброс `localhost:17801` → VM `:7801`. Блокируется. Ctrl+C = закрыть туннель, GPU **оставить** | | `gpu-rent tunnel --open` | Туннель + сразу открыть браузер на 17801 | | `gpu-rent open` | Открыть браузер на `http://127.0.0.1:17801`. Туннель уже должен слушать порт | | `gpu-rent status` | State + Nova + диск used/free + ₽/час + сколько до 24 ч preempt + killer/hold. Туннель не обязателен | | `gpu-rent hold` | Отложить idle-killer на `IDLE_MINUTES` от сейчас | | `gpu-rent hold --minutes 90` | Hold до now+90 мин (заменяет предыдущий, не складывает) | | `gpu-rent hold --until ` | Hold до абсолютного времени | | `gpu-rent hold --clear` | Снять hold | | `gpu-rent stop` | Optional pull Output → удалить compute и FIP, диски оставить. С любой машины с `.env` | | `gpu-rent stop --no-pull` | Не тянуть Output, даже если `PULL_OUTPUT=true` | | `gpu-rent destroy` | `stop` + диски, только `--i-understand-data-loss` | | `gpu-rent logs` | journalctl swarmui / cloud-init по SSH | | `gpu-rent ssh` | Оболочка на VM | | `gpu-rent seed-models` | Докачать новые строки манифеста Civitai на уже существующий диск | | `gpu-rent push` | Инкремент `Models/` + `Wildcards/` + `CustomWorkflows/` (пустые skip) | | `gpu-rent push-models` | Только `./Models` | | `gpu-rent pull-output` | Забрать новые файлы с VM `Output/` в `./Output` (сервер не чистим) | | `gpu-rent seed-extensions` | Доклонировать/обновить git-репы; если VM жива — `systemctl restart swarmui` | | `gpu-rent resize-data --gb 400` | Увеличить data volume вверх (Selectel online resize). Вниз нельзя | | `gpu-rent dry-run` | План без mutating-вызовов | Второй `up` при живой VM: не создавать второй GPU; сделать autocomplete-check и **push** локальных папок; если `PULL_OUTPUT` — подтянуть Output; напомнить про `tunnel` / `stop`. `--adopt` если нашли тег без state. Нет команды `generate`. Нет зеркала каталога локального SwarmUI — только папки приложения, см. [local-folders.md](local-folders.md). Сейчас в коде: `up` создаёт compute, идемпотентный bootstrap (без Docker), **затем** git-расширения, autocomplete, Civitai-seed и push локальных папок, и только потом `systemctl start swarmui`. `tunnel` на 17801. Ещё нет: idle-killer, snapshot, hold, EXPIRED-reconnect туннеля. ## `doctor` Не создаёт сервер, не тратит GPU. Нужен до первого `up` и когда «вчера работало». Проверки по порядку, все печатаются (не падать на первой, собрать отчёт): 1. Читается `.env`, обязательные `OS_*`. 2. Keystone: токен выдаётся. 3. Квота GPU > 0; иначе текст «напишите в поддержку Selectel». 4. В сегменте есть хотя бы один flavor из `FLAVOR_PREFERENCE` (не `disabled`). 5. Volume type сегмента существует; data 100 GB влезает в квоту дисков. 6. SSH-ключ: есть `/.gpu-rent/id_ed25519` или CLI сможет его создать. 7. Если задан `CIVITAI_API_TOKEN` — HEAD/лёгкий запрос к `CIVITAI_API_HOST` (дефолт `.red`); манифест парсится. 8. `extensions.yaml` парсится, если файл есть. 9. Локальные папки: предупреждение, если `Models/` огромный относительно свободного места на будущем диске. Exit 0 — можно `up`. Exit 1 — нельзя, причина в отчёте. ## `status` Без туннеля. Если SSH есть — ещё диск и killer; если нет — только OpenStack. | Поле | Откуда | | --- | --- | | Фаза state / Nova status | `state.json` + compute | | Flavor, ₽/час | extra specs / оценка с spike; нет цены в API — «см. панель», не выдумывать | | Preempt window | create/unshelve timestamp + 24 ч; «осталось Hh Mm» или «не preemptible» | | Data disk used/free | SSH `df` на `/mnt/swarm_data` | | Idle-killer | armed / grace до … / hold до … / busy (очередь или качалка) / слеп (нет кредов) | | Туннель | слушает ли локальный 17801 | | Snapshot boot | есть ли `gpu-rent-boot-ok` | ## `hold` Пишет на VM `/mnt/swarm_data/.gpu-rent-hold-until` (unix ts). Killer не удаляет compute, пока `now < ts`. Нужен SSH и живой сервер. Без VM — ошибка, не «запомню на потом». После `unshelve` hold-файл на диске сохраняется. ## Что печатать при `up` 1. Preflight (тот же набор, что `doctor`, можно вызвать его внутри). 2. Если квота 0 — стоп с текстом «напишите в поддержку Selectel», не traceback. 3. Выбранный flavor (или фоллбек) + оценка: GPU ₽/час, диск ₽/мес, preemptible 24 ч, idle-killer через N мин. 4. Фазы: provisioning → bootstrap → clone extensions → autocomplete → seed Civitai → push локальных папок → waiting UI → backend Idle. 5. Если `NOTIFY_READY` — Windows toast + звук (и строка в лог). 6. Готово: ```text SwarmUI на VM: 127.0.0.1:7801 (только через туннель) Локально: gpu-rent tunnel Браузер: gpu-rent open → http://127.0.0.1:17801 API: http://127.0.0.1:17801/API/ MCP: http://127.0.0.1:17801/mcp Hold killer: gpu-rent hold Стоп GPU: gpu-rent stop ``` Сниппет MCP для Cursor — в stdout, `mcp.json` не редактировать. ## Конфигурация `.env` в корне репозитория (рядом с `env.example`): ```env OS_AUTH_URL=https://cloud.api.selcloud.ru/identity/v3 OS_USER_DOMAIN_NAME= OS_USERNAME= OS_PASSWORD= OS_PROJECT_ID= OS_REGION_NAME=ru-7 GPU_RENT_AZ=ru-7a SSH_PRIVATE_KEY_PATH= SSH_USER=ubuntu BOOT_VOLUME_ID= DATA_VOLUME_ID= DATA_VOLUME_SIZE_GB=100 BOOT_SNAPSHOT_NAME=gpu-rent-boot-ok CIVITAI_API_TOKEN= CIVITAI_API_HOST=civitai.red MODELS_MANIFEST= LOCAL_MODELS_DIR= LOCAL_WILDCARDS_DIR= LOCAL_WORKFLOWS_DIR= LOCAL_OUTPUT_DIR= EXTENSIONS_MANIFEST= GIT_TOKEN= AUTOCOMPLETE_ENABLED=true AUTOCOMPLETE_GITHUB_REPO=DominikDoom/a1111-sd-webui-tagcomplete AUTOCOMPLETE_GITHUB_PATH=tags/danbooru.csv AUTOCOMPLETE_GITHUB_REF=main AUTOCOMPLETE_FILENAME=danbooru.csv SWARMUI_LOCAL_PORT=17801 DEFAULT_FLAVOR_ID= FLAVOR_PREFERENCE=4090-24,4090-48,a5000,a100-40 FLAVOR_FALLBACK=true DEFAULT_SPOT=true KEEP_FLOATING_IP=false IDLE_MINUTES=30 IDLE_GRACE_MINUTES=45 PULL_OUTPUT=false NOTIFY_READY=true ``` Flavor id в git не хардкодить. `FLAVOR_PREFERENCE` — ярлыки; реальные uuid резолвятся в сегменте. `FLAVOR_FALLBACK=false` — только `DEFAULT_FLAVOR_ID` / `--flavor`, без следующего в списке. Application credential для idle-killer CLI создаёт при bootstrap и кладёт на VM; в `.env` ноутбука его можно не дублировать. Пути локальных папок по умолчанию — каталоги в корне приложения: `Models/`, `Wildcards/`, `CustomWorkflows/`, `Output/`. ## State `/.gpu-rent/state.json` — ids, фаза (`idle` / `ready_cloud` / `ready_tunneled` / …), flavor, timestamps create/unshelve (для окна 24 ч). Без паролей. Lockfile там же, чтобы два `up` не создали два сервера. ## Ожидание готовности Потолок ~20–40 мин на первый bootstrap, ~5–10 мин на unshelve: 1. Nova `ACTIVE` 2. TCP 22 3. SSH: cloud-init или `systemctl is-active swarmui` 4. HTTP `http://127.0.0.1:7801` **на VM** (через SSH), не путать с локальным 7801 5. Для MCP/API / toast — дождаться Idle backend. ## Windows Лаунчеры в корне: `gpu-rent.bat` (cmd / двойной клик), `.\gpu-rent.ps1` (PowerShell). На Unix — `./gpu-rent.sh`. Они создают `.venv` в репозитории и вызывают `python -m gpu_rent`. Ключ генерирует CLI: `/.gpu-rent/id_ed25519`. `NOTIFY_READY`: toast через WinRT / `win10toast` (что заработает на 10/11 без админ-прав) + системный звук. Если toast недоступен — только звук и лог, не падать.