Skip to content

Commit 12aa7ba

Browse files
author
v.shepard
committed
Add info about remote mode in README.md
1 parent 0f14034 commit 12aa7ba

File tree

8 files changed

+130
-59
lines changed

8 files changed

+130
-59
lines changed

README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,33 @@ with testgres.get_new_node().init() as master:
173173
Note that `default_conf()` is called by `init()` function; both of them overwrite
174174
the configuration file, which means that they should be called before `append_conf()`.
175175

176+
### Remote mode
177+
Testgres supports the creation of PostgreSQL nodes on a remote host. This is useful when you want to run distributed tests involving multiple nodes spread across different machines.
178+
179+
To use this feature, you need to use the RemoteOperations class.
180+
Here is an example of how you might set this up:
181+
182+
```python
183+
from testgres import ConnectionParams, RemoteOperations, TestgresConfig, get_remote_node
184+
185+
# Set up connection params
186+
conn_params = ConnectionParams(
187+
host='your_host', # replace with your host
188+
username='user_name', # replace with your username
189+
ssh_key='path_to_ssh_key' # replace with your SSH key path
190+
)
191+
os_ops = RemoteOperations(conn_params)
192+
193+
# Add remote testgres config before test
194+
TestgresConfig.set_os_ops(os_ops=os_ops)
195+
196+
# Proceed with your test
197+
def test_basic_query(self):
198+
with get_remote_node(conn_params=conn_params) as node:
199+
node.init().start()
200+
res = node.execute('SELECT 1')
201+
self.assertEqual(res, [(1,)])
202+
```
176203

177204
## Authors
178205

testgres/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from .api import get_new_node
1+
from .api import get_new_node, get_remote_node
22
from .backup import NodeBackup
33

44
from .config import \
@@ -52,6 +52,7 @@
5252

5353
__all__ = [
5454
"get_new_node",
55+
"get_remote_node",
5556
"NodeBackup",
5657
"TestgresConfig", "configure_testgres", "scoped_config", "push_config", "pop_config",
5758
"NodeConnection", "DatabaseError", "InternalError", "ProgrammingError", "OperationalError",

testgres/api.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,18 @@ def get_new_node(name=None, base_dir=None, **kwargs):
3737
"""
3838
Simply a wrapper around :class:`.PostgresNode` constructor.
3939
See :meth:`.PostgresNode.__init__` for details.
40+
"""
41+
# NOTE: leave explicit 'name' and 'base_dir' for compatibility
42+
return PostgresNode(name=name, base_dir=base_dir, **kwargs)
43+
44+
45+
def get_remote_node(name=None, conn_params=None):
46+
"""
47+
Simply a wrapper around :class:`.PostgresNode` constructor for remote node.
48+
See :meth:`.PostgresNode.__init__` for details.
4049
For remote connection you can add the next parameter:
4150
conn_params = ConnectionParams(host='127.0.0.1',
4251
ssh_key=None,
4352
username=default_username())
4453
"""
45-
# NOTE: leave explicit 'name' and 'base_dir' for compatibility
46-
return PostgresNode(name=name, base_dir=base_dir, **kwargs)
54+
return get_new_node(name=name, conn_params=conn_params)

testgres/node.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,9 @@ def __init__(self, name=None, port=None, base_dir=None, conn_params: ConnectionP
146146

147147
# basic
148148
self.name = name or generate_app_name()
149-
150-
if conn_params.ssh_key:
149+
if testgres_config.os_ops:
150+
self.os_ops = testgres_config.os_ops
151+
elif conn_params.ssh_key:
151152
self.os_ops = RemoteOperations(conn_params)
152153
else:
153154
self.os_ops = LocalOperations(conn_params)
@@ -157,7 +158,6 @@ def __init__(self, name=None, port=None, base_dir=None, conn_params: ConnectionP
157158
self.host = self.os_ops.host
158159
self.ssh_key = self.os_ops.ssh_key
159160

160-
testgres_config.os_ops = self.os_ops
161161
# defaults for __exit__()
162162
self.cleanup_on_good_exit = testgres_config.node_cleanup_on_good_exit
163163
self.cleanup_on_bad_exit = testgres_config.node_cleanup_on_bad_exit

testgres/operations/remote_ops.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
sshtunnel.TUNNEL_TIMEOUT = 5.0
1818

1919

20-
error_markers = [b'error', b'Permission denied', b'fatal']
20+
error_markers = [b'error', b'Permission denied', b'fatal', b'No such file or directory']
2121

2222

2323
class PsUtilProcessProxy:
@@ -203,7 +203,10 @@ def makedirs(self, path, remove_existing=False):
203203
cmd = "rm -rf {} && mkdir -p {}".format(path, path)
204204
else:
205205
cmd = "mkdir -p {}".format(path)
206-
exit_status, result, error = self.exec_command(cmd, verbose=True)
206+
try:
207+
exit_status, result, error = self.exec_command(cmd, verbose=True)
208+
except ExecUtilException as e:
209+
raise Exception("Couldn't create dir {} because of error {}".format(path, e.message))
207210
if exit_status != 0:
208211
raise Exception("Couldn't create dir {} because of error {}".format(path, error))
209212
return result

testgres/utils.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,12 @@ def get_bin_path(filename):
8787
# check if it's already absolute
8888
if os.path.isabs(filename):
8989
return filename
90+
if tconf.os_ops.remote:
91+
pg_config = os.environ.get("PG_CONFIG_REMOTE") or os.environ.get("PG_CONFIG")
92+
else:
93+
# try PG_CONFIG - get from local machine
94+
pg_config = os.environ.get("PG_CONFIG")
9095

91-
# try PG_CONFIG - get from local machine
92-
pg_config = os.environ.get("PG_CONFIG")
9396
if pg_config:
9497
bindir = get_pg_config()["BINDIR"]
9598
return os.path.join(bindir, filename)
@@ -139,7 +142,11 @@ def cache_pg_config_data(cmd):
139142
return _pg_config_data
140143

141144
# try specified pg_config path or PG_CONFIG
142-
pg_config = pg_config_path or os.environ.get("PG_CONFIG")
145+
if tconf.os_ops.remote:
146+
pg_config = pg_config_path or os.environ.get("PG_CONFIG_REMOTE") or os.environ.get("PG_CONFIG")
147+
else:
148+
# try PG_CONFIG - get from local machine
149+
pg_config = pg_config_path or os.environ.get("PG_CONFIG")
143150
if pg_config:
144151
return cache_pg_config_data(pg_config)
145152

tests/README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,32 @@ export PYTHON_VERSION=3 # or 2
2727
# Run tests
2828
./run_tests.sh
2929
```
30+
31+
32+
#### Remote host tests
33+
34+
1. Start remote host or docker container
35+
2. Make sure that you run ssh
36+
```commandline
37+
sudo apt-get install openssh-server
38+
sudo systemctl start sshd
39+
```
40+
3. You need to connect to the remote host at least once to add it to the known hosts file
41+
4. Generate ssh keys
42+
5. Set up params for tests
43+
44+
45+
```commandline
46+
conn_params = ConnectionParams(
47+
host='remote_host',
48+
username='username',
49+
ssh_key=/path/to/your/ssh/key'
50+
)
51+
os_ops = RemoteOperations(conn_params)
52+
```
53+
If you have different path to `PG_CONFIG` on your local and remote host you can set up `PG_CONFIG_REMOTE`, this value will be
54+
using during work with remote host.
55+
56+
`test_remote` - Tests for RemoteOperations class.
57+
58+
`test_simple_remote` - Tests that create node and check it. The same as `test_simple`, but for remote node.

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy