当前位置: 首页 > news >正文

ssh_utils.py

# -*- coding: utf-8 -*-
import paramiko
import socket
import time
import subprocess
import os
from config import Config


# utils/ssh_utils.py

import paramiko
import time

# utils/ssh_utils.py - 恢复原来能工作的版本
def ssh_exec(ip, port, user, password, command, timeout=30):
    """执行 SSH 命令"""
    import paramiko
   
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
   
    try:
        ssh.connect(ip, port=port, username=user, password=password, timeout=timeout)
        stdin, stdout, stderr = ssh.exec_command(command, timeout=timeout)
        stdout_str = stdout.read().decode('utf-8', errors='ignore')
        stderr_str = stderr.read().decode('utf-8', errors='ignore')
        exit_code = stdout.channel.recv_exit_status()
        ssh.close()
        return stdout_str, stderr_str, exit_code
    except Exception as e:
        ssh.close()
        raise e
       
def wait_for_ssh(ip, port, timeout=1200, first_wait=180, log_callback=None):
    """等待SSH服务就绪"""
    RETRY_INTERVAL = 30

    total_timeout = timeout if timeout else 1200
    start = time.time()
    attempt = 0

    def output(msg):
        if log_callback:
            log_callback(msg)

    output(f"  ⏳ 等待 {first_wait} 秒让服务器启动...")
    time.sleep(first_wait)
    elapsed = int(time.time() - start)

    output(f"  🔄 开始检测SSH服务(已等待{elapsed}秒)")

    while time.time() - start < total_timeout:
        attempt += 1
        elapsed = int(time.time() - start)
        remaining = total_timeout - elapsed

        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.settimeout(5)
            result = sock.connect_ex((ip, port))
            sock.close()

            if result == 0:
                output(f"  ✅ SSH端口已通,等待 {Config.WAIT_EXTRA_SECONDS} 秒系统稳定...")
                time.sleep(Config.WAIT_EXTRA_SECONDS)
                return True
        except:
            pass

        if attempt % 2 == 0:
            output(f"  ⏳ 检测SSH中... (第{attempt}次, 已等待{elapsed}秒, 剩余{remaining}秒)")

        time.sleep(RETRY_INTERVAL)

    output(f"  ❌ SSH恢复超时 (已等待{total_timeout}秒,共检测{attempt}次)")
    return False


def wait_for_power_off(ip, log_callback=None, timeout=30):
    """等待服务器断电(ping 不通)- Python 3.6 兼容"""
    if log_callback:
        log_callback(f"等待服务器 {ip} 断电...")
   
    start_time = time.time()
    while time.time() - start_time < timeout:
        if os.name == 'nt':
            cmd = ['ping', '-n', '1', '-w', '1000', ip]
        else:
            cmd = ['ping', '-c', '1', '-W', '1', ip]
       
        try:
            result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=5)
            is_alive = (result.returncode == 0)
        except subprocess.TimeoutExpired:
            is_alive = False
        except Exception:
            is_alive = True
       
        if not is_alive:
            elapsed = int(time.time() - start_time)
            if log_callback:
                log_callback(f"✅ 服务器 {ip} 已断电 (等待 {elapsed} 秒)")
            return True
        time.sleep(2)
   
    if log_callback:
        log_callback(f"❌ 服务器 {ip} 断电超时 ({timeout} 秒)")
    return False


def check_nvme_health(ip, port, user, password, nvme_disk):
    """检查单个NVMe盘是否健康"""
    cmd = f"ls {nvme_disk} 2>/dev/null && echo 'OK' || echo 'FAIL'"
    stdout, stderr, code = ssh_exec(ip, port, user, password, cmd)
    if 'OK' in stdout:
        return True, ""
   
    cmd2 = f"nvme list 2>/dev/null | grep {nvme_disk}"
    stdout2, _, _ = ssh_exec(ip, port, user, password, cmd2)
    if stdout2.strip():
        return True, ""
   
    return False, f"NVMe盘 {nvme_disk} 不可见"
http://www.jsqmd.com/news/858413/

相关文章:

  • 告别混乱搜索:Visual Paradigm 17.0 企业模型查找器(Enterprise Model Finder)深度使用指南
  • FanControl完全指南:Windows风扇控制软件的专业配置教程
  • PPTist:重新定义在线演示文稿创作的Web应用革命
  • Java开发选服务器:8核16G真的适合你吗
  • 小程序商城怎么选才能符合自己的需求|2026核心选型技巧 - FaiscoJeff
  • 在ubuntu上用python和taotoken快速搭建多模型对话测试工具
  • 深入WCH USB主机IP:对比CH58x与CH32系列寄存器差异及CherryUSB适配心得
  • PyTorch DDP分布式训练崩溃怎么办?教你一招避坑
  • 2026年最新解答:天学网的英语听力对孩子真的有用吗?
  • Google I/O 2026 发布会大招不断,免费用户能体验哪些新功能?
  • 终极英雄联盟自动化工具箱:League Akari完全指南
  • 蓝桥杯单片机按键编程避坑指南:从S4/S5/S8/S9高频考点代码到实战调试
  • 填充与积累:积分与面积的可视化
  • 华为认证“以学代考”续证政策——伙伴篇
  • 3步上手Ryujinx:在PC上畅玩Switch游戏的完整指南
  • 使用taotoken cli工具一键配置开发环境与多个ai工具
  • 2026京东e卡回收平台排名,哪家回购折扣高? - 京顺回收
  • 如何快速掌握NarratoAI:AI视频解说自动化的完整教程
  • 手把手教你配置杰理701N SDK的蓝牙回连与超距断开(附代码追踪)
  • 从GPIO到PCIe:一张图看懂FPGA通信接口的速度与距离选择
  • 观察 TaoToken 在多模型间智能路由对响应速度的实际影响
  • 2026年最新英语老师常用的英语听说教学辅助工具都有哪些
  • 微信投票小程序排行榜丨2026年5月已更新 - 资讯速览
  • 别再傻傻暴力破解了!用Python脚本5分钟探测OpenSSH 7.7以下版本的用户名(CVE-2018-15473)
  • 六自由度并联无人机自适应起降平台设计——从构型选型到运动学仿真全流程
  • 九江人卖黄金千万别乱跑 这四家正规回收门店才是避坑首选 - 润富黄金珠宝行
  • 看懂海康红外相机命名,选型效率至少提升一大截
  • 终极指南:如何快速上手ElectronBot桌面机器人开发
  • Navicat Premium Mac版终极重置指南:免费无限试用全攻略
  • LaneNet车道检测:如何在复杂路况下实现50fps的精准车道线识别?