Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 51f05de

Browse files
author
v.shepard
committed
PBCKP-152 change local function on execution by ssh
1 parent 8be1b3a commit 51f05de

File tree

11 files changed

+422
-48
lines changed

11 files changed

+422
-48
lines changed

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from distutils.core import setup
77

88
# Basic dependencies
9-
install_requires = ["pg8000", "port-for>=0.4", "six>=1.9.0", "psutil"]
9+
install_requires = ["pg8000", "port-for>=0.4", "six>=1.9.0", "psutil", "fabric"]
1010

1111
# Add compatibility enum class
1212
if sys.version_info < (3, 4):
@@ -21,7 +21,7 @@
2121
readme = f.read()
2222

2323
setup(
24-
version='1.8.6',
24+
version='1.9.0',
2525
name='testgres',
2626
packages=['testgres'],
2727
description='Testing utility for PostgreSQL and its extensions',

testgres/api.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,19 @@
3030
PostgresNode(name='...', port=..., base_dir='...')
3131
[(3,)]
3232
"""
33+
from defaults import default_username
3334
from .node import PostgresNode
3435

3536

3637
def get_new_node(name=None, base_dir=None, **kwargs):
3738
"""
3839
Simply a wrapper around :class:`.PostgresNode` constructor.
3940
See :meth:`.PostgresNode.__init__` for details.
41+
For remote connection you can add next parameters:
42+
host='127.0.0.1',
43+
hostname='localhost',
44+
ssh_key=None,
45+
username=default_username()
4046
"""
4147
# NOTE: leave explicit 'name' and 'base_dir' for compatibility
4248
return PostgresNode(name=name, base_dir=base_dir, **kwargs)

testgres/backup.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from six import raise_from
77
from tempfile import mkdtemp
88

9+
from os_ops import OsOperations
910
from .enums import XLogMethod
1011

1112
from .consts import \
@@ -47,7 +48,7 @@ def __init__(self,
4748
username: database user name.
4849
xlog_method: none | fetch | stream (see docs)
4950
"""
50-
51+
self.os_ops = node.os_ops
5152
if not node.status():
5253
raise BackupException('Node must be running')
5354

@@ -60,8 +61,8 @@ def __init__(self,
6061
raise BackupException(msg)
6162

6263
# Set default arguments
63-
username = username or default_username()
64-
base_dir = base_dir or mkdtemp(prefix=TMP_BACKUP)
64+
username = username or self.os_ops.get_user()
65+
base_dir = base_dir or self.os_ops.mkdtemp(prefix=TMP_BACKUP)
6566

6667
# public
6768
self.original_node = node
@@ -81,7 +82,7 @@ def __init__(self,
8182
"-D", data_dir,
8283
"-X", xlog_method.value
8384
] # yapf: disable
84-
execute_utility(_params, self.log_file)
85+
execute_utility(_params, self.log_file, hostname=node.hostname, ssh_key=node.ssh_key)
8586

8687
def __enter__(self):
8788
return self
@@ -107,7 +108,7 @@ def _prepare_dir(self, destroy):
107108
available = not destroy
108109

109110
if available:
110-
dest_base_dir = mkdtemp(prefix=TMP_NODE)
111+
dest_base_dir = self.os_ops.mkdtemp(prefix=TMP_NODE)
111112

112113
data1 = os.path.join(self.base_dir, DATA_DIR)
113114
data2 = os.path.join(dest_base_dir, DATA_DIR)
@@ -185,4 +186,4 @@ def cleanup(self):
185186

186187
if self._available:
187188
self._available = False
188-
rmtree(self.base_dir, ignore_errors=True)
189+
self.os_ops.rmdirs(self.base_dir, ignore_errors=True)

testgres/cache.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from shutil import copytree
77
from six import raise_from
88

9+
from os_ops import OsOperations
910
from .config import testgres_config
1011

1112
from .consts import XLOG_CONTROL_FILE
@@ -21,14 +22,16 @@
2122
execute_utility
2223

2324

24-
def cached_initdb(data_dir, logfile=None, params=None):
25+
def cached_initdb(data_dir, logfile=None, hostname='localhost', ssh_key=None, params=None):
2526
"""
2627
Perform initdb or use cached node files.
2728
"""
29+
os_ops = OsOperations(hostname=hostname, ssh_key=ssh_key)
30+
2831
def call_initdb(initdb_dir, log=None):
2932
try:
3033
_params = [get_bin_path("initdb"), "-D", initdb_dir, "-N"]
31-
execute_utility(_params + (params or []), log)
34+
execute_utility(_params + (params or []), log, hostname=hostname, ssh_key=ssh_key)
3235
except ExecUtilException as e:
3336
raise_from(InitNodeException("Failed to run initdb"), e)
3437

@@ -39,26 +42,27 @@ def call_initdb(initdb_dir, log=None):
3942
cached_data_dir = testgres_config.cached_initdb_dir
4043

4144
# Initialize cached initdb
42-
if not os.path.exists(cached_data_dir) or \
43-
not os.listdir(cached_data_dir):
45+
46+
if not os_ops.path_exists(cached_data_dir) or \
47+
not os_ops.listdir(cached_data_dir):
4448
call_initdb(cached_data_dir)
4549

4650
try:
4751
# Copy cached initdb to current data dir
48-
copytree(cached_data_dir, data_dir)
52+
os_ops.copytree(cached_data_dir, data_dir)
4953

5054
# Assign this node a unique system id if asked to
5155
if testgres_config.cached_initdb_unique:
5256
# XXX: write new unique system id to control file
5357
# Some users might rely upon unique system ids, but
5458
# our initdb caching mechanism breaks this contract.
5559
pg_control = os.path.join(data_dir, XLOG_CONTROL_FILE)
56-
with io.open(pg_control, "r+b") as f:
57-
f.write(generate_system_id()) # overwrite id
60+
system_id = generate_system_id()
61+
os_ops.write(pg_control, system_id, truncate=True, binary=True, read_and_write=True)
5862

5963
# XXX: build new WAL segment with our system id
6064
_params = [get_bin_path("pg_resetwal"), "-D", data_dir, "-f"]
61-
execute_utility(_params, logfile)
65+
execute_utility(_params, logfile, hostname=hostname, ssh_key=ssh_key)
6266

6367
except ExecUtilException as e:
6468
msg = "Failed to reset WAL for system id"

testgres/config.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ class GlobalConfig(object):
4343

4444
_cached_initdb_dir = None
4545
""" underlying class attribute for cached_initdb_dir property """
46+
47+
os_ops = None
48+
""" OsOperation object that allows work on remote host """
4649
@property
4750
def cached_initdb_dir(self):
4851
""" path to a temp directory for cached initdb. """
@@ -52,8 +55,15 @@ def cached_initdb_dir(self):
5255
def cached_initdb_dir(self, value):
5356
self._cached_initdb_dir = value
5457

58+
# NOTE: assign initial cached dir for initdb
59+
if self.os_ops:
60+
testgres_config.cached_initdb_dir = self.os_ops.mkdtemp(prefix=TMP_CACHE)
61+
else:
62+
testgres_config.cached_initdb_dir = mkdtemp(prefix=TMP_CACHE)
63+
5564
if value:
5665
cached_initdb_dirs.add(value)
66+
return testgres_config.cached_initdb_dir
5767

5868
@property
5969
def temp_dir(self):
@@ -133,9 +143,12 @@ def copy(self):
133143

134144

135145
@atexit.register
136-
def _rm_cached_initdb_dirs():
146+
def _rm_cached_initdb_dirs(os_ops=None):
137147
for d in cached_initdb_dirs:
138-
rmtree(d, ignore_errors=True)
148+
if os_ops:
149+
os_ops.rmtree(d, ignore_errors=True)
150+
else:
151+
rmtree(d, ignore_errors=True)
139152

140153

141154
def push_config(**options):
@@ -195,7 +208,3 @@ def configure_testgres(**options):
195208
"""
196209

197210
testgres_config.update(options)
198-
199-
200-
# NOTE: assign initial cached dir for initdb
201-
testgres_config.cached_initdb_dir = mkdtemp(prefix=TMP_CACHE)

testgres/connection.py

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# coding: utf-8
2+
from os_ops import OsOperations
23

34
# we support both pg8000 and psycopg2
45
try:
@@ -41,11 +42,12 @@ def __init__(self,
4142

4243
self._node = node
4344

44-
self._connection = pglib.connect(database=dbname,
45-
user=username,
46-
password=password,
47-
host=node.host,
48-
port=node.port)
45+
self.os_ops = OsOperations(node.host, node.hostname, node.ssh_key, node.username)
46+
self._connection = self.os_ops.db_connect(dbname=dbname,
47+
user=username,
48+
password=password,
49+
host=node.host,
50+
port=node.port)
4951

5052
self._connection.autocommit = autocommit
5153
self._cursor = self.connection.cursor()
@@ -102,17 +104,24 @@ def rollback(self):
102104
return self
103105

104106
def execute(self, query, *args):
105-
self.cursor.execute(query, args)
106-
107107
try:
108-
res = self.cursor.fetchall()
109-
110-
# pg8000 might return tuples
111-
if isinstance(res, tuple):
112-
res = [tuple(t) for t in res]
113-
114-
return res
115-
except Exception:
108+
with self.connection.cursor() as cursor:
109+
cursor.execute(query, args)
110+
try:
111+
res = cursor.fetchall()
112+
113+
# pg8000 might return tuples
114+
if isinstance(res, tuple):
115+
res = [tuple(t) for t in res]
116+
117+
return res
118+
except (pglib.ProgrammingError, pglib.InternalError) as e:
119+
# An error occurred while trying to fetch results (e.g., no results to fetch)
120+
print(f"Error fetching results: {e}")
121+
return None
122+
except (pglib.Error, Exception) as e:
123+
# Handle other database errors
124+
print(f"Error executing query: {e}")
116125
return None
117126

118127
def close(self):

testgres/defaults.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,15 @@ def default_dbname():
1313
return 'postgres'
1414

1515

16-
def default_username():
16+
def default_username(os_ops=None):
1717
"""
1818
Return default username (current user).
1919
"""
20-
21-
return getpass.getuser()
20+
if os_ops:
21+
user = os_ops.get_user()
22+
else:
23+
user = getpass.getuser()
24+
return user
2225

2326

2427
def generate_app_name():
@@ -29,7 +32,7 @@ def generate_app_name():
2932
return 'testgres-{}'.format(str(uuid.uuid4()))
3033

3134

32-
def generate_system_id():
35+
def generate_system_id(os_ops=None):
3336
"""
3437
Generate a new 64-bit unique system identifier for node.
3538
"""
@@ -44,7 +47,10 @@ def generate_system_id():
4447
system_id = 0
4548
system_id |= (secs << 32)
4649
system_id |= (usecs << 12)
47-
system_id |= (os.getpid() & 0xFFF)
50+
if os_ops:
51+
system_id |= (os_ops.get_pid() & 0xFFF)
52+
else:
53+
system_id |= (os.getpid() & 0xFFF)
4854

4955
# pack ULL in native byte order
5056
return struct.pack('=Q', system_id)

testgres/logger.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,20 @@
66
import time
77

88

9+
# create logger
10+
log = logging.getLogger('Testgres')
11+
log.setLevel(logging.DEBUG)
12+
# create console handler and set level to debug
13+
ch = logging.StreamHandler()
14+
ch.setLevel(logging.DEBUG)
15+
# create formatter
16+
formatter = logging.Formatter('\n%(asctime)s - %(name)s[%(levelname)s]: %(message)s')
17+
# add formatter to ch
18+
ch.setFormatter(formatter)
19+
# add ch to logger
20+
log.addHandler(ch)
21+
22+
923
class TestgresLogger(threading.Thread):
1024
"""
1125
Helper class to implement reading from log files.

testgres/node.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import subprocess
1313
import time
1414

15+
from os_ops import OsOperations
1516

1617
try:
1718
from collections.abc import Iterable
@@ -129,7 +130,8 @@ def __repr__(self):
129130

130131

131132
class PostgresNode(object):
132-
def __init__(self, name=None, port=None, base_dir=None):
133+
def __init__(self, name=None, port=None, base_dir=None,
134+
host='127.0.0.1', hostname='localhost', ssh_key=None, username=default_username()):
133135
"""
134136
PostgresNode constructor.
135137
@@ -147,10 +149,14 @@ def __init__(self, name=None, port=None, base_dir=None):
147149
self._master = None
148150

149151
# basic
150-
self.host = '127.0.0.1'
151152
self.name = name or generate_app_name()
152153
self.port = port or reserve_port()
153154

155+
self.host = host
156+
self.hostname = hostname
157+
self.ssh_key = ssh_key
158+
self.os_ops = OsOperations(host, hostname, ssh_key, username=username)
159+
154160
# defaults for __exit__()
155161
self.cleanup_on_good_exit = testgres_config.node_cleanup_on_good_exit
156162
self.cleanup_on_bad_exit = testgres_config.node_cleanup_on_bad_exit
@@ -455,9 +461,12 @@ def init(self, initdb_params=None, **kwargs):
455461
"""
456462

457463
# initialize this PostgreSQL node
458-
cached_initdb(data_dir=self.data_dir,
459-
logfile=self.utils_log_file,
460-
params=initdb_params)
464+
cached_initdb(
465+
data_dir=self.data_dir,
466+
logfile=self.utils_log_file,
467+
hostname=self.hostname,
468+
ssh_key=self.ssh_key,
469+
params=initdb_params)
461470

462471
# initialize default config files
463472
self.default_conf(**kwargs)
@@ -514,6 +523,10 @@ def get_auth_method(t):
514523
new_lines = [
515524
u"local\treplication\tall\t\t\t{}\n".format(auth_local),
516525
u"host\treplication\tall\t127.0.0.1/32\t{}\n".format(auth_host),
526+
527+
u"host\treplication\tall\t0.0.0.0/0\t{}\n".format(auth_host),
528+
u"host\tall\tall\t0.0.0.0/0\t{}\n".format(auth_host),
529+
517530
u"host\treplication\tall\t::1/128\t\t{}\n".format(auth_host)
518531
] # yapf: disable
519532

0 commit comments

Comments
 (0)