8

我想使用 rsync 和 SSH(从 Python 程序中)从远程机器获取文件。

如何启动 rsync 的本地实例并将其引入我用 Paramiko 打开的 SSH 通道?

4

2 回答 2

10

这是一个老问题,但在搜索“rsync over paramiko”时仍然是谷歌的第一个热门话题,这里唯一被投票赞成的项目是与 OP 的问题无关的评论(该评论中的链接指向使用 ControlMaster 哪个Paramiko 不支持)。

在此处的 Paramiko 演示中,有一个如何设置本地端口转发的示例。在拉取请求中还有一个更易于使用的版本。您可以通过两种方式使用本地端口转发:

  1. 将临时本地端口转发到远程 ssh 服务器并rsync使用 ssh 协议通过本地端口。这相当于运行ssh -L12345:localhost:22 remote-host后跟rsync --rsh 'ssh -p 12345' sourcedir/file localhost:/destdir/file.
  2. 将 ad-hoc 本地端口转发到 ad-hoc 远程 rsync 守护程序,并rsync使用 rsync 协议通过本地端口。这类似于 runningssh -L12345:localhost:12345后跟rsync sourcedir/file rsync://localhost:12345/module/destdir/file,不同之处在于您需要设置一个 ad-hoc rsync 守护程序,该守护程序在其上运行12345,其模块名称指向destdir远程主机上的 。

我个人更喜欢上面的第二种方法,尽管它稍微复杂一些,因为它跳过了本地ssh客户端并且还使用了 rsync 协议,我认为这比使用ssh.

使用ForwardServer上面的拉取请求,代码看起来有点像这样(取决于Fabric):

RSYNC_SPEC = """
port=12345
use chroot=false

[homedir]
log file=/tmp/rsync-ad-hoc.log
max verbosity=4
path=/home/{user}/
read only=false
"""

@task
def rsync(local_path, remote_path):
    """
    local_path: Absolute path to a local source
    remote_path: Relative path (from home directory) to a remote destination
    """
    with ForwardServer(0, "localhost", rsync_port, connections[env.host_string].get_transport()) as serv:
        local_port = serv.socket.getsockname()[1]
        run("killall rsync; rm -f /tmp/rsync-ad-hoc.log /tmp/rsync-ad-hoc.conf; :")
        put(local_path=StringIO(RSYNC_SPEC.format(user=env.user)), remote_path="/tmp/rsync-ad-hoc.conf", )
        run("rsync --daemon --config /tmp/rsync-ad-hoc.conf")
        remote_rsync_path = os.path.join("rsync://localhost:%s/homedir" % local_port, remote_path)
        # Rsync expects the root of the destination to exist.
        run("mkdir -p /home/{user}/{path}".format(user=env.user, path=remote_path))
        logging.info("Attempting rsync from (localhost, %s, %s) to (%s, %s, %s)", local_port, local_path, env.host_string, rsync_port, remote_path)
        local("rsync -avzPh --delete %s/ %s/" % (local_path, remote_rsync_path))

您还可以让该函数采用远程绝对路径并为模块生成目录(而不是假设它是相对于用户的主目录)。

于 2015-04-24T14:41:23.200 回答
0

我在使用 paramiko 和 rsync 时遇到了我无法解决的问题。我经常使用这个典型的框架成功地将 paramiko 与许多其他命令(例如,mkdir、mpstat、服务、本地 python 程序等)一起使用:

    client = paramiko.SSHClient()
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    client.connect(domain, username="root",timeout=5)

    stdin, mpstat, stderr = client.exec_command('mpstat')
    x=mpstat.readlines()
    # process the lines as though it is a file

关于 rsync,我没有追求 paramiko 解决方案,而是恢复为:

    x='''ssh root@%s "rsync -aRzq root@%s:%s /root/Backups/%s/%s " \
      '''%(BackupServerIP, ServerIP, file, Service, Server)
    os.system(x)

我通常更喜欢 paramiko,因为它很容易处理它的输出,所以我很想知道将它与 rsync 一起使用是否有问题,或者我只是没有坚持足够长的时间。

于 2015-01-10T19:51:45.730 回答