7

这是我在 StackOverflow 的第一篇文章,所以我希望以正确的方式来做!:)

我的新工作需要连接到多台服务器并在所有服务器中执行 python 脚本。我对服务器不是很熟悉(刚开始使用 paramiko),所以对于任何重大错误,我深表歉意!

我想在它们上运行的脚本修改了 authorized_keys 文件,但开始时,我只用一个服务器尝试它,还没有使用上述脚本(我不想犯错误并在我的第一个任务中阻止服务器!)。我只是想用一个非常简单的函数 getDir() 列出远程机器中的目录。到目前为止,我已经能够使用基本的 paramiko 连接到服务器(顺便说一下,我正在使用 pdb 来调试脚本):

try_paramiko.py

#!/usr/bin/python

import paramiko
from getDir import get_dir
import pdb


def try_this(server):
    pdb.set_trace()
    ssh = paramiko.SSHClient()
    ssh.load_host_keys("pth/to/known_hosts")
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    my_key = paramiko.RSAKey.from_private_key_file("pth/to/id_rsa")
    ssh.connect(server, username = "root", pkey = my_key)
    i, o, e = ssh.exec_command(getDir())

这是获取目录列表的函数:

获取目录.py

#!/usr/bin/python

import os
import pdb


def get_dir():
    pdb.set_trace()
    print "Current dir list is:"
    for item in os.listdir(os.getcwd()):
        print item

在调试时,我得到了本地机器的目录列表,而不是来自远程机器的目录列表……有没有办法通过 paramiko 将 python 函数作为参数传递?我只想在本地拥有脚本并远程运行它,就像您使用来自 ssh 的 bash 文件执行它时一样:

ssh -i pth/to/key username@domain.com 'bash -s' < script.sh

所以实际上避免将python脚本复制到每台机器然后从它们运行它(我猜使用上面的命令脚本也会被复制到远程机器然后删除,对吧?)有没有办法做到这一点paramiko.sshClient()?

我还尝试修改代码并使用创建 exec_command 的通道的标准输出来列出留下脚本的目录,例如:

try_paramiko.py

#!/usr/bin/python

import paramiko
from getDir import get_dir
import pdb


def try_this(server):
    pdb.set_trace()
    ssh = paramiko.SSHClient()
    ssh.load_host_keys("pth/to/known_hosts")
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    my_key = paramiko.RSAKey.from_private_key_file("pth/to/id_rsa")
    ssh.connect(server, username = "root", pkey = my_key)
    i, o, e = ssh.exec_command(getDir())
    for line in o.readlines():
        print line
    for line in e.readlines():
        print line    

获取目录.py

def get_dir():
    return ', '.join(os.listdir(os.getcwd()))

但是有了这个,它实际上会尝试将本地目录列表作为命令运行(这实际上对我来说是有意义的)。我不得不将列表转换为字符串,因为我有一个 TypeError 说它需要一个字符串或只读字符缓冲区,而不是列表......我知道这是传递函数的绝望尝试......任何人都知道我怎么能做这样的事情(通过 paramiko 传递一个本地函数在远程机器上执行它)?如果您对代码有任何更正或提示,非常欢迎他们(实际上,非常感谢任何形式的帮助!)。

提前非常感谢!:)

4

3 回答 3

5

您不能只通过 ssh 执行 python 函数。ssh 只是一条隧道,您的代码在一侧(客户端),外壳在另一侧(服务器)。您应该在远程端执行 shell 命令。

如果使用原始 ssh 代码并不重要,我建议fabric将其作为编写管理工具的库。它包含用于轻松处理 ssh、文件传输、sudo、并行执行等的工具。

于 2012-11-02T19:38:21.593 回答
2

我认为您可能想要更改要传递的参数ssh.exec_command这是一个想法:

而不是这样做:

def get_dir():
    return ', '.join(os.listdir(os.getcwd()))

i, o, e = ssh.exec_command(getDir())

您可能想尝试:

i, o, e = ssh.exec_command('pwd')
o.printlines()

和其他要探索的东西:

  • 编写驻留在您的服务器上的 bash 脚本或 Python。您可以使用 Paramiko 登录服务器并使用ssh.exec_command(some_script.sh)或执行脚本ssh.exec_command(some_script.py)
  • Paramiko 有一些 FTP/SFTP 实用程序,因此您实际上可以使用它将脚本放在服务器上然后执行它。
于 2012-11-19T19:16:15.197 回答
0

可以通过使用 here 文档将模块提供给远程服务器的 python 解释器来做到这一点。

remotepypath = "/usr/bin/"

# open the module as a text file
with open("getDir.py", "r") as f:
    mymodule = f.read()

# setup from OP code
ssh = paramiko.SSHClient()
ssh.load_host_keys("pth/to/known_hosts")
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
my_key = paramiko.RSAKey.from_private_key_file("pth/to/id_rsa")
ssh.connect(server, username = "root", pkey = my_key)

# use here document to feed module into python interpreter
stdin, stdout, stderr = ssh.exec_command("{p}python - <<EOF\n{s}\nEOF".format(p=remotepypath, s=mymodule))
print("stderr: ", stderr.readlines())
print("stdout: ", stdout.readlines())
于 2020-07-20T07:46:59.443 回答