"""Grow data volume upward (Cinder extend + resize2fs on VM).""" from __future__ import annotations import shlex import time from collections.abc import Callable from gpu_rent.config import Config from gpu_rent.errors import CloudError, GpuRentError from gpu_rent.os_client import DATA_VOLUME_NAME, connect, find_volumes_by_name from gpu_rent.ssh_ops import run_ssh from gpu_rent.state import load_state, save_state Log = Callable[[str], None] _GROW_FS = r""" set -euo pipefail mnt=/mnt/swarm_data src=$(findmnt -n -o SOURCE "$mnt" || true) if [[ -z "$src" ]]; then echo "data volume not mounted at $mnt" exit 1 fi if command -v resize2fs >/dev/null 2>&1; then resize2fs "$src" elif command -v xfs_growfs >/dev/null 2>&1; then xfs_growfs "$mnt" else echo "нет resize2fs/xfs_growfs" exit 1 fi df -h "$mnt" """ def resize_data_volume(cfg: Config, new_gb: int, log: Log) -> None: if new_gb < 1: raise GpuRentError("--gb должен быть положительным") state = load_state() vol_id = state.data_volume_id conn = connect(cfg) if not vol_id: found = find_volumes_by_name(conn, DATA_VOLUME_NAME) if not found: raise CloudError("нет data volume — сначала gpu-rent up") vol_id = found[0].id state.data_volume_id = vol_id save_state(state) vol = conn.block_storage.get_volume(vol_id) current = int(getattr(vol, "size", 0) or 0) if new_gb < current: raise GpuRentError( f"вниз нельзя: сейчас {current} GB, запрошено {new_gb} GB. " "Selectel online resize только вверх." ) if new_gb == current: log(f"data volume уже {current} GB") return log(f"Cinder extend {vol_id}: {current} → {new_gb} GB") try: conn.block_storage.extend_volume(vol, new_gb) except Exception: try: conn.block_storage.extend_volume(vol_id, new_gb) except Exception as exc: raise CloudError(f"extend volume: {exc}") from exc deadline = time.time() + 600 while time.time() < deadline: cur = conn.block_storage.get_volume(vol_id) size = int(getattr(cur, "size", 0) or 0) status = (getattr(cur, "status", "") or "").lower() if size >= new_gb and status in {"available", "in-use"}: log(f"volume size={size} status={status}") break time.sleep(5) else: raise CloudError("volume не вырос за 10 мин") host = state.floating_ip if not host: log("нет FIP — FS на VM не расширяю; подними GPU и повтори resize2fs вручную") return log("resize2fs на /mnt/swarm_data…") quoted = shlex.quote(_GROW_FS) out = run_ssh(cfg, host, f"sudo -n bash -c {quoted}", timeout=180) log(out.strip() or "FS grown")