问题描述
我的网络跳是A(本地)-> B-> C-> D(端口3306上的数据库已为本地主机打开)。
我需要从A访问D上的数据库。
我正在使用fabric进行ssh连接
我的代码如下:
import socket
from contextlib import closing
from fabric import Connection
import MysqL.connector
def _connect_to_middleware_database(self,port):
return MysqL.connector.connect(
user="DB-USER",password="MYPASS",host="127.0.0.1",port=port,database="tasks",connection_timeout=10)
def get_free_port():
with closing(socket.socket(socket.AF_INET,socket.soCK_STREAM)) as s:
s.bind(("localhost",0))
s.setsockopt(socket.soL_SOCKET,socket.so_REUSEADDR,1)
return s.getsockname()[1]
def _get_connection(self,ip,port,user,pw):
return Connection(
host=ip,user=user,connect_kwargs={
"password": pw,"allow_agent": False,"look_for_keys": False,},)
res = {}
local_port = get_free_port()
local_port_1 = get_free_port()
local_port_2 = get_free_port()
c1 = self._get_connection(
"IP-B",22,"USER-B","PASS-B",)
c2 = self._get_connection(
"127.0.0.1",local_port,"USER-C","PASS-C",)
c3 = self._get_connection(
"127.0.0.1",local_port_1,"USER-D","PASS-D",)
with c1.forward_local(
local_port=local_port,remote_port=22,local_host="127.0.0.1",remote_host="IP-C",):
with c2.forward_local(
local_port=local_port_1,remote_host="IP-D",):
with c3.forward_local(
local_port=local_port_2,remote_port=3306,remote_host="127.0.0.1",):
cnx = _connect_to_middleware_database(
local_port_2
)
if cnx:
cursor = cnx.cursor()
cursor.execute("show tables")
sql_result = cursor.fetchall()
print(str(sql_result))
问题在于它只能真正不一致。经过一些尝试,它可以工作,但大多数情况下,我得到:
Traceback (most recent call last):
File "tunnel_test.py",line 78,in <module>
remote_host="IP-D",File "/usr/lib/python3.6/contextlib.py",line 159,in helper
return _GeneratorContextManager(func,args,kwds)
File "/usr/lib/python3.6/contextlib.py",line 60,in __init__
self.gen = func(*args,**kwds)
File "<decorator-gen-6>",line 2,in forward_local
File "/usr/local/lib/python3.6/dist-packages/fabric/connection.py",line 29,in opens
self.open()
File "/usr/local/lib/python3.6/dist-packages/fabric/connection.py",line 634,in open
self.client.connect(**kwargs)
File "/usr/local/lib/python3.6/dist-packages/paramiko/client.py",line 368,in connect
raise NovalidConnectionsError(errors)
paramiko.ssh_exception.NovalidConnectionsError: [Errno None] Unable to connect to port 59235 on 127.0.0.1
在某些情况下它可以正常工作,而且我使用的主机肯定可以访问。
我很感谢所有答案。
解决方法
使用sshtunnel
代替fabric
。
import sshtunnel
with sshtunnel.open_tunnel(
ssh_address_or_host=('IP_B',22),remote_bind_address=('IP_C',ssh_username='USER_B',ssh_password='PASS_B',block_on_close=False
) as tunnel1:
print('Connection to B OK...')
with sshtunnel.open_tunnel(
ssh_address_or_host=('localhost',tunnel1.local_bind_port),remote_bind_address=('IP_D',ssh_username='USER_C',ssh_password='PASS_C',block_on_close=False
) as tunnel2:
print('Connection to C OK...')
with sshtunnel.open_tunnel(
ssh_address_or_host=('localhost',tunnel2.local_bind_port),remote_bind_address=('127.0.0.1',3306),ssh_username='USER_D',ssh_password='PASS_D',block_on_close=False
) as tunnel3:
print('Connection to D OK...')
cnx = _connect_to_middleware_database(
tunnel3.local_bind_port
)
if cnx:
cursor = cnx.cursor()
cursor.execute("show tables")
sql_result = cursor.fetchall()
print(str(sql_result))