- Notifications
You must be signed in to change notification settings - Fork35
Add port conn params#127
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
base:master
Are you sure you want to change the base?
Uh oh!
There was an error while loading.Please reload this page.
Changes fromall commits
e8f4da9
80ba614
dc775c2
da22340
d08325b
f786b87
48594f6
fffb23c
1eb9a92
0611d10
3f9c618
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -1,8 +1,11 @@ | ||||||
import os | ||||||
import socket | ||||||
import subprocess | ||||||
import tempfile | ||||||
import platform | ||||||
import time | ||||||
from ..utils import reserve_port | ||||||
# we support both pg8000 and psycopg2 | ||||||
try: | ||||||
@@ -14,6 +17,7 @@ | ||||||
raise ImportError("You must have psycopg2 or pg8000 modules installed") | ||||||
from ..exceptions import ExecUtilException | ||||||
from ..utils import reserve_port | ||||||
from .os_ops import OsOperations, ConnectionParams, get_default_encoding | ||||||
error_markers = [b'error', b'Permission denied', b'fatal', b'No such file or directory'] | ||||||
@@ -46,47 +50,60 @@ def __init__(self, conn_params: ConnectionParams): | ||||||
self.host = conn_params.host | ||||||
self.port = conn_params.port | ||||||
self.ssh_key = conn_params.ssh_key | ||||||
self.ssh_cmd = ["-o StrictHostKeyChecking=no"] | ||||||
self.ssh_args = [] | ||||||
if self.ssh_key: | ||||||
self.ssh_args += ["-i", self.ssh_key] | ||||||
if self.port: | ||||||
self.ssh_args += ["-p", self.port] | ||||||
self.remote = True | ||||||
self.username = conn_params.username or self.get_user() | ||||||
self.tunnel_process = None | ||||||
self.tunnel_port = None | ||||||
def __enter__(self): | ||||||
return self | ||||||
def __exit__(self, exc_type, exc_val, exc_tb): | ||||||
self.close_ssh_tunnel() | ||||||
@staticmethod | ||||||
def is_port_open(host, port): | ||||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: | ||||||
sock.settimeout(1) # Таймаут для попытки соединения | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Hi, it will be added in scope ofhttps://github.com/postgrespro/testgres/pull/129/files I think the new testgres version will be deployed next week. | ||||||
try: | ||||||
sock.connect((host, port)) | ||||||
return True | ||||||
except socket.error: | ||||||
return False | ||||||
def establish_ssh_tunnel(self, local_port, remote_port, host): | ||||||
""" | ||||||
Establish an SSH tunnel from a local port to a remote PostgreSQL port. | ||||||
""" | ||||||
if host != 'localhost': | ||||||
ssh_cmd = ['-N', '-L', f"localhost:{local_port}:{host}:{remote_port}"] | ||||||
else: | ||||||
ssh_cmd = ['-N', '-L', f"{local_port}:{host}:{remote_port}"] | ||||||
self.tunnel_process = self.exec_command(ssh_cmd, get_process=True, timeout=300) | ||||||
timeout = 10 | ||||||
start_time = time.time() | ||||||
while time.time() - start_time < timeout: | ||||||
if self.is_port_open('localhost', local_port): | ||||||
print("SSH tunnel established.") | ||||||
return | ||||||
time.sleep(0.5) | ||||||
raise Exception("Failed to establish SSH tunnel within the timeout period.") | ||||||
def close_ssh_tunnel(self): | ||||||
if self.tunnel_process: | ||||||
self.tunnel_process.terminate() | ||||||
self.tunnel_process.wait() | ||||||
print("SSH tunnel closed.") | ||||||
del self.tunnel_process | ||||||
else: | ||||||
print("No active tunnel to close.") | ||||||
def exec_command(self, cmd, wait_exit=False, verbose=False, expect_error=False, | ||||||
encoding=None, shell=True, text=False, input=None, stdin=None, stdout=None, | ||||||
stderr=None, get_process=None, timeout=None): | ||||||
@@ -295,6 +312,7 @@ def write(self, filename, data, truncate=False, binary=False, read_and_write=Fal | ||||||
with tempfile.NamedTemporaryFile(mode=mode, delete=False) as tmp_file: | ||||||
# For scp the port is specified by a "-P" option | ||||||
scp_args = ['-P' if x == '-p' else x for x in self.ssh_args] | ||||||
if not truncate: | ||||||
scp_cmd = ['scp'] + scp_args + [f"{self.username}@{self.host}:{filename}", tmp_file.name] | ||||||
subprocess.run(scp_cmd, check=False) # The file might not exist yet | ||||||
@@ -394,17 +412,25 @@ def get_process_children(self, pid): | ||||||
# Database control | ||||||
def db_connect(self, dbname, user, password=None, host="localhost", port=5432): | ||||||
""" | ||||||
EstablishSSH tunnel andconnect to a PostgreSQL database. | ||||||
""" | ||||||
local_port = reserve_port() | ||||||
self.tunnel_port = local_port | ||||||
self.establish_ssh_tunnel(local_port=local_port, remote_port=port, host=host) | ||||||
try: | ||||||
conn = pglib.connect( | ||||||
host='localhost', | ||||||
port=local_port, | ||||||
database=dbname, | ||||||
user=user, | ||||||
password=password, | ||||||
timeout=10 | ||||||
) | ||||||
print("Database connection established successfully.") | ||||||
return conn | ||||||
except Exception as e: | ||||||
print(f"Error connecting to the database: {str(e)}") | ||||||
if self.tunnel_process: | ||||||
self.tunnel_process.terminate() | ||||||
print("SSH tunnel closed due to connection failure.") | ||||||
raise |