- Added `ollama-models.yaml` to .gitignore and implemented logic to copy it in gpu-rent.ps1 and gpu-rent.sh. - Enhanced env.example to include new variables for LLM runtime options and local watchdog configuration. - Updated CLI commands to support LLM options during setup and execution, including new flags for Ollama and llama.cpp. - Improved documentation in cli.md and README.md to reflect changes in LLM integration and local watchdog functionality. - Adjusted architecture and decisions documentation to clarify the role of LLMs and local watchdog in the system.
136 lines
4.1 KiB
Python
136 lines
4.1 KiB
Python
"""openstacksdk connection. IAM token is 24h; sdk refreshes on authorize()."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from collections.abc import Iterator
|
|
from typing import Any
|
|
|
|
from gpu_rent import __version__
|
|
from gpu_rent.config import Config
|
|
from gpu_rent.errors import CloudError
|
|
|
|
RESOURCE_TAG = "gpu-rent"
|
|
PREEMPTIBLE_TAG = "preemptible"
|
|
COMPUTE_MICROVERSION = "2.72"
|
|
|
|
SERVER_NAME = "gpu-rent"
|
|
KEYPAIR_NAME = "gpu-rent"
|
|
NET_NAME = "gpu-rent"
|
|
SUBNET_NAME = "gpu-rent-subnet"
|
|
ROUTER_NAME = "gpu-rent"
|
|
SG_NAME = "gpu-rent"
|
|
BOOT_VOLUME_NAME = "gpu-rent-boot"
|
|
DATA_VOLUME_NAME = "gpu-rent-data"
|
|
SUBNET_CIDR = "192.168.77.0/24"
|
|
BOOT_VOLUME_SIZE_GB = 30
|
|
|
|
|
|
def connect(cfg: Config):
|
|
try:
|
|
import openstack
|
|
except ImportError as exc:
|
|
raise CloudError("Нет openstacksdk. Переустанови пакет: pip install -e .") from exc
|
|
|
|
try:
|
|
conn = openstack.connect(
|
|
auth_url=cfg.os_auth_url,
|
|
project_id=cfg.os_project_id,
|
|
username=cfg.os_username,
|
|
password=cfg.os_password,
|
|
user_domain_name=cfg.os_user_domain_name,
|
|
project_domain_name=cfg.os_user_domain_name,
|
|
region_name=cfg.os_region_name,
|
|
identity_api_version="3",
|
|
interface="public",
|
|
compute_api_version=COMPUTE_MICROVERSION,
|
|
app_name="gpu-rent",
|
|
app_version=__version__,
|
|
)
|
|
conn.authorize()
|
|
try:
|
|
conn.compute.default_microversion = COMPUTE_MICROVERSION
|
|
except Exception:
|
|
pass
|
|
except Exception as exc:
|
|
raise CloudError(
|
|
"Keystone не выдал токен. Проверь OS_USERNAME / OS_PASSWORD / "
|
|
"OS_PROJECT_ID / OS_USER_DOMAIN_NAME (номер аккаунта). "
|
|
"Не используй X-Token панели. Подробности: docs/setup.md. "
|
|
f"Ошибка SDK: {exc}"
|
|
) from exc
|
|
return conn
|
|
|
|
|
|
def _obj_dict(obj: Any) -> dict[str, Any]:
|
|
if obj is None:
|
|
return {}
|
|
if hasattr(obj, "to_dict"):
|
|
try:
|
|
return obj.to_dict(computed=False)
|
|
except TypeError:
|
|
return obj.to_dict()
|
|
if isinstance(obj, dict):
|
|
return obj
|
|
return {"repr": repr(obj)}
|
|
|
|
|
|
def compute_quotas(conn) -> dict[str, Any]:
|
|
project = conn.current_project_id
|
|
try:
|
|
quota = conn.compute.get_quota_set(project)
|
|
return _obj_dict(quota)
|
|
except Exception:
|
|
try:
|
|
return dict(conn.get_compute_quotas(project) or {})
|
|
except Exception as exc:
|
|
raise CloudError(f"Не прочитать compute quota: {exc}") from exc
|
|
|
|
|
|
def volume_quotas(conn) -> dict[str, Any]:
|
|
project = conn.current_project_id
|
|
try:
|
|
quota = conn.block_storage.get_quota_set(project)
|
|
return _obj_dict(quota)
|
|
except Exception:
|
|
try:
|
|
return dict(conn.get_volume_quotas(project) or {})
|
|
except Exception as exc:
|
|
return {"error": str(exc)}
|
|
|
|
|
|
def iter_flavors(conn) -> Iterator[Any]:
|
|
yield from conn.compute.flavors(details=True)
|
|
|
|
|
|
def iter_volume_types(conn) -> Iterator[Any]:
|
|
yield from conn.block_storage.types()
|
|
|
|
|
|
def iter_images(conn) -> Iterator[Any]:
|
|
yield from conn.image.images()
|
|
|
|
|
|
def find_tagged_servers(conn) -> list[Any]:
|
|
servers = []
|
|
for server in conn.compute.servers(details=True):
|
|
tags = set(getattr(server, "tags", None) or [])
|
|
name = (getattr(server, "name", "") or "").lower()
|
|
if RESOURCE_TAG in tags or name.startswith("gpu-rent"):
|
|
servers.append(server)
|
|
return servers
|
|
|
|
|
|
def find_volumes_by_name(conn, name: str) -> list[Any]:
|
|
found = []
|
|
for volume in conn.block_storage.volumes():
|
|
if getattr(volume, "name", None) == name:
|
|
found.append(volume)
|
|
return found
|
|
|
|
|
|
def find_snapshot_by_name(conn, name: str) -> Any | None:
|
|
for snap in conn.block_storage.snapshots():
|
|
if getattr(snap, "name", None) == name:
|
|
return snap
|
|
return None
|