Files
gpu-rent/src/gpu_rent/os_client.py
T
2026-08-21 02:42:48 +03:00

119 lines
3.6 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.config import Config
from gpu_rent.errors import CloudError
RESOURCE_TAG = "gpu-rent"
COMPUTE_MICROVERSION = "2.72"
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="0.1.0",
)
conn.authorize()
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