【问题标题】:python ssh script for linux ssh command用于 linux ssh 命令的 python ssh 脚本
【发布时间】:2021-01-10 05:33:10
【问题描述】:

我的 Linux 脚本如下所示,用于 ssh 托管和搜索具有内核更新的补丁更新

 for host in `cat patch.csv`
    do 
      echo "Host $host" >> /tmp/patching
      ssh -o "UserKnownHostsFile=/dev/null" -o "StrictHostKeyChecking=no" $host  'sudo yum check-update | grep "kernel.x86"'>>/tmp/patching
    done

现在我正在尝试编写一个与此等效的 python 脚本及其显示错误(无法连接到 ssh)。我尝试使用不起作用的子进程命令 - 它无法获取主机名和公钥错误。

import subprocess
import os
def read_file():
    # Read and print the entire file line by line
    with open('patch.csv', 'r') as reader:
        with open('server_names.txt', 'w') as writer:
            for host in reader:
                writer.write(host)
                p = subprocess.Popen(["ssh -o 'UserKnownHostsFile=/dev/null' -o 'StrictHostKeyChecking=no' host 'sudo yum check-update | grep kernel.x86'"], shell=True, stdout=subprocess.PIPE)
                output, err = p.communicate()
                print(host)
    print("file read done")

read_file()

【问题讨论】:

  • 不管怎样,您的原始脚本有许多 shell 脚本陷阱。可能先看看shellcheck.net 对此有何评论。 (尽管用 Python 替换其中的大部分内容可能没有实际意义。)

标签: python linux ssh


【解决方案1】:

您可以使用 paramiko 解决该问题,使用 python ssh 到另一个主机,我们在内部项目中使用它,效果很好。

http://www.paramiko.org/
$ pip install paramiko

如果主机要求,您可以使用密码或密码作为输入,因此可以自动进行身份验证。

http://docs.paramiko.org/en/stable/api/client.html#paramiko.client.SSHClient.connect

connect(hostname, port=22, username=None, password=None, pkey=None, key_filename=None, timeout=None, allow_agent=True, look_for_keys=True, compress=False, sock=None, gss_auth=False, gss_kex=False, gss_deleg_creds=True, gss_host=None, banner_timeout=None, auth_timeout=None, gss_trust_dns=True, passphrase=None, disabled_algorithms=None)
Connect to an SSH server and authenticate to it. The server’s host key is checked against the system host keys (see load_system_host_keys) and any local host keys (load_host_keys). If the server’s hostname is not found in either set of host keys, the missing host key policy is used (see set_missing_host_key_policy). The default policy is to reject the key and raise an SSHException.
Code sample adapted from https://gist.github.com/mlafeldt/841944

import paramiko

hostname = host
password = pass123
command = 'sudo yum check-update | grep kernel.x86'
username = "admin"
port = 22

try:
    client = paramiko.SSHClient()
    client.load_system_host_keys()
    client.set_missing_host_key_policy(paramiko.WarningPolicy)
    client.connect(hostname, port=port, username=username, password=password)
    stdin, stdout, stderr = client.exec_command(command)
    print stdout.read()
finally:
    client.close()

【讨论】:

  • 我从你给定的代码@lucasgvarela 中得到了一些想法,并想出了这个确实有效的方法。 ssh 完成后有没有办法可以执行多项操作?想在 ssh 之后运行几个 mysql 查询并检查查询的输出并基于此做一些事情吗?
【解决方案2】:

我从你给定的代码@lucasgvarela 中得到了一些想法,并使用 stackoverflow 中的其他一些帖子提出了这个想法。

import subprocess
import sys    
# Ports are handled in ~/.ssh/config since we use OpenSSH
COMMAND="uname -a"
COMMAND2="UserKnownHostsFile=/dev/null"
COMMAND3="StrictHostKeyChecking=no"

with open('patch.csv', 'r') as reader:
    with open('server_names.txt', 'w') as writer:
        for HOST in reader:
            print(HOST)
            HOST=HOST.strip()
            ssh = subprocess.Popen(["ssh","-o",COMMAND2,"-o",COMMAND3, "%s" % HOST, COMMAND],
                                shell=False,
                                stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE)
            result = ssh.stdout.readlines()
            if result == []:
                error = ssh.stderr.readlines()
            # print >>sys.stderr, "ERROR: %s" % error
                writer.write(f'The Host failed is {HOST} & the error is {error}')
                print(error)
            else:
                print (result)

【讨论】:

  • 当您的用例由subprocess.run() 处理得非常好(或实际上更好)时,您真的应该避免使用Popen。但是为什么不使用专为这个特定用例设计的 Paramiko,它可以处理常规子流程不能很好工作的几个极端情况?
猜你喜欢
  • 2019-05-20
  • 2017-03-11
  • 2021-06-05
  • 2011-09-12
  • 2012-08-24
  • 2011-12-23
  • 1970-01-01
  • 2017-03-18
  • 2011-06-21
相关资源
最近更新 更多