Skip to content

Commit 15e3fd1

Browse files
author
vshepard
committed
Add function pg_update
1 parent 79a8dc5 commit 15e3fd1

File tree

6 files changed

+90
-25
lines changed

6 files changed

+90
-25
lines changed

docker-compose.yml

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
1-
tests:
1+
version: '3.8'
2+
services:
3+
tests:
24
build: .

testgres/cache.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,20 @@
2222
from .operations.os_ops import OsOperations
2323

2424

25-
def cached_initdb(data_dir, logfile=None, params=None, os_ops: OsOperations = LocalOperations()):
25+
def cached_initdb(data_dir, logfile=None, params=None, os_ops: OsOperations = LocalOperations(), bin_path=None, cached=True):
2626
"""
2727
Perform initdb or use cached node files.
2828
"""
2929

3030
def call_initdb(initdb_dir, log=logfile):
3131
try:
32-
_params = [get_bin_path("initdb"), "-D", initdb_dir, "-N"]
32+
initdb_path = os.path.join(bin_path, 'initdb') if bin_path else get_bin_path("initdb")
33+
_params = [initdb_path, "-D", initdb_dir, "-N"]
3334
execute_utility(_params + (params or []), log)
3435
except ExecUtilException as e:
3536
raise_from(InitNodeException("Failed to run initdb"), e)
3637

37-
if params or not testgres_config.cache_initdb:
38+
if params or not testgres_config.cache_initdb or not cached:
3839
call_initdb(data_dir, logfile)
3940
else:
4041
# Fetch cached initdb dir

testgres/node.py

+66-18
Original file line numberDiff line numberDiff line change
@@ -127,20 +127,23 @@ def __repr__(self):
127127

128128

129129
class PostgresNode(object):
130-
def __init__(self, name=None, port=None, base_dir=None, conn_params: ConnectionParams = ConnectionParams()):
130+
def __init__(self, name=None, port=None, base_dir=None, conn_params: ConnectionParams = ConnectionParams(), bin_dir=None, prefix=None):
131131
"""
132132
PostgresNode constructor.
133133
134134
Args:
135135
name: node's application name.
136136
port: port to accept connections.
137137
base_dir: path to node's data directory.
138+
bin_dir: path to node's binary directory.
138139
"""
139140

140141
# private
141-
self._pg_version = PgVer(get_pg_version())
142+
self._pg_version = PgVer(get_pg_version(bin_dir))
142143
self._should_free_port = port is None
143144
self._base_dir = base_dir
145+
self._bin_dir = bin_dir
146+
self._prefix = prefix
144147
self._logger = None
145148
self._master = None
146149

@@ -281,14 +284,20 @@ def master(self):
281284
@property
282285
def base_dir(self):
283286
if not self._base_dir:
284-
self._base_dir = self.os_ops.mkdtemp(prefix=TMP_NODE)
287+
self._base_dir = self.os_ops.mkdtemp(prefix=self._prefix or TMP_NODE)
285288

286289
# NOTE: it's safe to create a new dir
287290
if not self.os_ops.path_exists(self._base_dir):
288291
self.os_ops.makedirs(self._base_dir)
289292

290293
return self._base_dir
291294

295+
@property
296+
def bin_dir(self):
297+
if not self._bin_dir:
298+
self._bin_dir = os.path.dirname(get_bin_path("pg_config"))
299+
return self._bin_dir
300+
292301
@property
293302
def logs_dir(self):
294303
path = os.path.join(self.base_dir, LOGS_DIR)
@@ -441,7 +450,7 @@ def _collect_special_files(self):
441450

442451
return result
443452

444-
def init(self, initdb_params=None, **kwargs):
453+
def init(self, initdb_params=None, cached=True, **kwargs):
445454
"""
446455
Perform initdb for this node.
447456
@@ -460,7 +469,9 @@ def init(self, initdb_params=None, **kwargs):
460469
data_dir=self.data_dir,
461470
logfile=self.utils_log_file,
462471
os_ops=self.os_ops,
463-
params=initdb_params)
472+
params=initdb_params,
473+
bin_path=self.bin_dir,
474+
cached=False)
464475

465476
# initialize default config files
466477
self.default_conf(**kwargs)
@@ -619,7 +630,7 @@ def status(self):
619630

620631
try:
621632
_params = [
622-
get_bin_path("pg_ctl"),
633+
self._get_bin_path('pg_ctl'),
623634
"-D", self.data_dir,
624635
"status"
625636
] # yapf: disable
@@ -645,7 +656,7 @@ def get_control_data(self):
645656
"""
646657

