You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何判断远程ESXI主机是否完成启动并可接收SSH命令

问题根因

你遇到的循环意外退出问题,核心是两处代码疏漏导致异常没有被正确捕获,直接触发程序崩溃:

  • 最后一个全局捕获块except:没有绑定异常变量e,执行print(e)时会直接抛出NameError,直接终止整个函数执行,不会进入下一次重试。ESXI启动过程中抛出的Errno 111 Connection refused在你当前的异常列表里没有被完全覆盖,会掉到这个全局捕获块触发崩溃。
  • 你代码中定义了总超时变量timeout_start但没有实际做判断,存在死循环风险;同时每次重试没有主动清理SSH连接实例,可能产生连接句柄泄漏,触发ESXI侧SSH服务的临时连接限制,也会加重111错误的出现概率。

修复方案

修改后的代码如下,主要做了几处调整:

  • 补充ConnectionRefusedError显式捕获,覆盖111错误场景
  • 修正全局异常捕获的变量绑定问题,避免NameError
  • 每次重试都重新实例化SSHClient、主动关闭旧连接,避免连接状态污染
  • 增加总超时逻辑,避免主机异常时无限重试
import time
import socket
import paramiko
from socket import error as socket_error

def send_command(ip, port, timeout, retry_interval, cmd, user, password):
    retry_interval = float(retry_interval)
    timeout = int(timeout)
    timeout_start = time.time()
    
    while time.time() < timeout_start + timeout:
        time.sleep(retry_interval)
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        try:
            ssh.connect(ip, port, user, password, timeout=5)
            stdin, stdout, stderr = ssh.exec_command(cmd)
            outlines = stdout.readlines()
            resp = ''.join(outlines)
            print(resp)
            ssh.close()
            return resp
        except ConnectionRefusedError as e:
            # 专门处理111连接拒绝,直接重试
            print(f"Connection refused: {e}, retrying...")
            ssh.close()
            continue
        except socket_error as e:
            print(e)
            ssh.close()
            continue
        except paramiko.ssh_exception.SSHException as e:
            # socket是通的但SSH服务未就绪,重试
            print(e) 
            ssh.close()
            continue
        except TimeoutError as e: 
            print(e)
            ssh.close()
            continue
        except socket.timeout as e: 
            print(e)
            ssh.close()
            continue
        except paramiko.ssh_exception.NoValidConnectionsError as e:
            print(e)
            ssh.close()
            continue
        except socket.error as serr:
            print(serr)
            ssh.close()
            continue 
        except IOError as e:
            print(e)
            ssh.close()
            continue 
        except Exception as e:
            # 兜底捕获所有其他异常,确保不会退出循环
            print(f"Unexpected error: {e}, retrying...")
            ssh.close()
            continue
    
    # 总超时退出
    raise TimeoutError(f"Failed to connect to {ip} within {timeout} seconds")

补充说明

你提到的更换命令为esxcli system hostname get并校验返回字段的方案可以作为业务层面的就绪判断逻辑,避免SSH服务刚启动但ESXI系统层未就绪时返回无效结果,建议和异常捕获修复同时使用。

内容的提问来源于stack exchange,提问作者jasont41

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.10 09:48:03