通过python子流程ssh:如果没有指纹,如何跳转(您确定要继续连接吗?)

通过python子流程ssh:如果没有指纹,如何跳转(您确定要继续连接吗?),python,ssh,subprocess,Python,Ssh,Subprocess,我正在使用python脚本管理工作站重新映像后的ssh指纹问题 我尝试连接,如果出现“远程主机标识已更改!”错误,则脚本将删除旧指纹,扫描新指纹并将其添加 这一切都很好,直到我得到这样的信息: Warning: the ECDSA host key for 'workstation-1-s' differs from the key for the IP address '192.168.1.132' Offending key for IP in /home/me/.ssh/known_ho

我正在使用python脚本管理工作站重新映像后的ssh指纹问题

我尝试连接,如果出现“远程主机标识已更改!”错误,则脚本将删除旧指纹,扫描新指纹并将其添加

这一切都很好,直到我得到这样的信息:

 Warning: the ECDSA host key for 'workstation-1-s' differs from the key for the IP address '192.168.1.132'
Offending key for IP in /home/me/.ssh/known_hosts:16
Matching host key in /home/me/.ssh/known_hosts:60
Are you sure you want to continue connecting (yes/no)?
脚本将等待用户输入,然后继续并删除有问题的密钥

如何让脚本通过,或输入“否”,以便脚本可以继续其指纹修复工作

以下是相关的方法:

def ssh_fingerprint_changed(node):
    """
    Checks if a node's ssh fingerprint has changed or an old key is found, which can occur when a node is reimaged.
    It does this by attempting to connect via ssh and inspecting stdout for an error message.
    :param node: the ip or hostname of the node
    :return: True if the node's fingerprint doesn't match the client's records. Else False.
    """
    cmd = ["ssh", "-q", ADMIN_USER + "@" + node, "exit"]
    completed = subprocess.run(cmd, stdout=subprocess.PIPE, universal_newlines=True)
    if completed.stdout.find("REMOTE HOST IDENTIFICATION HAS CHANGED!") == -1:
        print("REMOTE HOST IDENTIFICATION HAS CHANGED!")
        return True
    elif completed.stdout.find("Offending key") == -1:
        print("Offending key found.") # need to type "no" before this prints
        return True
    return False
run
(或legacy
call
)不允许您以交互方式控制流程的输入/输出。当您获得输出时,该过程已经结束。你来不及参加聚会了

有些人会将您引导到
pexpect
,或
paramiko
(不需要调用
ssh
命令)

这里有一个使用
Popen
的解决方法。我删除了你的
返回逻辑。如果您想保持这种状态,请记住,此时进程仍在运行,因此您必须终止它(或等待它完成):

如果您确定唯一的答案是“否”,并且在给定的次数下,循环的另一种选择是

out,err = p.communicate(b"no\n"*10)  # send 10 times no+linefeed
扫描字符串/写入数据时请注意“b”前缀,因为标准输入/输出/错误是二进制的。在Python2中没有关系,但在Python3中,省略
b
会将字符串与字节进行比较,并且永远不会得到匹配


除此之外,我在Windows上使用了
plink
,但过了一段时间,我累了,重新构建了
plink
版本,所有安全消息都被禁用/默认为“乐观”值。如果网络是防火墙后面的公司网络,并且您要回答任何问题以通过这些提示,最好从一开始就创建一个非交互式工具。

您需要
Popen
,stdin重定向,并在遇到消息时提供
no
。请注意,我已经黑掉了我版本的
plink
,去掉了一些互动的东西。但是它不安全。你能提供一个关于
Popen
的例子吗?通过查看
Popen
文档,它建议使用
Popen.communication
。这样会更好吗?否,因为通信不允许您逐行筛选输出并决定回复内容。如果你知道你要回答“否”一定次数,那么使用comunicate是可能的。为什么
b中的b“字符串的键有问题
?是不是
universal\u newlines=True
导致
stdout
成为字符串?这是不同的。这是CR+LF/LF转换。如果使用python 3,输出仍然是
字节!如果你愿意,我可以提出一个新问题。现在我发现密码请求(如果找不到“有问题的密钥”),但在循环后我无法
proc.terminate()
,因为它从未经过循环?
out,err = p.communicate(b"no\n"*10)  # send 10 times no+linefeed