first commit
This commit is contained in:
@@ -0,0 +1,190 @@
|
||||
"""Load ~/.gpu-rent/.env. No secrets in git."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from gpu_rent.errors import ConfigError
|
||||
from gpu_rent.paths import (
|
||||
default_ssh_key_path,
|
||||
detect_app_root,
|
||||
env_path,
|
||||
home_dir,
|
||||
)
|
||||
|
||||
|
||||
def _as_bool(value: str | None, default: bool) -> bool:
|
||||
if value is None or value.strip() == "":
|
||||
return default
|
||||
return value.strip().lower() in {"1", "true", "yes", "on"}
|
||||
|
||||
|
||||
def _as_int(value: str | None, default: int) -> int:
|
||||
if value is None or value.strip() == "":
|
||||
return default
|
||||
return int(value)
|
||||
|
||||
|
||||
def _csv(value: str | None, default: tuple[str, ...]) -> tuple[str, ...]:
|
||||
if value is None or value.strip() == "":
|
||||
return default
|
||||
return tuple(part.strip() for part in value.split(",") if part.strip())
|
||||
|
||||
|
||||
@dataclass
|
||||
class Config:
|
||||
os_auth_url: str
|
||||
os_user_domain_name: str
|
||||
os_username: str
|
||||
os_password: str
|
||||
os_project_id: str
|
||||
os_region_name: str
|
||||
gpu_rent_az: str
|
||||
|
||||
ssh_private_key_path: Path
|
||||
ssh_user: str
|
||||
|
||||
boot_volume_id: str
|
||||
data_volume_id: str
|
||||
data_volume_size_gb: int
|
||||
boot_snapshot_name: str
|
||||
|
||||
civitai_api_token: str
|
||||
civitai_api_host: str
|
||||
models_manifest: Path
|
||||
extensions_manifest: Path
|
||||
git_token: str
|
||||
|
||||
local_models_dir: Path
|
||||
local_wildcards_dir: Path
|
||||
local_workflows_dir: Path
|
||||
local_output_dir: Path
|
||||
app_root: Path
|
||||
|
||||
autocomplete_enabled: bool
|
||||
autocomplete_github_repo: str
|
||||
autocomplete_github_path: str
|
||||
autocomplete_github_ref: str
|
||||
autocomplete_filename: str
|
||||
|
||||
swarmui_local_port: int
|
||||
swarmui_image: str
|
||||
|
||||
default_flavor_id: str
|
||||
flavor_preference: tuple[str, ...]
|
||||
flavor_fallback: bool
|
||||
default_spot: bool
|
||||
keep_floating_ip: bool
|
||||
idle_minutes: int
|
||||
idle_grace_minutes: int
|
||||
pull_output: bool
|
||||
notify_ready: bool
|
||||
|
||||
missing: list[str] = field(default_factory=list)
|
||||
|
||||
@property
|
||||
def auth_ok(self) -> bool:
|
||||
return not self.missing
|
||||
|
||||
|
||||
def _required(name: str) -> str:
|
||||
return (os.environ.get(name) or "").strip()
|
||||
|
||||
|
||||
def load_config(*, require_auth: bool = True) -> Config:
|
||||
home_dir().mkdir(parents=True, exist_ok=True)
|
||||
env_file = env_path()
|
||||
if env_file.is_file():
|
||||
load_dotenv(env_file, override=False)
|
||||
|
||||
app_root = detect_app_root()
|
||||
missing: list[str] = []
|
||||
required = (
|
||||
"OS_AUTH_URL",
|
||||
"OS_USER_DOMAIN_NAME",
|
||||
"OS_USERNAME",
|
||||
"OS_PASSWORD",
|
||||
"OS_PROJECT_ID",
|
||||
"OS_REGION_NAME",
|
||||
"GPU_RENT_AZ",
|
||||
)
|
||||
values = {name: _required(name) for name in required}
|
||||
for name, value in values.items():
|
||||
if not value:
|
||||
missing.append(name)
|
||||
|
||||
if require_auth and missing:
|
||||
raise ConfigError(
|
||||
"В ~/.gpu-rent/.env не хватает: "
|
||||
+ ", ".join(missing)
|
||||
+ ". Как заполнить: docs/setup.md (сервисный пользователь, не X-Token)."
|
||||
)
|
||||
|
||||
key_override = (os.environ.get("SSH_PRIVATE_KEY_PATH") or "").strip()
|
||||
ssh_key = Path(key_override).expanduser() if key_override else default_ssh_key_path()
|
||||
|
||||
models_manifest = Path(
|
||||
(os.environ.get("MODELS_MANIFEST") or "").strip() or (home_dir() / "models.yaml")
|
||||
).expanduser()
|
||||
extensions_manifest = Path(
|
||||
(os.environ.get("EXTENSIONS_MANIFEST") or "").strip()
|
||||
or (home_dir() / "extensions.yaml")
|
||||
).expanduser()
|
||||
|
||||
def _dir(env_name: str, folder: str) -> Path:
|
||||
raw = (os.environ.get(env_name) or "").strip()
|
||||
return Path(raw).expanduser() if raw else (app_root / folder)
|
||||
|
||||
return Config(
|
||||
os_auth_url=values["OS_AUTH_URL"] or "https://cloud.api.selcloud.ru/identity/v3",
|
||||
os_user_domain_name=values["OS_USER_DOMAIN_NAME"],
|
||||
os_username=values["OS_USERNAME"],
|
||||
os_password=values["OS_PASSWORD"],
|
||||
os_project_id=values["OS_PROJECT_ID"],
|
||||
os_region_name=values["OS_REGION_NAME"],
|
||||
gpu_rent_az=values["GPU_RENT_AZ"],
|
||||
ssh_private_key_path=ssh_key,
|
||||
ssh_user=(os.environ.get("SSH_USER") or "ubuntu").strip(),
|
||||
boot_volume_id=(os.environ.get("BOOT_VOLUME_ID") or "").strip(),
|
||||
data_volume_id=(os.environ.get("DATA_VOLUME_ID") or "").strip(),
|
||||
data_volume_size_gb=_as_int(os.environ.get("DATA_VOLUME_SIZE_GB"), 100),
|
||||
boot_snapshot_name=(os.environ.get("BOOT_SNAPSHOT_NAME") or "gpu-rent-boot-ok").strip(),
|
||||
civitai_api_token=(os.environ.get("CIVITAI_API_TOKEN") or "").strip(),
|
||||
civitai_api_host=(os.environ.get("CIVITAI_API_HOST") or "civitai.red").strip().lower(),
|
||||
models_manifest=models_manifest,
|
||||
extensions_manifest=extensions_manifest,
|
||||
git_token=(os.environ.get("GIT_TOKEN") or "").strip(),
|
||||
local_models_dir=_dir("LOCAL_MODELS_DIR", "Models"),
|
||||
local_wildcards_dir=_dir("LOCAL_WILDCARDS_DIR", "Wildcards"),
|
||||
local_workflows_dir=_dir("LOCAL_WORKFLOWS_DIR", "CustomWorkflows"),
|
||||
local_output_dir=_dir("LOCAL_OUTPUT_DIR", "Output"),
|
||||
app_root=app_root,
|
||||
autocomplete_enabled=_as_bool(os.environ.get("AUTOCOMPLETE_ENABLED"), True),
|
||||
autocomplete_github_repo=(
|
||||
os.environ.get("AUTOCOMPLETE_GITHUB_REPO") or "DominikDoom/a1111-sd-webui-tagcomplete"
|
||||
).strip(),
|
||||
autocomplete_github_path=(
|
||||
os.environ.get("AUTOCOMPLETE_GITHUB_PATH") or "tags/danbooru.csv"
|
||||
).strip(),
|
||||
autocomplete_github_ref=(os.environ.get("AUTOCOMPLETE_GITHUB_REF") or "main").strip(),
|
||||
autocomplete_filename=(os.environ.get("AUTOCOMPLETE_FILENAME") or "danbooru.csv").strip(),
|
||||
swarmui_local_port=_as_int(os.environ.get("SWARMUI_LOCAL_PORT"), 17801),
|
||||
swarmui_image=(os.environ.get("SWARMUI_IMAGE") or "").strip(),
|
||||
default_flavor_id=(os.environ.get("DEFAULT_FLAVOR_ID") or "").strip(),
|
||||
flavor_preference=_csv(
|
||||
os.environ.get("FLAVOR_PREFERENCE"),
|
||||
("4090-24", "4090-48", "a5000", "a100-40"),
|
||||
),
|
||||
flavor_fallback=_as_bool(os.environ.get("FLAVOR_FALLBACK"), True),
|
||||
default_spot=_as_bool(os.environ.get("DEFAULT_SPOT"), True),
|
||||
keep_floating_ip=_as_bool(os.environ.get("KEEP_FLOATING_IP"), False),
|
||||
idle_minutes=_as_int(os.environ.get("IDLE_MINUTES"), 30),
|
||||
idle_grace_minutes=_as_int(os.environ.get("IDLE_GRACE_MINUTES"), 45),
|
||||
pull_output=_as_bool(os.environ.get("PULL_OUTPUT"), False),
|
||||
notify_ready=_as_bool(os.environ.get("NOTIFY_READY"), True),
|
||||
missing=missing,
|
||||
)
|
||||
Reference in New Issue
Block a user