# -*- coding: utf-8 -*- """ transfer.py — Адаптивный перенос архива (scp/rsync/fallback) """ import os import json from core.color import info, success, warn, error as cerror, prompt, confirm, step from core import state from core.runner import run, exists def do_transfer(): st = state.load_state() archive_path = st.get("archive_path") if not archive_path or not os.path.isfile(archive_path): raise RuntimeError("Архив не найден. Сначала выполните сборку (Source → Pack).") host = st.get("target_host") user = st.get("target_user") port = st.get("target_port", 22) step(5, "ПЕРЕНОС АРХИВА") info(f"Target: {user}@{host}:{port}") # Определяем размер size = os.path.getsize(archive_path) size_mb = size / 1024 / 1024 info(f"Размер архива: {size_mb:.2f} MB") # Определяем путь назначения remote_dir = "/tmp/docker-migrate-incoming" remote_path = os.path.join(remote_dir, os.path.basename(archive_path)) # Копируем bootstrap (migrate + core/) чтобы target мог запуститься # Найдём корень проекта project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) tar_script = os.path.join(project_root, "tar_project.sh") # Выбираем метод if size_mb < 50 and exists("scp"): method = "scp" elif size_mb >= 50 and exists("rsync"): method = "rsync" else: if exists("rsync"): method = "rsync" elif exists("scp"): method = "scp" else: raise RuntimeError("Ни rsync, ни scp не найдены. Установите один из них.") info(f"Выбран метод переноса: {method}") ssh_opts = f"-p {port}" if exists("ssh"): # Проверим доступность info("Проверяем SSH-соединение ...") check = run(f"ssh {ssh_opts} -o ConnectTimeout=10 -o BatchMode=yes {user}@{host} 'echo ok'", check=False) if check.returncode != 0: warn("SSH (batch mode) не прошёл — возможно, нужен пароль.") else: success("SSH доступ подтверждён") if method == "scp": info("Копируем архив через scp ...") run(f"scp {ssh_opts} {archive_path} {user}@{host}:{remote_path}", check=False) else: info("Копируем архив через rsync ...") run(f"rsync -avz --progress -e 'ssh {ssh_opts}' {archive_path} {user}@{host}:{remote_path}", check=False) success(f"Архив передан на {host}:{remote_path}") # Распаковка на target во временную директорию info("Распаковываем архив на target ...") run(f"ssh {ssh_opts} {user}@{host} 'mkdir -p {remote_dir} \u0026\u0026 tar xzf {remote_path} -C {remote_dir}'", check=False) # Сохраняем remote_dir в state для target state.set_stage("TRANSFER_DONE", target_remote_dir=remote_dir) # Предлагаем сразу запустить target-режим удалённо if confirm("Сразу запустить восстановление на новом сервере (remote target mode)", default="y"): info("Запускаем target-mode удалённо ...") # Передаём скрипт на target project_local = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) run(f"scp {ssh_opts} -r {project_local} {user}@{host}:/opt/docker-migrate-tool", check=False) # Запуск target как remote python run(f"ssh {ssh_opts} {user}@{host} 'cd /opt/docker-migrate-tool && python3 core/main.py --mode=target --remote-dir={remote_dir}'", check=False) else: success(f"Архив передан. Запустите на target: python3 core/main.py --mode=target --remote-dir={remote_dir}")