diff --git a/source/source.py b/source/source.py index 438fb94..b5d3f75 100644 --- a/source/source.py +++ b/source/source.py @@ -379,11 +379,11 @@ def do_transfer_offer(): if key_path: state.set_stage("TRANSFER", target_host=host, target_user=user, target_port=port_int, ssh_key=key_path) else: - # Нет SSH-ключа — запрашиваем пароль от TARGET сервера - password = prompt_password(f"Пароль от target-сервера {user}@{host} (Enter для отмены)") + # Нет SSH-ключа — запрашиваем пароль от НОВОГО сервера + password = prompt_password(f"Пароль от нового сервера {user}@{host} (Enter для отмены)") if not password: - state.set_error("ssh_key_setup", "", "Пароль не введён", suggestion="Запустите docker-migrate --resume или настройте SSH-ключ на target") - raise RuntimeError("Пароль от target не введён.") + state.set_error("ssh_key_setup", "", "Пароль не введён", suggestion="Запустите docker-migrate --resume или настройте приватный SSH-ключ на новом сервере") + raise RuntimeError("Пароль от нового сервера не введён.") from transfer.ssh import ensure_sshpass if not ensure_sshpass(): state.set_error("ssh_key_setup", "", "sshpass не найден", suggestion="apt-get install -y sshpass") diff --git a/transfer/ssh.py b/transfer/ssh.py index 30c3115..44e616a 100644 --- a/transfer/ssh.py +++ b/transfer/ssh.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ -ssh.py — SSH-подготовка для transfer на target-сервер. -НЕ ищем ключи на source — спрашиваем пользователя как подключиться к target. +ssh.py — SSH-подготовка для переноса на новый сервер. +НЕ ищем ключи на старом сервере — спрашиваем пользователя как подключиться к новому. """ import os @@ -10,7 +10,7 @@ from core.runner import run, exists def check_ssh_keyless(host, user, port, key_path, timeout=10): - """Проверяет подключение к target с данным ключом.""" + """Проверяет подключение к новому серверу с данным ключом.""" if not exists("ssh"): return (False, "ssh не найден") identity = f"-i '{key_path}'" if key_path and os.path.isfile(key_path) else "" @@ -24,94 +24,54 @@ def check_ssh_keyless(host, user, port, key_path, timeout=10): return (False, err[:120]) -def generate_temp_keypair(host_label): - """Генерирует временную пару ed25519 в /tmp/.""" - temp_dir = "/tmp/docker-migrate-ssh-keys" - os.makedirs(temp_dir, exist_ok=True) - priv = os.path.join(temp_dir, f"migrate_{host_label}") - pub = priv + ".pub" - info("Генерируем временную SSH-пару ed25519 ...") - run(f"ssh-keygen -t ed25519 -C 'docker-migrate-temp' -f '{priv}' -N ''", check=False) - if os.path.isfile(priv) and os.path.isfile(pub): - os.chmod(priv, 0o600) - success(f"Временная пара создана: {priv}") - return {"private": priv, "public": pub, "type": "ed25519", "temp": True} - return None - - -def ssh_copy_id(host, user, port, pubkey_path): - """ssh-copy-id на target. Интерактивно (пароль target).""" - if not exists("ssh-copy-id"): - return False - warn("⚠ Сейчас запустится ssh-copy-id — введите ПАРОЛЬ от target-сервера ↓") - r = run( - f"ssh-copy-id -p {port} -o ConnectTimeout=30 -o StrictHostKeyChecking=accept-new -i '{pubkey_path}' {user}@{host}", - check=False, capture=False, timeout=120 - ) - return r.returncode == 0 - - -def ensure_sshpass(): - """Устанавливает sshpass если нужно.""" - if exists("sshpass"): - return True - info("sshpass не найден. Устанавливаем ...") - r1 = run("apt-get update", check=False, timeout=60) - if r1.returncode != 0: - warn(f"apt-get update: {r1.stderr.strip()[:120]}") - r = run("apt-get install -y sshpass", check=False, timeout=120) - if r.returncode != 0: - warn(f"Не удалось установить sshpass: {r.stderr.strip()[:120]}") - return False - return exists("sshpass") - +# ... def pick_or_setup_ssh_key(host, user, port): """ - Возвращает путь к приватному ключу для target. - Если None — значит нужен пароль target (sshpass). + Возвращает путь к приватному SSH-ключу для нового сервера. + Если None - значит нужен пароль нового сервера (sshpass). """ info("") - info("Как подключиться к target-серверу?") - print(" 1) У меня есть приватный ключ от target (файл .pem/.key/.ppk)") - print(" 2) У меня есть логин и пароль от target") + info("Как подключиться к новому серверу?") + print(" 1) У меня есть приватный SSH-ключ от нового сервера (файл .pem/.key/.ppk)") + print(" 2) У меня есть логин и пароль от нового сервера") print(" 0) Отмена") choice = prompt("Ваш выбор", default="1").strip() if choice == "1": - # Пользователь даёт путь к ключу target - key_path = prompt("Путь к приватному ключу (например, /root/server.pem)").strip() + # Пользователь даёт путь к ключу нового сервера + key_path = prompt("Путь к приватному SSH-ключу (например, /root/server.pem)").strip() if not key_path or not os.path.isfile(key_path): raise RuntimeError(f"Файл не найден: {key_path}") ok, why = check_ssh_keyless(host, user, port, key_path) if ok: - success("Ключ подходит для target!") + success("Приватный SSH-ключ подходит для нового сервера!") return key_path if why == "PASSPHRASE": - warn(f"Ключ защищён passphrase. Разблокируйте: ssh-add {key_path}") - raise RuntimeError("Ключ зашифрован. Разблокируйте через ssh-add и перезапустите.") - raise RuntimeError(f"Ключ не подходит: {why}") + warn(f"Приватный SSH-ключ защищён passphrase. Разблокируйте: ssh-add {key_path}") + raise RuntimeError("Приватный SSH-ключ зашифрован. Разблокируйте через ssh-add и перезапустите.") + raise RuntimeError(f"Приватный SSH-ключ не подходит: {why}") if choice == "2": - # Пароль target + # Пароль нового сервера info("") info("Выберите способ:") - print(" 1) Ввести пароль от target — scp через sshpass") - print(" 2) Сгенерировать временный ключ + ssh-copy-id (target спросит пароль)") + print(" 1) Ввести пароль от нового сервера — scp через sshpass") + print(" 2) Сгенерировать временный SSH-ключ + ssh-copy-id (новый сервер спросит пароль)") sub = prompt("Ваш выбор", default="1").strip() if sub == "2": temp = generate_temp_keypair(host.replace(".", "_")) if not temp: - raise RuntimeError("Не удалось сгенерировать ключ") + raise RuntimeError("Не удалось сгенерировать SSH-ключ") if ssh_copy_id(host, user, port, temp["public"]): ok, _ = check_ssh_keyless(host, user, port, temp["private"]) if ok: - success("Временный ключ добавлен на target!") + success("Временный SSH-ключ добавлен на новый сервер!") return temp["private"] # ssh-copy-id не сработал warn("ssh-copy-id не удался. Варианты:") - print(f" 1) Вручную на target: mkdir -p ~/.ssh; echo '$(cat {temp['public']})' >> ~/.ssh/authorized_keys") + print(f" 1) Вручную на новом сервере: mkdir -p ~/.ssh; echo '$(cat {temp['public']})' >> ~/.ssh/authorized_keys") print(f" 2) Затем: docker-migrate --resume") raise RuntimeError("ssh-copy-id не удался.")