Implement SSH user data handling and adjust volume size

- Added functions to generate SSH user data in cloud-config format and encode it in Base64 for server creation.
- Updated the `create_gpu_server` function to include public key handling for SSH access.
- Adjusted the default boot volume size from 40GB to 30GB in `os_client.py`.
- Enhanced the `cmd_up` function to manage SSH key injection and server state more effectively.
- Improved logging for SSH connection attempts and error handling in `wait_ssh` to provide clearer feedback on authentication issues.
This commit is contained in:
Leonid Pershin
2026-08-21 04:35:02 +03:00
parent d6d247875b
commit 1f7237f7db
6 changed files with 155 additions and 22 deletions
+67 -8
View File
@@ -18,6 +18,7 @@ from gpu_rent.cloud import (
pick_existing_server,
server_status,
unshelve,
wait_volume,
)
from gpu_rent.bootstrap import run_bootstrap
from gpu_rent.provision import provision_vm
@@ -140,12 +141,63 @@ def cmd_up(
state.server_id = existing.id
state.server_name = getattr(existing, "name", None)
if status == "ACTIVE":
log("сервер уже ACTIVE — второй GPU не создаём")
state.phase = "ready_cloud"
save_state(state)
_bind_access(conn, existing, state, cfg, log)
return state
if status in {"EXPIRED", "SHELVED", "SHELVED_OFFLOADED"}:
if state.bootstrapped and state.floating_ip:
log("сервер уже ACTIVE — второй GPU не создаём")
state.phase = "ready_cloud"
save_state(state)
_bind_access(conn, existing, state, cfg, log)
return state
# First boot / stuck without injected key: probe SSH briefly.
fip = state.floating_ip
if not fip:
try:
fip, fip_id = ensure_floating_ip(
conn, existing, state.floating_ip_id, state.floating_ip, log
)
state.floating_ip = fip
if fip_id:
state.floating_ip_id = fip_id
save_state(state)
except Exception as exc:
log(f"FIP: {exc}")
if fip:
try:
wait_ssh(cfg, fip, timeout=90)
log("сервер уже ACTIVE — второй GPU не создаём")
state.phase = "ready_cloud"
save_state(state)
_bind_access(conn, existing, state, cfg, log)
return state
except CloudError as exc:
msg = str(exc)
if "ключ отклонён" in msg or "Authentication" in msg:
log(
"SSH ключ не на VM (boot-from-volume) — "
"удаляем compute, диски оставляем, create с config_drive"
)
delete_server(conn, existing, log)
state.server_id = None
state.server_name = None
state.bootstrapped = False
state.phase = "idle"
save_state(state)
for vid in (state.boot_volume_id, state.data_volume_id):
if not vid:
continue
try:
wait_volume(conn, conn.block_storage.get_volume(vid), "available")
except Exception as vol_exc:
log(f"wait volume {vid}: {vol_exc}")
existing = None
else:
raise
if existing is not None:
log("сервер уже ACTIVE — второй GPU не создаём")
state.phase = "ready_cloud"
save_state(state)
_bind_access(conn, existing, state, cfg, log)
return state
if existing is not None and status in {"EXPIRED", "SHELVED", "SHELVED_OFFLOADED"}:
existing = unshelve(conn, existing, log)
state.server_id = existing.id
state.phase = "ready_cloud"
@@ -153,7 +205,8 @@ def cmd_up(
save_state(state)
_bind_access(conn, existing, state, cfg, log)
return state
raise CloudError(f"сервер gpu-rent в статусе {status} — разбери в панели")
if existing is not None:
raise CloudError(f"сервер gpu-rent в статусе {status} — разбери в панели")
if state.server_id:
log(f"в state был server {state.server_id}, в облаке нет — создаём заново")
@@ -220,7 +273,12 @@ def cmd_up(
net, _subnet = ensure_network(conn, log)
cidr = guess_operator_cidr()
if cidr == "0.0.0.0/0":
log("не удалось узнать твой IP — SG откроет SSH с 0.0.0.0/0")
import os
if (os.environ.get("GPU_RENT_SSH_CIDR") or "").strip():
log("SG SSH: GPU_RENT_SSH_CIDR=0.0.0.0/0")
else:
log("не удалось узнать твой IP — SG откроет SSH с 0.0.0.0/0")
sg = ensure_security_group(conn, cidr, log)
boot = ensure_boot_volume(
@@ -263,6 +321,7 @@ def cmd_up(
data_volume_id=data.id,
az=cfg.gpu_rent_az,
spot=spot,
public_key=public_key,
log=log,
)
state.server_id = server.id