Refactor environment and configuration management
- Updated the project structure to store configuration files (.env, models.yaml, extensions.yaml) in the project root instead of the user's home directory. - Enhanced the setup process to automatically copy example files to the project root on first run. - Implemented a migration function to transfer legacy configuration files from the user's home directory to the new project structure. - Revised documentation to reflect changes in file locations and setup instructions. - Improved code readability and maintainability by refactoring path management functions.
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
│ gpu-rent CLI │
|
||||
│ up / stop / status / doctor / hold │
|
||||
│ tunnel / open — SSH localhost:17801 → VM :7801 │
|
||||
│ state ~/.gpu-rent/state.json │
|
||||
│ state <repo>/.gpu-rent/state.json │
|
||||
│ │
|
||||
│ браузер / MCP / curl API → http://127.0.0.1:17801 │
|
||||
│ локальный SwarmUI → http://127.0.0.1:7801 (не трогаем)
|
||||
@@ -169,5 +169,5 @@ Reconcile: сервер с тегом `gpu-rent` есть, локального
|
||||
| --- | --- |
|
||||
| Python 3.11+ | openstacksdk, paramiko, Typer, Rich, questionary, dotenv |
|
||||
| SSH | paramiko + sshtunnel (Windows без системного `ssh -L`) |
|
||||
| Конфиг | `%USERPROFILE%\.gpu-rent\.env` |
|
||||
| Конфиг | `<repo>/.env` + runtime в `<repo>/.gpu-rent/` |
|
||||
| Лицензия | MIT |
|
||||
|
||||
+4
-4
@@ -48,7 +48,7 @@
|
||||
3. Квота GPU > 0; иначе текст «напишите в поддержку Selectel».
|
||||
4. В сегменте есть хотя бы один flavor из `FLAVOR_PREFERENCE` (не `disabled`).
|
||||
5. Volume type сегмента существует; data 100 GB влезает в квоту дисков.
|
||||
6. SSH-ключ: есть `~/.gpu-rent/id_ed25519` или CLI сможет его создать.
|
||||
6. SSH-ключ: есть `<repo>/.gpu-rent/id_ed25519` или CLI сможет его создать.
|
||||
7. Если задан `CIVITAI_API_TOKEN` — HEAD/лёгкий запрос к `CIVITAI_API_HOST` (дефолт `.red`); манифест парсится.
|
||||
8. `extensions.yaml` парсится, если файл есть.
|
||||
9. Локальные папки: предупреждение, если `Models/` огромный относительно свободного места на будущем диске.
|
||||
@@ -98,7 +98,7 @@ Hold killer: gpu-rent hold
|
||||
|
||||
## Конфигурация
|
||||
|
||||
`%USERPROFILE%\.gpu-rent\.env` / `~/.gpu-rent/.env`:
|
||||
`.env` в корне репозитория (рядом с `env.example`):
|
||||
|
||||
```env
|
||||
OS_AUTH_URL=https://cloud.api.selcloud.ru/identity/v3
|
||||
@@ -154,7 +154,7 @@ Application credential для idle-killer CLI создаёт при bootstrap и
|
||||
|
||||
## State
|
||||
|
||||
`~/.gpu-rent/state.json` — ids, фаза (`idle` / `ready_cloud` / `ready_tunneled` / …), flavor, timestamps create/unshelve (для окна 24 ч). Без паролей. Lockfile, чтобы два `up` не создали два сервера.
|
||||
`<repo>/.gpu-rent/state.json` — ids, фаза (`idle` / `ready_cloud` / `ready_tunneled` / …), flavor, timestamps create/unshelve (для окна 24 ч). Без паролей. Lockfile там же, чтобы два `up` не создали два сервера.
|
||||
|
||||
## Ожидание готовности
|
||||
|
||||
@@ -168,6 +168,6 @@ Application credential для idle-killer CLI создаёт при bootstrap и
|
||||
|
||||
## Windows
|
||||
|
||||
Лаунчеры в корне: `gpu-rent.bat` (cmd / двойной клик), `.\gpu-rent.ps1` (PowerShell). На Unix — `./gpu-rent.sh`. Они создают `.venv` в репозитории и вызывают `python -m gpu_rent`. Пути в приложении через `Path.expanduser`. Ключ генерирует CLI: `~/.gpu-rent/id_ed25519`.
|
||||
Лаунчеры в корне: `gpu-rent.bat` (cmd / двойной клик), `.\gpu-rent.ps1` (PowerShell). На Unix — `./gpu-rent.sh`. Они создают `.venv` в репозитории и вызывают `python -m gpu_rent`. Ключ генерирует CLI: `<repo>/.gpu-rent/id_ed25519`.
|
||||
|
||||
`NOTIFY_READY`: toast через WinRT / `win10toast` (что заработает на 10/11 без админ-прав) + системный звук. Если toast недоступен — только звук и лог, не падать.
|
||||
|
||||
+4
-3
@@ -8,8 +8,8 @@
|
||||
| Сессия | GPU живёт до `stop` **или** простоя (idle-killer **на VM**). Ноут можно закрыть — compute не обязан умереть |
|
||||
| Модели | Пустой `./Models` → не грузим ничего. Появились веса + метадата → на `up` выгрузить эту пару. Civitai-seed отдельно. С сервера не удаляем |
|
||||
| Civitai хост | Дефолт API `civitai.red` (полный каталог). `.com` — SFW-витрина, NSFW с неё часто 404. Ссылки `.com`/`.red`/`.green` в манифесте принимаем. 404 → один retry на второй хост. Один токен на оба домена |
|
||||
| Манифест моделей | `~/.gpu-rent/models.yaml`, типы: checkpoint / lora / vae / embedding / controlnet / upscaler. В git только `models.example.yaml` |
|
||||
| Расширения | `~/.gpu-rent/extensions.yaml`: git-репы `swarmui` → `src/Extensions`, `comfy` → DLNodes. Клон на первом bootstrap до старта UI. Пустой файл — стоковый SwarmUI |
|
||||
| Манифест моделей | `<repo>/models.yaml`, типы: checkpoint / lora / vae / embedding / controlnet / upscaler. В git только `models.example.yaml` |
|
||||
| Расширения | `<repo>/extensions.yaml`: git-репы `swarmui` → `src/Extensions`, `comfy` → DLNodes. Клон на первом bootstrap до старта UI. Пустой файл — стоковый SwarmUI |
|
||||
| Autocomplete | До первого старта: скачать word-list в `Data/Autocompletions`, прописать `DefaultUser.AutoComplete.Source`. На каждом `up` сверить GitHub blob sha и обновить файл, если изменился. Дефолт: `tags/danbooru.csv` из a1111-sd-webui-tagcomplete (как в доке SwarmUI) |
|
||||
| Доступ | Браузер на туннеле; MCP переключается на облако, пока оно живо; HTTP API SwarmUI через тот же туннель |
|
||||
| Preemptible | По умолчанию всегда. Обычный сервер — только `--no-spot` |
|
||||
@@ -20,7 +20,8 @@
|
||||
| Льгота после boot | Killer молчит во время clone/seed/push, hold, качалки в UI SwarmUI, пока backend не Idle, и 45 мин после ACTIVE/unshelve |
|
||||
| `up` / `tunnel` | Разделены: `up` только облако, `tunnel` отдельно. Ctrl+C на туннеле не удаляет VM |
|
||||
| Data-диск | Старт **100 GB**, рост через resize вверх (вниз Selectel не умеет) |
|
||||
| SSH | CLI генерирует `~/.gpu-rent/id_ed25519` без passphrase и сам регистрирует keypair |
|
||||
| SSH | CLI генерирует `<repo>/.gpu-rent/id_ed25519` без passphrase и сам регистрирует keypair |
|
||||
| Локальные файлы | Всё в корне репозитория: `.env`, `models.yaml`, `extensions.yaml`; runtime (`state.json`, lock, SSH) в `<repo>/.gpu-rent/`. Не `%USERPROFILE%\.gpu-rent` |
|
||||
| Локальный порт | **17801** |
|
||||
| MCP-конфиг Cursor | Только сниппет в stdout, файл не трогаем |
|
||||
| `ready` для API | Ждать Idle backend, не только HTTP UI |
|
||||
|
||||
+3
-3
@@ -13,7 +13,7 @@
|
||||
|
||||
## Манифест
|
||||
|
||||
Пример: [`extensions.example.yaml`](../extensions.example.yaml). Рабочая копия: `~/.gpu-rent/extensions.yaml` (или `EXTENSIONS_MANIFEST`).
|
||||
Пример: [`extensions.example.yaml`](../extensions.example.yaml). Рабочая копия: `extensions.yaml` в корне репо (или `EXTENSIONS_MANIFEST`).
|
||||
|
||||
```yaml
|
||||
swarmui:
|
||||
@@ -52,7 +52,7 @@ Idle-killer ещё не вооружён. Git нужен на VM (`apt` в boots
|
||||
Публичный HTTPS без секретов. Приватный репозиторий:
|
||||
|
||||
- `GIT_TOKEN` в `.env` (GitHub: `x-access-token`; GitLab: `oauth2` / PAT). CLI подставляет в URL **только на VM**, не пишет токен в yaml и не в cloud-init.
|
||||
- Либо отдельный deploy key `~/.gpu-rent/git_deploy` — v1.1, не обязательно сейчас.
|
||||
- Либо отдельный deploy key `<repo>/.gpu-rent/git_deploy` — v1.1, не обязательно сейчас.
|
||||
|
||||
Не использовать `git://`. Только `https://` и `git@` + ключ.
|
||||
|
||||
@@ -63,6 +63,6 @@ Idle-killer ещё не вооружён. Git нужен на VM (`apt` в boots
|
||||
## Конфиг
|
||||
|
||||
```env
|
||||
EXTENSIONS_MANIFEST= # пусто = ~/.gpu-rent/extensions.yaml
|
||||
EXTENSIONS_MANIFEST= # пусто = <repo>/extensions.yaml
|
||||
GIT_TOKEN= # опционально, для приватных https
|
||||
```
|
||||
|
||||
+9
-15
@@ -67,27 +67,21 @@ ComfyUI в `dlbackend` качается всегда. Речь только о *
|
||||
|
||||
## Манифест
|
||||
|
||||
Пример в репозитории: [`models.example.yaml`](../models.example.yaml). Рабочая копия: `~/.gpu-rent/models.yaml` (или путь `MODELS_MANIFEST`).
|
||||
Пример в репозитории: [`models.example.yaml`](../models.example.yaml). Рабочая копия: `models.yaml` в корне репо (или путь `MODELS_MANIFEST`).
|
||||
|
||||
Идентификатор — **Civitai model version id**, не имя файла и не «последняя версия модели» (она плывёт).
|
||||
|
||||
```yaml
|
||||
# ~/.gpu-rent/models.yaml
|
||||
# models.yaml — пример: Krea 2 + LoRA (см. models.example.yaml)
|
||||
checkpoint:
|
||||
- version_id: 2514310
|
||||
- url: https://civitai.red/models/2786499/realism-by-stable-yogi-krea2?modelVersionId=3231611
|
||||
lora:
|
||||
- version_id: 123456
|
||||
vae:
|
||||
- version_id: 789012
|
||||
embedding:
|
||||
- version_id: 111
|
||||
controlnet:
|
||||
- version_id: 222
|
||||
upscaler:
|
||||
- version_id: 333
|
||||
- url: https://civitai.red/models/2268008/realistic-snapshot-z-image-turbo-krea-2?modelVersionId=3084537
|
||||
- url: https://civitai.red/models/2187487/cutifyier?modelVersionId=3107521
|
||||
- url: https://civitai.red/models/1134895/2000s-analog-core?modelVersionId=3103914
|
||||
```
|
||||
|
||||
Допустимо вместо `version_id` поле `url` страницы модели/версии — CLI вынимает id. Хосты `civitai.com`, `civitai.red`, `civitai.green` равнозначны (зелёный редиректит на `.com`). Несколько файлов у версии: берём `files[]` с `"primary": true`, иначе SafeTensor / fp16.
|
||||
Допустимо вместо `url` поле `version_id` (число из `modelVersionId=`). Хосты `civitai.com`, `civitai.red`, `civitai.green` равнозначны (зелёный редиректит на `.com`). Несколько файлов у версии: берём `files[]` с `"primary": true`, иначе SafeTensor / fp16.
|
||||
|
||||
Типы манифеста → каталоги SwarmUI (`ModelRoot` = `Models`):
|
||||
|
||||
@@ -103,7 +97,7 @@ upscaler:
|
||||
|
||||
Тип в yaml задаёт **куда класть**, даже если Civitai назвал иначе. Если API-тип совсем другой — предупреждение, кладём по yaml.
|
||||
|
||||
В git не коммитить рабочий манифест с личными чекпоинтами. В примере — вымышленные id.
|
||||
В git не коммитить рабочий манифест с личными чекпоинтами. В `models.example.yaml` — стартовый набор Krea 2 (чекпоинт + три LoRA); скопируй и дополни под себя.
|
||||
|
||||
## Civitai API (.com / .red)
|
||||
|
||||
@@ -169,6 +163,6 @@ REST не раздвоился: те же `/api/v1/...` на обоих хост
|
||||
```env
|
||||
CIVITAI_API_TOKEN=
|
||||
CIVITAI_API_HOST=civitai.red # полный каталог; civitai.com = только SFW
|
||||
MODELS_MANIFEST= # пусто = ~/.gpu-rent/models.yaml
|
||||
MODELS_MANIFEST= # пусто = <repo>/models.yaml
|
||||
LOCAL_MODELS_DIR= # пусто = <корень приложения>/Models
|
||||
```
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@
|
||||
- [ ] `status`: диск used/free, ₽/час, TTL preempt 24 ч, killer/hold
|
||||
- [x] Второй `up` не создаёт второй GPU
|
||||
- [ ] `resize-data` вверх
|
||||
- [x] Генерация `~/.gpu-rent/id_ed25519` + keypair при первом `up`
|
||||
- [x] Генерация `<repo>/.gpu-rent/id_ed25519` + keypair при первом `up`
|
||||
- [x] `seed-models` на живом диске (идемпотентно, SHA256)
|
||||
- [x] `push` / `push-models`: `Models/`, `Wildcards/`, `CustomWorkflows/`
|
||||
- [x] `pull-output` и `PULL_OUTPUT` на `stop` / повторный `up`
|
||||
|
||||
+9
-8
@@ -26,7 +26,9 @@ chmod +x gpu-rent.sh
|
||||
./gpu-rent.sh --help
|
||||
```
|
||||
|
||||
Первый запуск копирует `env.example` в `%USERPROFILE%\.gpu-rent\.env` / `~/.gpu-rent/.env`, если файла ещё нет. Заполни `OS_*` (шаги ниже). После `git pull`, если изменился `pyproject.toml`, лаунчер переустановит пакет.
|
||||
Первый запуск копирует `env.example` → `.env`, `models.example.yaml` → `models.yaml`, `extensions.example.yaml` → `extensions.yaml` в **корне репозитория**, если файлов ещё нет. Заполни `OS_*` в `.env` (шаги ниже). После `git pull`, если изменился `pyproject.toml`, лаунчер переустановит пакет.
|
||||
|
||||
Секреты и runtime не уезжают в `%USERPROFILE%`: только `<repo>/.env` и `<repo>/.gpu-rent/` (state, SSH-ключ). Оба в `.gitignore`. Если раньше лежало в `~\.gpu-rent\`, CLI один раз перенесёт в проект.
|
||||
|
||||
Ручной венв по желанию (для разработки / pytest):
|
||||
|
||||
@@ -129,9 +131,8 @@ python -m gpu_rent --help
|
||||
Создай каталог и файл **вне git**:
|
||||
|
||||
```powershell
|
||||
mkdir $env:USERPROFILE\.gpu-rent
|
||||
copy env.example $env:USERPROFILE\.gpu-rent\.env
|
||||
notepad $env:USERPROFILE\.gpu-rent\.env
|
||||
copy env.example .env
|
||||
notepad .env
|
||||
```
|
||||
|
||||
Вставь значения из RC + пароль + `GPU_RENT_AZ`. Никогда не коммить `.env`.
|
||||
@@ -163,7 +164,7 @@ openstack flavor list
|
||||
Манифест (не в git со своими id, если не хочешь светить вкусы):
|
||||
|
||||
```powershell
|
||||
copy models.example.yaml $env:USERPROFILE\.gpu-rent\models.yaml
|
||||
copy models.example.yaml models.yaml
|
||||
```
|
||||
|
||||
`version_id: 0` — заглушка, doctor её игнорирует. Нужен **modelVersionId** из URL, не id карточки модели.
|
||||
@@ -180,13 +181,13 @@ copy models.example.yaml $env:USERPROFILE\.gpu-rent\models.yaml
|
||||
2. Fine-grained: доступ только к нужным репам, **Contents: Read**.
|
||||
3. `GIT_TOKEN` в `.env`.
|
||||
|
||||
Скопируй шаблон: `extensions.example.yaml` → `~\.gpu-rent\extensions.yaml`. Пустой файл = стоковый SwarmUI.
|
||||
Скопируй шаблон: `extensions.example.yaml` → `extensions.yaml` в корне репо. Пустой файл = стоковый SwarmUI.
|
||||
|
||||
---
|
||||
|
||||
## 6. SSH
|
||||
|
||||
Ключ **не надо** делать руками. CLI создаст `~\.gpu-rent\id_ed25519` без passphrase и зарегистрирует keypair в OpenStack при первом `up`. `doctor` только проверяет, что это получится.
|
||||
Ключ **не надо** делать руками. CLI создаст `<repo>\.gpu-rent\id_ed25519` без passphrase и зарегистрирует keypair в OpenStack при первом `up`. `doctor` только проверяет, что это получится.
|
||||
|
||||
---
|
||||
|
||||
@@ -197,7 +198,7 @@ copy models.example.yaml $env:USERPROFILE\.gpu-rent\models.yaml
|
||||
- [ ] Тикет на лимит **1× GPU** в нужном сегменте (или квота уже > 0)
|
||||
- [ ] Сервисный пользователь `member` на этот проект, пароль сохранён
|
||||
- [ ] RC скачан на **тот же пул**, где GPU
|
||||
- [ ] `~\.gpu-rent\.env` заполнен (`OS_*` + `GPU_RENT_AZ`)
|
||||
- [ ] `.env` в корне репо заполнен (`OS_*` + `GPU_RENT_AZ`)
|
||||
- [ ] Нет `X-Token` вместо пароля сервисного пользователя
|
||||
- [ ] (опционально) Civitai token + `models.yaml`
|
||||
- [ ] На балансе хватает на диск 100 GB **даже когда GPU выключен**
|
||||
|
||||
Reference in New Issue
Block a user