647658
# this one is tricky (blame PG 9.4)
648-
_params = [get_bin_path("pg_controldata")]
659+
_params = [self._get_bin_path("pg_controldata")]
649660
_params += ["-D"] if self._pg_version >= PgVer('9.5') else []
650661
_params += [self.data_dir]
651662

@@ -708,7 +719,7 @@ def start(self, params=[], wait=True):
708719
return self
709720

710721
_params = [
711-
get_bin_path("pg_ctl"),
722+
self._get_bin_path("pg_ctl"),
712723
"-D", self.data_dir,
713724
"-l", self.pg_log_file,
714725
"-w" if wait else '-W', # --wait or --no-wait
@@ -742,7 +753,7 @@ def stop(self, params=[], wait=True):
742753
return self
743754

744755
_params = [
745-
get_bin_path("pg_ctl"),
756+
self._get_bin_path("pg_ctl"),
746757
"-D", self.data_dir,
747758
"-w" if wait else '-W', # --wait or --no-wait
748759
"stop"
@@ -782,7 +793,7 @@ def restart(self, params=[]):
782793
"""
783794

784795
_params = [
785-
get_bin_path("pg_ctl"),
796+
self._get_bin_path("pg_ctl"),
786797
"-D", self.data_dir,
787798
"-l", self.pg_log_file,
788799
"-w", # wait
@@ -814,7 +825,7 @@ def reload(self, params=[]):
814825
"""
815826

816827
_params = [
817-
get_bin_path("pg_ctl"),
828+
self._get_bin_path("pg_ctl"),
818829
"-D", self.data_dir,
819830
"reload"
820831
] + params # yapf: disable
@@ -835,7 +846,7 @@ def promote(self, dbname=None, username=None):
835846
"""
836847

837848
_params = [
838-
get_bin_path("pg_ctl"),
849+
self._get_bin_path("pg_ctl"),
839850
"-D", self.data_dir,
840851
"-w", # wait
841852
"promote"
@@ -871,7 +882,7 @@ def pg_ctl(self, params):
871882
"""
872883

873884
_params = [
874-
get_bin_path("pg_ctl"),
885+
self._get_bin_path("pg_ctl"),
875886
"-D", self.data_dir,
876887
"-w" # wait
877888
] + params # yapf: disable
@@ -945,7 +956,7 @@ def psql(self,
945956
username = username or default_username()
946957

947958
psql_params = [
948-
get_bin_path("psql"),
959+
self._get_bin_path("psql"),
949960
"-p", str(self.port),
950961
"-h", self.host,
951962
"-U", username,
@@ -1066,7 +1077,7 @@ def tmpfile():
10661077
filename = filename or tmpfile()
10671078

10681079
_params = [
1069-
get_bin_path("pg_dump"),
1080+
self._get_bin_path("pg_dump"),
10701081
"-p", str(self.port),
10711082
"-h", self.host,
10721083
"-f", filename,
@@ -1094,7 +1105,7 @@ def restore(self, filename, dbname=None, username=None):
10941105
username = username or default_username()
10951106

10961107
_params = [
1097-
get_bin_path("pg_restore"),
1108+
self._get_bin_path("pg_restore"),
10981109
"-p", str(self.port),
10991110
"-h", self.host,
11001111
"-U", username,
@@ -1364,7 +1375,7 @@ def pgbench(self,
13641375
username = username or default_username()
13651376

13661377
_params = [
1367-
get_bin_path("pgbench"),
1378+
self._get_bin_path("pgbench"),
13681379
"-p", str(self.port),
13691380
"-h", self.host,
13701381
"-U", username,
@@ -1416,7 +1427,7 @@ def pgbench_run(self, dbname=None, username=None, options=[], **kwargs):
14161427
username = username or default_username()
14171428

14181429
_params = [
1419-
get_bin_path("pgbench"),
1430+
self._get_bin_path("pgbench"),
14201431
"-p", str(self.port),
14211432
"-h", self.host,
14221433
"-U", username,
@@ -1587,6 +1598,43 @@ def set_auto_conf(self, options, config='postgresql.auto.conf', rm_options={}):
15871598

15881599
self.os_ops.write(path, auto_conf, truncate=True)
15891600

1601+
def upgrade_from(self, old_node):
1602+
"""
1603+
Upgrade this node from an old node using pg_upgrade.
1604+
1605+
Args:
1606+
old_node: An instance of PostgresNode representing the old node.
1607+
"""
1608+
if not os.path.exists(old_node.data_dir):
1609+
raise Exception("Old node must be initialized")
1610+
1611+
if not os.path.exists(self.data_dir):
1612+
self.init()
1613+
1614+
pg_upgrade_binary = self._get_bin_path("pg_upgrade")
1615+
1616+
if not os.path.exists(pg_upgrade_binary):
1617+
raise Exception("pg_upgrade does not exist in the new node's binary path")
1618+
1619+
upgrade_command = [
1620+
pg_upgrade_binary,
1621+
"--old-bindir", old_node.bin_dir,
1622+
"--new-bindir", self.bin_dir,
1623+
"--old-datadir", old_node.data_dir,
1624+
"--new-datadir", self.data_dir,
1625+
"--old-port", str(old_node.port),
1626+
"--new-port", str(self.port),
1627+
]
1628+
1629+
return self.os_ops.exec_command(upgrade_command)
1630+
1631+
def _get_bin_path(self, filename):
1632+
if self.bin_dir:
1633+
bin_path = os.path.join(self.bin_dir, filename)
1634+
else:
1635+
bin_path = get_bin_path(filename)
1636+
return bin_path
1637+
15901638

15911639
class NodeApp:
15921640

testgres/operations/local_ops.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def __init__(self, conn_params=None):
4444
def _raise_exec_exception(message, command, exit_code, output):
4545
"""Raise an ExecUtilException."""
4646
raise ExecUtilException(message=message.format(output),
47-
command=command,
47+
command=' '.join(command) if isinstance(command, list) else command,
4848
exit_code=exit_code,
4949
out=output)
5050

testgres/utils.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -172,13 +172,14 @@ def cache_pg_config_data(cmd):
172172
return cache_pg_config_data("pg_config")
173173

174174

175-
def get_pg_version():
175+
def get_pg_version(bin_dir=None):
176176
"""
177177
Return PostgreSQL version provided by postmaster.
178178
"""
179179

180180
# get raw version (e.g. postgres (PostgreSQL) 9.5.7)
181-
_params = [get_bin_path('postgres'), '--version']
181+
postgres_path = os.path.join(bin_dir, 'postgres') if bin_dir else get_bin_path('postgres')
182+
_params = [postgres_path, '--version']
182183
raw_ver = tconf.os_ops.exec_command(_params, encoding='utf-8')
183184

184185
# Remove "(Homebrew)" if present

tests/test_simple.py

+13
Original file line numberDiff line numberDiff line change
@@ -1010,6 +1010,19 @@ def test_child_process_dies(self):
10101010
# try to handle children list -- missing processes will have ptype "ProcessType.Unknown"
10111011
[ProcessProxy(p) for p in children]
10121012

1013+
def test_upgrade_node(self):
1014+
old_bin_dir = os.path.dirname(get_bin_path("pg_config"))
1015+
new_bin_dir = os.path.dirname(get_bin_path("pg_config"))
1016+
node_old = get_new_node(prefix='node_old', bin_dir=old_bin_dir)
1017+
node_old.init()
1018+
node_old.start()
1019+
node_old.stop()
1020+
node_new = get_new_node(prefix='node_new', bin_dir=new_bin_dir)
1021+
node_new.init(cached=False)
1022+
res = node_new.upgrade_from(old_node=node_old)
1023+
node_new.start()
1024+
self.assertTrue(b'Upgrade Complete' in res)
1025+
10131026

10141027
if __name__ == '__main__':
10151028
if os.environ.get('ALT_CONFIG'):

0 commit comments

Comments
 (0)