- Added package data configuration for the 'gpu_rent' package in pyproject.toml. - Updated README.md to include usage instructions for Windows and Unix launchers. - Enhanced CLI documentation in cli.md to reflect new commands and their functionalities. - Revised setup.md to clarify installation steps and environment setup. - Improved error handling and command descriptions in the CLI implementation. - Added new functions for model version handling and flavor resolution in the codebase. - Updated state management to include additional properties for better tracking.
133 lines
5.2 KiB
Python
133 lines
5.2 KiB
Python
import pytest
|
|
|
|
from gpu_rent.config import load_config
|
|
from gpu_rent.errors import CloudError, GpuRentError
|
|
from gpu_rent.lock import SessionLock
|
|
from gpu_rent.paths import lock_path
|
|
from gpu_rent.session import cmd_stop, cmd_up
|
|
from gpu_rent.state import SessionState, save_state
|
|
|
|
|
|
class Server:
|
|
def __init__(self, status="ACTIVE", server_id="s1"):
|
|
self.id = server_id
|
|
self.name = "gpu-rent"
|
|
self.status = status
|
|
self.flavor = {"id": "f1"}
|
|
self.addresses = {
|
|
"gpu-rent": [{"addr": "203.0.113.9", "OS-EXT-IPS:type": "floating"}]
|
|
}
|
|
|
|
|
|
def _cfg(monkeypatch):
|
|
monkeypatch.setenv("OS_AUTH_URL", "https://example.invalid/identity/v3")
|
|
monkeypatch.setenv("OS_USER_DOMAIN_NAME", "999")
|
|
monkeypatch.setenv("OS_USERNAME", "svc")
|
|
monkeypatch.setenv("OS_PASSWORD", "secret")
|
|
monkeypatch.setenv("OS_PROJECT_ID", "proj")
|
|
monkeypatch.setenv("OS_REGION_NAME", "ru-7")
|
|
monkeypatch.setenv("GPU_RENT_AZ", "ru-7a")
|
|
return load_config(require_auth=True)
|
|
|
|
|
|
def test_cmd_up_refuses_zero_gpu_quota(monkeypatch):
|
|
monkeypatch.setattr("gpu_rent.session.connect", lambda cfg: object())
|
|
monkeypatch.setattr("gpu_rent.session.compute_quotas", lambda conn: {"gpu": 0})
|
|
with pytest.raises(CloudError, match="квота GPU"):
|
|
cmd_up(_cfg(monkeypatch), yes=True)
|
|
|
|
|
|
def test_cmd_up_does_not_create_second_gpu(monkeypatch):
|
|
created = []
|
|
monkeypatch.setattr("gpu_rent.session.connect", lambda cfg: object())
|
|
monkeypatch.setattr("gpu_rent.session.compute_quotas", lambda conn: {"gpu": 1})
|
|
monkeypatch.setattr("gpu_rent.session.pick_existing_server", lambda conn: Server())
|
|
monkeypatch.setattr(
|
|
"gpu_rent.session.ensure_floating_ip",
|
|
lambda conn, server, existing_id, existing_addr, log: ("203.0.113.9", "fip1"),
|
|
)
|
|
monkeypatch.setattr("gpu_rent.session.wait_ssh", lambda cfg, host, timeout=420.0: None)
|
|
monkeypatch.setattr("gpu_rent.session.run_bootstrap", lambda cfg, host, log: None)
|
|
monkeypatch.setattr("gpu_rent.session.provision_vm", lambda cfg, host, log: None)
|
|
monkeypatch.setattr(
|
|
"gpu_rent.session.create_gpu_server",
|
|
lambda *a, **k: created.append("created") or Server(),
|
|
)
|
|
state = cmd_up(_cfg(monkeypatch), yes=True)
|
|
assert created == []
|
|
assert state.server_id == "s1"
|
|
assert state.phase == "ready_cloud"
|
|
assert state.floating_ip == "203.0.113.9"
|
|
assert state.bootstrapped is True
|
|
|
|
|
|
def test_cmd_up_unshelves_expired(monkeypatch):
|
|
unshelved = []
|
|
created = []
|
|
monkeypatch.setattr("gpu_rent.session.connect", lambda cfg: object())
|
|
monkeypatch.setattr("gpu_rent.session.compute_quotas", lambda conn: {"gpu": 1})
|
|
monkeypatch.setattr(
|
|
"gpu_rent.session.pick_existing_server", lambda conn: Server(status="EXPIRED")
|
|
)
|
|
monkeypatch.setattr(
|
|
"gpu_rent.session.unshelve",
|
|
lambda conn, server, log: unshelved.append(server.id) or Server(status="ACTIVE"),
|
|
)
|
|
monkeypatch.setattr(
|
|
"gpu_rent.session.ensure_floating_ip",
|
|
lambda conn, server, existing_id, existing_addr, log: ("203.0.113.9", "fip1"),
|
|
)
|
|
monkeypatch.setattr("gpu_rent.session.wait_ssh", lambda cfg, host, timeout=420.0: None)
|
|
monkeypatch.setattr("gpu_rent.session.run_bootstrap", lambda cfg, host, log: None)
|
|
monkeypatch.setattr("gpu_rent.session.provision_vm", lambda cfg, host, log: None)
|
|
monkeypatch.setattr(
|
|
"gpu_rent.session.create_gpu_server",
|
|
lambda *a, **k: created.append("created"),
|
|
)
|
|
state = cmd_up(_cfg(monkeypatch), yes=True)
|
|
assert unshelved == ["s1"]
|
|
assert created == []
|
|
assert state.unshelved_at
|
|
assert state.phase == "ready_cloud"
|
|
assert state.bootstrapped is True
|
|
|
|
|
|
def test_cmd_stop_deletes_compute_keeps_disks(monkeypatch):
|
|
deleted = []
|
|
monkeypatch.setattr("gpu_rent.session.connect", lambda cfg: object())
|
|
monkeypatch.setattr("gpu_rent.session.pick_existing_server", lambda conn: Server())
|
|
monkeypatch.setattr(
|
|
"gpu_rent.session.delete_server",
|
|
lambda conn, server, log: deleted.append(server.id),
|
|
)
|
|
monkeypatch.setattr(
|
|
"gpu_rent.session.delete_floating_ip",
|
|
lambda conn, fip_id, address, log: deleted.append("fip"),
|
|
)
|
|
save_state(
|
|
SessionState(server_id="s1", boot_volume_id="b1", data_volume_id="d1", floating_ip="1.1.1.1")
|
|
)
|
|
|
|
class Conn:
|
|
class compute:
|
|
@staticmethod
|
|
def get_server(sid):
|
|
return Server(server_id=sid)
|
|
|
|
monkeypatch.setattr("gpu_rent.session.connect", lambda cfg: Conn())
|
|
state = cmd_stop(_cfg(monkeypatch))
|
|
assert "s1" in deleted
|
|
assert state.phase == "idle"
|
|
assert state.server_id is None
|
|
assert state.boot_volume_id == "b1"
|
|
assert state.data_volume_id == "d1"
|
|
|
|
|
|
def test_lock_busy(monkeypatch):
|
|
lock_path().parent.mkdir(parents=True, exist_ok=True)
|
|
lock_path().write_text("1", encoding="utf-8")
|
|
monkeypatch.setattr("gpu_rent.lock._pid_alive", lambda pid: True)
|
|
monkeypatch.setattr("gpu_rent.lock.os.getpid", lambda: 99)
|
|
with pytest.raises(GpuRentError, match="уже работает"):
|
|
SessionLock().__enter__()
|