2010-12-06 137 views
4

我想用django連接到遠程mysql數據庫。
該文檔指定需要首先打開SSH隧道才能連接到數據庫。
是否有一個python庫,只要設置了某些設置,就可以打開SSH隧道?如何使用python打開SSH隧道?

+0

http://stackoverflow.com/questions/953477/ssh-connection-with-python-3-0 – 2010-12-06 08:10:57

+0

嘗試https:///github.com/pahaz/sshtunnel – pahaz 2016-02-11 09:42:00

回答

7

您可以嘗試paramikoforward功能。對於paramiko概述,請參見here

+0

forward.py鏈接不可用。 – 2010-12-06 08:59:50

5

以下是Python3的代碼片段(但您應該可以毫無困難地將其改裝爲Python2)。它在一個單獨的線程中運行SSH隧道;那麼主線程會通過SSH隧道獲取網絡流量。

在本例中,ssh隧道將本地端口2222轉發到localhost上的端口80。主要活動包括運行

curl http://localhost:2222 

即,獲取的網頁,但從端口2222

類SshTunnel用4個參數,本地和遠程端口,遠程用戶,並且遠程初始化主辦。它所做的,是通過以下方式啓動SSH:

ssh -N -L localport:remotehost:remoteport [email protected] 

爲了使這項工作,你所需要的remoteuser表@遠程主機密碼登錄少(通過的〜/ .ssh/id_rsa.pub這在遠程服務器上已知)。 因此正在運行的ssh隧道在一個線程上;主要任務必須在另一個。 ssh隧道線程被標記爲守護進程,以便主活動終止後它會自動停止。

我沒有提供完整的MySQL連接示例,因爲它應該是不言自明的。一旦SshTunnel建立了一個本地TCP端口,你就可以連接到它 - 無論是通過你的MySQL客戶端,捲曲還是其他任何東西。

import subprocess 
import time 
import threading 

class SshTunnel(threading.Thread): 
    def __init__(self, localport, remoteport, remoteuser, remotehost): 
     threading.Thread.__init__(self) 
     self.localport = localport  # Local port to listen to 
     self.remoteport = remoteport # Remote port on remotehost 
     self.remoteuser = remoteuser # Remote user on remotehost 
     self.remotehost = remotehost # What host do we send traffic to 
     self.daemon = True    # So that thread will exit when 
             # main non-daemon thread finishes 

    def run(self): 
     if subprocess.call([ 
      'ssh', '-N', 
        '-L', str(self.localport) + ':' + self.remotehost + ':' + str(self.remoteport), 
        self.remoteuser + '@' + self.remotehost ]): 
      raise Exception ('ssh tunnel setup failed') 


if __name__ == '__main__': 
    tunnel = SshTunnel(2222, 80, 'karel', 'localhost') 
    tunnel.start() 
    time.sleep(1) 
    subprocess.call(['curl', 'http://localhost:2222']) 
3

嘗試使用sshtunnel package

這很簡單:

pip install sshtunnel 
python -m sshtunnel -U vagrant -P vagrant -L :3306 -R 127.0.0.1:3306 -p 2222 localhost 
2

這裏有一個小的類,你可以拖放到你的代碼:

import subprocess 
import random 
import tempfile 

class SSHTunnel: 

    def __init__(self, host, user, port, key, remote_port): 
     self.host = host 
     self.user = user 
     self.port = port 
     self.key = key 
     self.remote_port = remote_port 
     # Get a temporary file name 
     tmpfile = tempfile.NamedTemporaryFile() 
     tmpfile.close() 
     self.socket = tmpfile.name 
     self.local_port = random.randint(10000, 65535) 
     self.local_host = '127.0.0.1' 
     self.open = False 

    def start(self): 
     exit_status = subprocess.call(['ssh', '-MfN', 
      '-S', self.socket, 
      '-i', self.key, 
      '-p', self.port, 
      '-l', self.user, 
      '-L', '{}:{}:{}'.format(self.local_port, self.local_host, self.remote_port), 
      '-o', 'ExitOnForwardFailure=True', 
      self.host 
     ]) 
     if exit_status != 0: 
      raise Exception('SSH tunnel failed with status: {}'.format(exit_status)) 
     if self.send_control_command('check') != 0: 
      raise Exception('SSH tunnel failed to check') 
     self.open = True 

    def stop(self): 
     if self.open: 
      if self.send_control_command('exit') != 0: 
       raise Exception('SSH tunnel failed to exit') 
      self.open = False 

    def send_control_command(self, cmd): 
     return subprocess.check_call(['ssh', '-S', self.socket, '-O', cmd, '-l', self.user, self.host]) 

    def __enter__(self): 
     self.start() 
     return self 

    def __exit__(self, type, value, traceback): 
     self.stop() 

而且這裏是你如何能與MySQL(3306端口經常使用,例如):

with SSHTunnel('database.server.com', 'you', '22', '/path/to/private_key', '3306') as tunnel: 
    print "Connected on port {} at {}".format(tunnel.local_port, tunnel.local_host)