@@ -127,20 +127,23 @@ def __repr__(self):
127127
128128
129129class 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
15911639class NodeApp :
15921640
0 commit comments