3131HBA_CONF_FILE , \
3232RECOVERY_CONF_FILE , \
3333PG_LOG_FILE , \
34- UTILS_LOG_FILE
34+ UTILS_LOG_FILE , \
35+ PG_PID_FILE
3536
3637from .decorators import \
3738method_decorator , \
6667class PostgresNode (object ):
6768def __init__ (self ,name = None ,port = None ,base_dir = None ):
6869"""
69- Create a new node manually .
70+ Create a new node.
7071
7172 Args:
7273 name: node's application name.
7374 port: port to accept connections.
7475 base_dir: path to node's data directory.
7576 """
7677
78+ # private
79+ self ._should_free_port = port is None
80+ self ._base_dir = base_dir
81+ self ._logger = None
82+ self ._master = None
83+
7784# basic
7885self .host = '127.0.0.1'
7986self .name = name or generate_app_name ()
8087self .port = port or reserve_port ()
81- self .base_dir = base_dir
8288
8389# defaults for __exit__()
8490self .cleanup_on_good_exit = testgres_config .node_cleanup_on_good_exit
8591self .cleanup_on_bad_exit = testgres_config .node_cleanup_on_bad_exit
8692self .shutdown_max_attempts = 3
8793
88- # private
89- self ._should_free_port = port is None
90- self ._logger = None
91- self ._master = None
92-
93- # create directories if needed
94- self ._prepare_dirs ()
94+ # NOTE: for compatibility
95+ self .utils_log_name = self .utils_log_file
96+ self .pg_log_name = self .pg_log_file
9597
9698def __enter__ (self ):
9799return self
@@ -121,19 +123,37 @@ def master(self):
121123return self ._master
122124
123125@property
124- def data_dir (self ):
125- return os .path .join (self .base_dir ,DATA_DIR )
126+ def base_dir (self ):
127+ if not self ._base_dir :
128+ self ._base_dir = mkdtemp (prefix = TMP_NODE )
129+
130+ # NOTE: it's safe to create a new dir
131+ if not os .path .exists (self ._base_dir ):
132+ os .makedirs (self ._base_dir )
133+
134+ return self ._base_dir
126135
127136@property
128137def logs_dir (self ):
129- return os .path .join (self .base_dir ,LOGS_DIR )
138+ path = os .path .join (self .base_dir ,LOGS_DIR )
139+
140+ # NOTE: it's safe to create a new dir
141+ if not os .path .exists (path ):
142+ os .makedirs (path )
143+
144+ return path
145+
146+ @property
147+ def data_dir (self ):
148+ # NOTE: we can't run initdb without user's args
149+ return os .path .join (self .base_dir ,DATA_DIR )
130150
131151@property
132- def utils_log_name (self ):
152+ def utils_log_file (self ):
133153return os .path .join (self .logs_dir ,UTILS_LOG_FILE )
134154
135155@property
136- def pg_log_name (self ):
156+ def pg_log_file (self ):
137157return os .path .join (self .logs_dir ,PG_LOG_FILE )
138158
139159def _try_shutdown (self ,max_attempts ):
@@ -189,21 +209,11 @@ def _create_recovery_conf(self, username):
189209
190210self .append_conf (RECOVERY_CONF_FILE ,line )
191211
192- def _prepare_dirs (self ):
193- if not self .base_dir :
194- self .base_dir = mkdtemp (prefix = TMP_NODE )
195-
196- if not os .path .exists (self .base_dir ):
197- os .makedirs (self .base_dir )
198-
199- if not os .path .exists (self .logs_dir ):
200- os .makedirs (self .logs_dir )
201-
202212def _maybe_start_logger (self ):
203213if testgres_config .use_python_logging :
204214# spawn new logger if it doesn't exist or is stopped
205215if not self ._logger or not self ._logger .is_alive ():
206- self ._logger = TestgresLogger (self .name ,self .pg_log_name )
216+ self ._logger = TestgresLogger (self .name ,self .pg_log_file )
207217self ._logger .start ()
208218
209219def _maybe_stop_logger (self ):
@@ -219,7 +229,7 @@ def _collect_special_files(self):
219229 (os .path .join (self .data_dir ,PG_AUTO_CONF_FILE ),0 ),
220230 (os .path .join (self .data_dir ,RECOVERY_CONF_FILE ),0 ),
221231 (os .path .join (self .data_dir ,HBA_CONF_FILE ),0 ),
222- (self .pg_log_name ,testgres_config .error_log_lines )
232+ (self .pg_log_file ,testgres_config .error_log_lines )
223233 ]
224234
225235for f ,num_lines in files :
@@ -254,12 +264,9 @@ def init(self, initdb_params=None, **kwargs):
254264 This instance of PostgresNode.
255265 """
256266
257- # create directories if needed
258- self ._prepare_dirs ()
259-
260267# initialize this PostgreSQL node
261268cached_initdb (data_dir = self .data_dir ,
262- logfile = self .utils_log_name ,
269+ logfile = self .utils_log_file ,
263270params = initdb_params )
264271
265272# initialize default config files
@@ -398,7 +405,7 @@ def status(self):
398405"-D" ,self .data_dir ,
399406"status"
400407 ]
401- execute_utility (_params ,self .utils_log_name )
408+ execute_utility (_params ,self .utils_log_file )
402409return NodeStatus .Running
403410
404411except ExecUtilException as e :
@@ -416,7 +423,7 @@ def get_pid(self):
416423 """
417424
418425if self .status ():
419- pid_file = os .path .join (self .data_dir ,'postmaster.pid' )
426+ pid_file = os .path .join (self .data_dir ,PG_PID_FILE )
420427with io .open (pid_file )as f :
421428return int (f .readline ())
422429
@@ -433,7 +440,7 @@ def get_control_data(self):
433440_params += ["-D" ]if pg_version_ge ('9.5' )else []
434441_params += [self .data_dir ]
435442
436- data = execute_utility (_params ,self .utils_log_name )
443+ data = execute_utility (_params ,self .utils_log_file )
437444
438445out_dict = {}
439446
@@ -458,13 +465,13 @@ def start(self, params=[]):
458465_params = [
459466get_bin_path ("pg_ctl" ),
460467"-D" ,self .data_dir ,
461- "-l" ,self .pg_log_name ,
468+ "-l" ,self .pg_log_file ,
462469"-w" ,# wait
463470"start"
464471 ]+ params
465472
466473try :
467- execute_utility (_params ,self .utils_log_name )
474+ execute_utility (_params ,self .utils_log_file )
468475except ExecUtilException as e :
469476msg = 'Cannot start node'
470477files = self ._collect_special_files ()
@@ -493,7 +500,7 @@ def stop(self, params=[]):
493500"stop"
494501 ]+ params
495502
496- execute_utility (_params ,self .utils_log_name )
503+ execute_utility (_params ,self .utils_log_file )
497504
498505self ._maybe_stop_logger ()
499506
@@ -514,13 +521,13 @@ def restart(self, params=[]):
514521_params = [
515522get_bin_path ("pg_ctl" ),
516523"-D" ,self .data_dir ,
517- "-l" ,self .pg_log_name ,
524+ "-l" ,self .pg_log_file ,
518525"-w" ,# wait
519526"restart"
520527 ]+ params
521528
522529try :
523- execute_utility (_params ,self .utils_log_name )
530+ execute_utility (_params ,self .utils_log_file )
524531except ExecUtilException as e :
525532msg = 'Cannot restart node'
526533files = self ._collect_special_files ()
@@ -549,7 +556,7 @@ def reload(self, params=[]):
549556"reload"
550557 ]+ params
551558
552- execute_utility (_params ,self .utils_log_name )
559+ execute_utility (_params ,self .utils_log_file )
553560
554561def pg_ctl (self ,params ):
555562"""
@@ -569,7 +576,7 @@ def pg_ctl(self, params):
569576"-w" # wait
570577 ]+ params
571578
572- return execute_utility (_params ,self .utils_log_name )
579+ return execute_utility (_params ,self .utils_log_file )
573580
574581def free_port (self ):
575582"""
@@ -578,6 +585,7 @@ def free_port(self):
578585 """
579586
580587if self ._should_free_port :
588+ self ._should_free_port = False
581589release_port (self .port )
582590
583591def cleanup (self ,max_attempts = 3 ):
@@ -717,7 +725,7 @@ def tmpfile():
717725"-d" ,dbname
718726 ]
719727
720- execute_utility (_params ,self .utils_log_name )
728+ execute_utility (_params ,self .utils_log_file )
721729
722730return filename
723731
@@ -953,7 +961,7 @@ def pgbench_run(self,
953961** kwargs ):
954962"""
955963 Run pgbench with some options.
956- This event is logged (see self.utils_log_name ).
964+ This event is logged (see self.utils_log_file ).
957965
958966 Args:
959967 dbname: database name to connect to.
@@ -996,7 +1004,7 @@ def pgbench_run(self,
9961004# should be the last one
9971005_params .append (dbname )
9981006
999- return execute_utility (_params ,self .utils_log_name )
1007+ return execute_utility (_params ,self .utils_log_file )
10001008
10011009def connect (self ,dbname = None ,username = None ,password = None ):
10021010"""